File Index
Files and directories
Sign in
FILE

vkms_configfs.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/vkms/vkms_configfs.c C
  1// SPDX-License-Identifier: GPL-2.0+
  2#include <linux/cleanup.h>
  3#include <linux/configfs.h>
  4#include <linux/mutex.h>
  5#include <linux/slab.h>
  6
  7#include "vkms_drv.h"
  8#include "vkms_config.h"
  9#include "vkms_configfs.h"
 10#include "vkms_connector.h"
 11
 12/* To avoid registering configfs more than once or unregistering on error */
 13static bool is_configfs_registered;
 14
 15/**
 16 * struct vkms_configfs_device - Configfs representation of a VKMS device
 17 *
 18 * @group: Top level configuration group that represents a VKMS device.
 19 * Initialized when a new directory is created under "/config/vkms/"
 20 * @planes_group: Default subgroup of @group at "/config/vkms/planes"
 21 * @crtcs_group: Default subgroup of @group at "/config/vkms/crtcs"
 22 * @encoders_group: Default subgroup of @group at "/config/vkms/encoders"
 23 * @connectors_group: Default subgroup of @group at "/config/vkms/connectors"
 24 * @lock: Lock used to project concurrent access to the configuration attributes
 25 * @config: Protected by @lock. Configuration of the VKMS device
 26 * @enabled: Protected by @lock. The device is created or destroyed when this
 27 * option changes
 28 */
 29struct vkms_configfs_device {
 30	struct config_group group;
 31	struct config_group planes_group;
 32	struct config_group crtcs_group;
 33	struct config_group encoders_group;
 34	struct config_group connectors_group;
 35
 36	struct mutex lock;
 37	struct vkms_config *config;
 38	bool enabled;
 39};
 40
 41/**
 42 * struct vkms_configfs_plane - Configfs representation of a plane
 43 *
 44 * @group: Top level configuration group that represents a plane.
 45 * Initialized when a new directory is created under "/config/vkms/planes"
 46 * @possible_crtcs_group: Default subgroup of @group at "plane/possible_crtcs"
 47 * @dev: The vkms_configfs_device this plane belongs to
 48 * @config: Configuration of the VKMS plane
 49 */
 50struct vkms_configfs_plane {
 51	struct config_group group;
 52	struct config_group possible_crtcs_group;
 53	struct vkms_configfs_device *dev;
 54	struct vkms_config_plane *config;
 55};
 56
 57/**
 58 * struct vkms_configfs_crtc - Configfs representation of a CRTC
 59 *
 60 * @group: Top level configuration group that represents a CRTC.
 61 * Initialized when a new directory is created under "/config/vkms/crtcs"
 62 * @dev: The vkms_configfs_device this CRTC belongs to
 63 * @config: Configuration of the VKMS CRTC
 64 */
 65struct vkms_configfs_crtc {
 66	struct config_group group;
 67	struct vkms_configfs_device *dev;
 68	struct vkms_config_crtc *config;
 69};
 70
 71/**
 72 * struct vkms_configfs_encoder - Configfs representation of a encoder
 73 *
 74 * @group: Top level configuration group that represents a encoder.
 75 * Initialized when a new directory is created under "/config/vkms/encoders"
 76 * @possible_crtcs_group: Default subgroup of @group at "encoder/possible_crtcs"
 77 * @dev: The vkms_configfs_device this encoder belongs to
 78 * @config: Configuration of the VKMS encoder
 79 */
 80struct vkms_configfs_encoder {
 81	struct config_group group;
 82	struct config_group possible_crtcs_group;
 83	struct vkms_configfs_device *dev;
 84	struct vkms_config_encoder *config;
 85};
 86
 87/**
 88 * struct vkms_configfs_connector - Configfs representation of a connector
 89 *
 90 * @group: Top level configuration group that represents a connector.
 91 * Initialized when a new directory is created under "/config/vkms/connectors"
 92 * @possible_encoders_group: Default subgroup of @group at
 93 * "connector/possible_encoders"
 94 * @dev: The vkms_configfs_device this connector belongs to
 95 * @config: Configuration of the VKMS connector
 96 */
 97struct vkms_configfs_connector {
 98	struct config_group group;
 99	struct config_group possible_encoders_group;
100	struct vkms_configfs_device *dev;
101	struct vkms_config_connector *config;
102};
103
104#define device_item_to_vkms_configfs_device(item) \
105	container_of(to_config_group((item)), struct vkms_configfs_device, \
106		     group)
107
108#define child_group_to_vkms_configfs_device(group) \
109	device_item_to_vkms_configfs_device((&(group)->cg_item)->ci_parent)
110
111#define plane_item_to_vkms_configfs_plane(item) \
112	container_of(to_config_group((item)), struct vkms_configfs_plane, group)
113
114#define plane_possible_crtcs_item_to_vkms_configfs_plane(item) \
115	container_of(to_config_group((item)), struct vkms_configfs_plane, \
116		     possible_crtcs_group)
117
118#define crtc_item_to_vkms_configfs_crtc(item) \
119	container_of(to_config_group((item)), struct vkms_configfs_crtc, group)
120
121#define encoder_item_to_vkms_configfs_encoder(item) \
122	container_of(to_config_group((item)), struct vkms_configfs_encoder, \
123		     group)
124
125#define encoder_possible_crtcs_item_to_vkms_configfs_encoder(item) \
126	container_of(to_config_group((item)), struct vkms_configfs_encoder, \
127		     possible_crtcs_group)
128
129#define connector_item_to_vkms_configfs_connector(item) \
130	container_of(to_config_group((item)), struct vkms_configfs_connector, \
131		     group)
132
133#define connector_possible_encoders_item_to_vkms_configfs_connector(item) \
134	container_of(to_config_group((item)), struct vkms_configfs_connector, \
135		     possible_encoders_group)
136
137static ssize_t crtc_writeback_show(struct config_item *item, char *page)
138{
139	struct vkms_configfs_crtc *crtc;
140	bool writeback;
141
142	crtc = crtc_item_to_vkms_configfs_crtc(item);
143
144	scoped_guard(mutex, &crtc->dev->lock)
145		writeback = vkms_config_crtc_get_writeback(crtc->config);
146
147	return sprintf(page, "%d\n", writeback);
148}
149
150static ssize_t crtc_writeback_store(struct config_item *item, const char *page,
151				    size_t count)
152{
153	struct vkms_configfs_crtc *crtc;
154	bool writeback;
155
156	crtc = crtc_item_to_vkms_configfs_crtc(item);
157
158	if (kstrtobool(page, &writeback))
159		return -EINVAL;
160
161	scoped_guard(mutex, &crtc->dev->lock) {
162		if (crtc->dev->enabled)
163			return -EBUSY;
164
165		vkms_config_crtc_set_writeback(crtc->config, writeback);
166	}
167
168	return (ssize_t)count;
169}
170
171CONFIGFS_ATTR(crtc_, writeback);
172
173static struct configfs_attribute *crtc_item_attrs[] = {
174	&crtc_attr_writeback,
175	NULL,
176};
177
178static void crtc_release(struct config_item *item)
179{
180	struct vkms_configfs_crtc *crtc;
181	struct mutex *lock;
182
183	crtc = crtc_item_to_vkms_configfs_crtc(item);
184	lock = &crtc->dev->lock;
185
186	scoped_guard(mutex, lock) {
187		vkms_config_destroy_crtc(crtc->dev->config, crtc->config);
188		kfree(crtc);
189	}
190}
191
192static struct configfs_item_operations crtc_item_operations = {
193	.release	= &crtc_release,
194};
195
196static const struct config_item_type crtc_item_type = {
197	.ct_attrs	= crtc_item_attrs,
198	.ct_item_ops	= &crtc_item_operations,
199	.ct_owner	= THIS_MODULE,
200};
201
202static struct config_group *make_crtc_group(struct config_group *group,
203					    const char *name)
204{
205	struct vkms_configfs_device *dev;
206	struct vkms_configfs_crtc *crtc;
207	int ret;
208
209	dev = child_group_to_vkms_configfs_device(group);
210
211	scoped_guard(mutex, &dev->lock) {
212		if (dev->enabled)
213			return ERR_PTR(-EBUSY);
214
215		crtc = kzalloc(sizeof(*crtc), GFP_KERNEL);
216		if (!crtc)
217			return ERR_PTR(-ENOMEM);
218
219		crtc->dev = dev;
220
221		crtc->config = vkms_config_create_crtc(dev->config);
222		if (IS_ERR(crtc->config)) {
223			ret = PTR_ERR(crtc->config);
224			kfree(crtc);
225			return ERR_PTR(ret);
226		}
227
228		config_group_init_type_name(&crtc->group, name, &crtc_item_type);
229	}
230
231	return &crtc->group;
232}
233
234static struct configfs_group_operations crtcs_group_operations = {
235	.make_group	= &make_crtc_group,
236};
237
238static const struct config_item_type crtc_group_type = {
239	.ct_group_ops	= &crtcs_group_operations,
240	.ct_owner	= THIS_MODULE,
241};
242
243static int plane_possible_crtcs_allow_link(struct config_item *src,
244					   struct config_item *target)
245{
246	struct vkms_configfs_plane *plane;
247	struct vkms_configfs_crtc *crtc;
248	int ret;
249
250	if (target->ci_type != &crtc_item_type)
251		return -EINVAL;
252
253	plane = plane_possible_crtcs_item_to_vkms_configfs_plane(src);
254	crtc = crtc_item_to_vkms_configfs_crtc(target);
255
256	scoped_guard(mutex, &plane->dev->lock) {
257		if (plane->dev->enabled)
258			return -EBUSY;
259
260		ret = vkms_config_plane_attach_crtc(plane->config, crtc->config);
261	}
262
263	return ret;
264}
265
266static void plane_possible_crtcs_drop_link(struct config_item *src,
267					   struct config_item *target)
268{
269	struct vkms_configfs_plane *plane;
270	struct vkms_configfs_crtc *crtc;
271
272	plane = plane_possible_crtcs_item_to_vkms_configfs_plane(src);
273	crtc = crtc_item_to_vkms_configfs_crtc(target);
274
275	scoped_guard(mutex, &plane->dev->lock)
276		vkms_config_plane_detach_crtc(plane->config, crtc->config);
277}
278
279static struct configfs_item_operations plane_possible_crtcs_item_operations = {
280	.allow_link	= plane_possible_crtcs_allow_link,
281	.drop_link	= plane_possible_crtcs_drop_link,
282};
283
284static const struct config_item_type plane_possible_crtcs_group_type = {
285	.ct_item_ops	= &plane_possible_crtcs_item_operations,
286	.ct_owner	= THIS_MODULE,
287};
288
289static ssize_t plane_type_show(struct config_item *item, char *page)
290{
291	struct vkms_configfs_plane *plane;
292	enum drm_plane_type type;
293
294	plane = plane_item_to_vkms_configfs_plane(item);
295
296	scoped_guard(mutex, &plane->dev->lock)
297		type = vkms_config_plane_get_type(plane->config);
298
299	return sprintf(page, "%u", type);
300}
301
302static ssize_t plane_type_store(struct config_item *item, const char *page,
303				size_t count)
304{
305	struct vkms_configfs_plane *plane;
306	enum drm_plane_type type;
307
308	plane = plane_item_to_vkms_configfs_plane(item);
309
310	if (kstrtouint(page, 10, &type))
311		return -EINVAL;
312
313	if (type != DRM_PLANE_TYPE_OVERLAY && type != DRM_PLANE_TYPE_PRIMARY &&
314	    type != DRM_PLANE_TYPE_CURSOR)
315		return -EINVAL;
316
317	scoped_guard(mutex, &plane->dev->lock) {
318		if (plane->dev->enabled)
319			return -EBUSY;
320
321		vkms_config_plane_set_type(plane->config, type);
322	}
323
324	return (ssize_t)count;
325}
326
327CONFIGFS_ATTR(plane_, type);
328
329static struct configfs_attribute *plane_item_attrs[] = {
330	&plane_attr_type,
331	NULL,
332};
333
334static void plane_release(struct config_item *item)
335{
336	struct vkms_configfs_plane *plane;
337	struct mutex *lock;
338
339	plane = plane_item_to_vkms_configfs_plane(item);
340	lock = &plane->dev->lock;
341
342	scoped_guard(mutex, lock) {
343		vkms_config_destroy_plane(plane->config);
344		kfree(plane);
345	}
346}
347
348static struct configfs_item_operations plane_item_operations = {
349	.release	= &plane_release,
350};
351
352static const struct config_item_type plane_item_type = {
353	.ct_attrs	= plane_item_attrs,
354	.ct_item_ops	= &plane_item_operations,
355	.ct_owner	= THIS_MODULE,
356};
357
358static struct config_group *make_plane_group(struct config_group *group,
359					     const char *name)
360{
361	struct vkms_configfs_device *dev;
362	struct vkms_configfs_plane *plane;
363	int ret;
364
365	dev = child_group_to_vkms_configfs_device(group);
366
367	scoped_guard(mutex, &dev->lock) {
368		if (dev->enabled)
369			return ERR_PTR(-EBUSY);
370
371		plane = kzalloc(sizeof(*plane), GFP_KERNEL);
372		if (!plane)
373			return ERR_PTR(-ENOMEM);
374
375		plane->dev = dev;
376
377		plane->config = vkms_config_create_plane(dev->config);
378		if (IS_ERR(plane->config)) {
379			ret = PTR_ERR(plane->config);
380			kfree(plane);
381			return ERR_PTR(ret);
382		}
383
384		config_group_init_type_name(&plane->group, name, &plane_item_type);
385
386		config_group_init_type_name(&plane->possible_crtcs_group,
387					    "possible_crtcs",
388					    &plane_possible_crtcs_group_type);
389		configfs_add_default_group(&plane->possible_crtcs_group,
390					   &plane->group);
391	}
392
393	return &plane->group;
394}
395
396static struct configfs_group_operations planes_group_operations = {
397	.make_group	= &make_plane_group,
398};
399
400static const struct config_item_type plane_group_type = {
401	.ct_group_ops	= &planes_group_operations,
402	.ct_owner	= THIS_MODULE,
403};
404
405static int encoder_possible_crtcs_allow_link(struct config_item *src,
406					     struct config_item *target)
407{
408	struct vkms_configfs_encoder *encoder;
409	struct vkms_configfs_crtc *crtc;
410	int ret;
411
412	if (target->ci_type != &crtc_item_type)
413		return -EINVAL;
414
415	encoder = encoder_possible_crtcs_item_to_vkms_configfs_encoder(src);
416	crtc = crtc_item_to_vkms_configfs_crtc(target);
417
418	scoped_guard(mutex, &encoder->dev->lock) {
419		if (encoder->dev->enabled)
420			return -EBUSY;
421
422		ret = vkms_config_encoder_attach_crtc(encoder->config, crtc->config);
423	}
424
425	return ret;
426}
427
428static void encoder_possible_crtcs_drop_link(struct config_item *src,
429					     struct config_item *target)
430{
431	struct vkms_configfs_encoder *encoder;
432	struct vkms_configfs_crtc *crtc;
433
434	encoder = encoder_possible_crtcs_item_to_vkms_configfs_encoder(src);
435	crtc = crtc_item_to_vkms_configfs_crtc(target);
436
437	scoped_guard(mutex, &encoder->dev->lock)
438		vkms_config_encoder_detach_crtc(encoder->config, crtc->config);
439}
440
441static struct configfs_item_operations encoder_possible_crtcs_item_operations = {
442	.allow_link	= encoder_possible_crtcs_allow_link,
443	.drop_link	= encoder_possible_crtcs_drop_link,
444};
445
446static const struct config_item_type encoder_possible_crtcs_group_type = {
447	.ct_item_ops	= &encoder_possible_crtcs_item_operations,
448	.ct_owner	= THIS_MODULE,
449};
450
451static void encoder_release(struct config_item *item)
452{
453	struct vkms_configfs_encoder *encoder;
454	struct mutex *lock;
455
456	encoder = encoder_item_to_vkms_configfs_encoder(item);
457	lock = &encoder->dev->lock;
458
459	scoped_guard(mutex, lock) {
460		vkms_config_destroy_encoder(encoder->dev->config, encoder->config);
461		kfree(encoder);
462	}
463}
464
465static struct configfs_item_operations encoder_item_operations = {
466	.release	= &encoder_release,
467};
468
469static const struct config_item_type encoder_item_type = {
470	.ct_item_ops	= &encoder_item_operations,
471	.ct_owner	= THIS_MODULE,
472};
473
474static struct config_group *make_encoder_group(struct config_group *group,
475					       const char *name)
476{
477	struct vkms_configfs_device *dev;
478	struct vkms_configfs_encoder *encoder;
479	int ret;
480
481	dev = child_group_to_vkms_configfs_device(group);
482
483	scoped_guard(mutex, &dev->lock) {
484		if (dev->enabled)
485			return ERR_PTR(-EBUSY);
486
487		encoder = kzalloc(sizeof(*encoder), GFP_KERNEL);
488		if (!encoder)
489			return ERR_PTR(-ENOMEM);
490
491		encoder->dev = dev;
492
493		encoder->config = vkms_config_create_encoder(dev->config);
494		if (IS_ERR(encoder->config)) {
495			ret = PTR_ERR(encoder->config);
496			kfree(encoder);
497			return ERR_PTR(ret);
498		}
499
500		config_group_init_type_name(&encoder->group, name,
501					    &encoder_item_type);
502
503		config_group_init_type_name(&encoder->possible_crtcs_group,
504					    "possible_crtcs",
505					    &encoder_possible_crtcs_group_type);
506		configfs_add_default_group(&encoder->possible_crtcs_group,
507					   &encoder->group);
508	}
509
510	return &encoder->group;
511}
512
513static struct configfs_group_operations encoders_group_operations = {
514	.make_group	= &make_encoder_group,
515};
516
517static const struct config_item_type encoder_group_type = {
518	.ct_group_ops	= &encoders_group_operations,
519	.ct_owner	= THIS_MODULE,
520};
521
522static ssize_t connector_status_show(struct config_item *item, char *page)
523{
524	struct vkms_configfs_connector *connector;
525	enum drm_connector_status status;
526
527	connector = connector_item_to_vkms_configfs_connector(item);
528
529	scoped_guard(mutex, &connector->dev->lock)
530		status = vkms_config_connector_get_status(connector->config);
531
532	return sprintf(page, "%u", status);
533}
534
535static ssize_t connector_status_store(struct config_item *item,
536				      const char *page, size_t count)
537{
538	struct vkms_configfs_connector *connector;
539	enum drm_connector_status status;
540
541	connector = connector_item_to_vkms_configfs_connector(item);
542
543	if (kstrtouint(page, 10, &status))
544		return -EINVAL;
545
546	if (status != connector_status_connected &&
547	    status != connector_status_disconnected &&
548	    status != connector_status_unknown)
549		return -EINVAL;
550
551	scoped_guard(mutex, &connector->dev->lock) {
552		vkms_config_connector_set_status(connector->config, status);
553
554		if (connector->dev->enabled)
555			vkms_trigger_connector_hotplug(connector->dev->config->dev);
556	}
557
558	return (ssize_t)count;
559}
560
561CONFIGFS_ATTR(connector_, status);
562
563static struct configfs_attribute *connector_item_attrs[] = {
564	&connector_attr_status,
565	NULL,
566};
567
568static void connector_release(struct config_item *item)
569{
570	struct vkms_configfs_connector *connector;
571	struct mutex *lock;
572
573	connector = connector_item_to_vkms_configfs_connector(item);
574	lock = &connector->dev->lock;
575
576	scoped_guard(mutex, lock) {
577		vkms_config_destroy_connector(connector->config);
578		kfree(connector);
579	}
580}
581
582static struct configfs_item_operations connector_item_operations = {
583	.release	= &connector_release,
584};
585
586static const struct config_item_type connector_item_type = {
587	.ct_attrs	= connector_item_attrs,
588	.ct_item_ops	= &connector_item_operations,
589	.ct_owner	= THIS_MODULE,
590};
591
592static int connector_possible_encoders_allow_link(struct config_item *src,
593						  struct config_item *target)
594{
595	struct vkms_configfs_connector *connector;
596	struct vkms_configfs_encoder *encoder;
597	int ret;
598
599	if (target->ci_type != &encoder_item_type)
600		return -EINVAL;
601
602	connector = connector_possible_encoders_item_to_vkms_configfs_connector(src);
603	encoder = encoder_item_to_vkms_configfs_encoder(target);
604
605	scoped_guard(mutex, &connector->dev->lock) {
606		if (connector->dev->enabled)
607			return -EBUSY;
608
609		ret = vkms_config_connector_attach_encoder(connector->config,
610							   encoder->config);
611	}
612
613	return ret;
614}
615
616static void connector_possible_encoders_drop_link(struct config_item *src,
617						  struct config_item *target)
618{
619	struct vkms_configfs_connector *connector;
620	struct vkms_configfs_encoder *encoder;
621
622	connector = connector_possible_encoders_item_to_vkms_configfs_connector(src);
623	encoder = encoder_item_to_vkms_configfs_encoder(target);
624
625	scoped_guard(mutex, &connector->dev->lock) {
626		vkms_config_connector_detach_encoder(connector->config,
627						     encoder->config);
628	}
629}
630
631static struct configfs_item_operations connector_possible_encoders_item_operations = {
632	.allow_link	= connector_possible_encoders_allow_link,
633	.drop_link	= connector_possible_encoders_drop_link,
634};
635
636static const struct config_item_type connector_possible_encoders_group_type = {
637	.ct_item_ops	= &connector_possible_encoders_item_operations,
638	.ct_owner	= THIS_MODULE,
639};
640
641static struct config_group *make_connector_group(struct config_group *group,
642						 const char *name)
643{
644	struct vkms_configfs_device *dev;
645	struct vkms_configfs_connector *connector;
646	int ret;
647
648	dev = child_group_to_vkms_configfs_device(group);
649
650	scoped_guard(mutex, &dev->lock) {
651		if (dev->enabled)
652			return ERR_PTR(-EBUSY);
653
654		connector = kzalloc(sizeof(*connector), GFP_KERNEL);
655		if (!connector)
656			return ERR_PTR(-ENOMEM);
657
658		connector->dev = dev;
659
660		connector->config = vkms_config_create_connector(dev->config);
661		if (IS_ERR(connector->config)) {
662			ret = PTR_ERR(connector->config);
663			kfree(connector);
664			return ERR_PTR(ret);
665		}
666
667		config_group_init_type_name(&connector->group, name,
668					    &connector_item_type);
669
670		config_group_init_type_name(&connector->possible_encoders_group,
671					    "possible_encoders",
672					    &connector_possible_encoders_group_type);
673		configfs_add_default_group(&connector->possible_encoders_group,
674					   &connector->group);
675	}
676
677	return &connector->group;
678}
679
680static struct configfs_group_operations connectors_group_operations = {
681	.make_group	= &make_connector_group,
682};
683
684static const struct config_item_type connector_group_type = {
685	.ct_group_ops	= &connectors_group_operations,
686	.ct_owner	= THIS_MODULE,
687};
688
689static ssize_t device_enabled_show(struct config_item *item, char *page)
690{
691	struct vkms_configfs_device *dev;
692	bool enabled;
693
694	dev = device_item_to_vkms_configfs_device(item);
695
696	scoped_guard(mutex, &dev->lock)
697		enabled = dev->enabled;
698
699	return sprintf(page, "%d\n", enabled);
700}
701
702static ssize_t device_enabled_store(struct config_item *item, const char *page,
703				    size_t count)
704{
705	struct vkms_configfs_device *dev;
706	bool enabled;
707	int ret = 0;
708
709	dev = device_item_to_vkms_configfs_device(item);
710
711	if (kstrtobool(page, &enabled))
712		return -EINVAL;
713
714	scoped_guard(mutex, &dev->lock) {
715		if (!dev->enabled && enabled) {
716			if (!vkms_config_is_valid(dev->config))
717				return -EINVAL;
718
719			ret = vkms_create(dev->config);
720			if (ret)
721				return ret;
722		} else if (dev->enabled && !enabled) {
723			vkms_destroy(dev->config);
724		}
725
726		dev->enabled = enabled;
727	}
728
729	return (ssize_t)count;
730}
731
732CONFIGFS_ATTR(device_, enabled);
733
734static struct configfs_attribute *device_item_attrs[] = {
735	&device_attr_enabled,
736	NULL,
737};
738
739static void device_release(struct config_item *item)
740{
741	struct vkms_configfs_device *dev;
742
743	dev = device_item_to_vkms_configfs_device(item);
744
745	if (dev->enabled)
746		vkms_destroy(dev->config);
747
748	mutex_destroy(&dev->lock);
749	vkms_config_destroy(dev->config);
750	kfree(dev);
751}
752
753static struct configfs_item_operations device_item_operations = {
754	.release	= &device_release,
755};
756
757static const struct config_item_type device_item_type = {
758	.ct_attrs	= device_item_attrs,
759	.ct_item_ops	= &device_item_operations,
760	.ct_owner	= THIS_MODULE,
761};
762
763static struct config_group *make_device_group(struct config_group *group,
764					      const char *name)
765{
766	struct vkms_configfs_device *dev;
767	int ret;
768
769	if (strcmp(name, DEFAULT_DEVICE_NAME) == 0)
770		return ERR_PTR(-EINVAL);
771
772	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
773	if (!dev)
774		return ERR_PTR(-ENOMEM);
775
776	dev->config = vkms_config_create(name);
777	if (IS_ERR(dev->config)) {
778		ret = PTR_ERR(dev->config);
779		kfree(dev);
780		return ERR_PTR(ret);
781	}
782
783	config_group_init_type_name(&dev->group, name, &device_item_type);
784	mutex_init(&dev->lock);
785
786	config_group_init_type_name(&dev->planes_group, "planes",
787				    &plane_group_type);
788	configfs_add_default_group(&dev->planes_group, &dev->group);
789
790	config_group_init_type_name(&dev->crtcs_group, "crtcs",
791				    &crtc_group_type);
792	configfs_add_default_group(&dev->crtcs_group, &dev->group);
793
794	config_group_init_type_name(&dev->encoders_group, "encoders",
795				    &encoder_group_type);
796	configfs_add_default_group(&dev->encoders_group, &dev->group);
797
798	config_group_init_type_name(&dev->connectors_group, "connectors",
799				    &connector_group_type);
800	configfs_add_default_group(&dev->connectors_group, &dev->group);
801
802	return &dev->group;
803}
804
805static struct configfs_group_operations device_group_ops = {
806	.make_group = &make_device_group,
807};
808
809static const struct config_item_type device_group_type = {
810	.ct_group_ops	= &device_group_ops,
811	.ct_owner	= THIS_MODULE,
812};
813
814static struct configfs_subsystem vkms_subsys = {
815	.su_group = {
816		.cg_item = {
817			.ci_name = "vkms",
818			.ci_type = &device_group_type,
819		},
820	},
821	.su_mutex = __MUTEX_INITIALIZER(vkms_subsys.su_mutex),
822};
823
824int vkms_configfs_register(void)
825{
826	int ret;
827
828	if (is_configfs_registered)
829		return 0;
830
831	config_group_init(&vkms_subsys.su_group);
832	ret = configfs_register_subsystem(&vkms_subsys);
833
834	is_configfs_registered = ret == 0;
835
836	return ret;
837}
838
839void vkms_configfs_unregister(void)
840{
841	if (is_configfs_registered)
842		configfs_unregister_subsystem(&vkms_subsys);
843}
~/ Read-only file preview.