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 */
13 static 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 */
29 struct 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 */
50 struct 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 */
65 struct 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 */
80 struct 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 */
97 struct 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
crtc_writeback_show(struct config_item * item,char * page)137 static 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
crtc_writeback_store(struct config_item * item,const char * page,size_t count)150 static 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
171 CONFIGFS_ATTR(crtc_, writeback);
172
173 static struct configfs_attribute *crtc_item_attrs[] = {
174 &crtc_attr_writeback,
175 NULL,
176 };
177
crtc_release(struct config_item * item)178 static 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
192 static struct configfs_item_operations crtc_item_operations = {
193 .release = &crtc_release,
194 };
195
196 static 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
make_crtc_group(struct config_group * group,const char * name)202 static 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
234 static struct configfs_group_operations crtcs_group_operations = {
235 .make_group = &make_crtc_group,
236 };
237
238 static const struct config_item_type crtc_group_type = {
239 .ct_group_ops = &crtcs_group_operations,
240 .ct_owner = THIS_MODULE,
241 };
242
plane_possible_crtcs_allow_link(struct config_item * src,struct config_item * target)243 static 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
plane_possible_crtcs_drop_link(struct config_item * src,struct config_item * target)266 static 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
279 static 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
284 static 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
plane_type_show(struct config_item * item,char * page)289 static 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
plane_type_store(struct config_item * item,const char * page,size_t count)302 static 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
327 CONFIGFS_ATTR(plane_, type);
328
329 static struct configfs_attribute *plane_item_attrs[] = {
330 &plane_attr_type,
331 NULL,
332 };
333
plane_release(struct config_item * item)334 static 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
348 static struct configfs_item_operations plane_item_operations = {
349 .release = &plane_release,
350 };
351
352 static 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
make_plane_group(struct config_group * group,const char * name)358 static 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
396 static struct configfs_group_operations planes_group_operations = {
397 .make_group = &make_plane_group,
398 };
399
400 static const struct config_item_type plane_group_type = {
401 .ct_group_ops = &planes_group_operations,
402 .ct_owner = THIS_MODULE,
403 };
404
encoder_possible_crtcs_allow_link(struct config_item * src,struct config_item * target)405 static 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
encoder_possible_crtcs_drop_link(struct config_item * src,struct config_item * target)428 static 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
441 static 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
446 static 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
encoder_release(struct config_item * item)451 static 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
465 static struct configfs_item_operations encoder_item_operations = {
466 .release = &encoder_release,
467 };
468
469 static const struct config_item_type encoder_item_type = {
470 .ct_item_ops = &encoder_item_operations,
471 .ct_owner = THIS_MODULE,
472 };
473
make_encoder_group(struct config_group * group,const char * name)474 static 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
513 static struct configfs_group_operations encoders_group_operations = {
514 .make_group = &make_encoder_group,
515 };
516
517 static const struct config_item_type encoder_group_type = {
518 .ct_group_ops = &encoders_group_operations,
519 .ct_owner = THIS_MODULE,
520 };
521
connector_status_show(struct config_item * item,char * page)522 static 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
connector_status_store(struct config_item * item,const char * page,size_t count)535 static 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
561 CONFIGFS_ATTR(connector_, status);
562
563 static struct configfs_attribute *connector_item_attrs[] = {
564 &connector_attr_status,
565 NULL,
566 };
567
connector_release(struct config_item * item)568 static 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
582 static struct configfs_item_operations connector_item_operations = {
583 .release = &connector_release,
584 };
585
586 static 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
connector_possible_encoders_allow_link(struct config_item * src,struct config_item * target)592 static 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
connector_possible_encoders_drop_link(struct config_item * src,struct config_item * target)616 static 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
631 static 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
636 static 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
make_connector_group(struct config_group * group,const char * name)641 static 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
680 static struct configfs_group_operations connectors_group_operations = {
681 .make_group = &make_connector_group,
682 };
683
684 static const struct config_item_type connector_group_type = {
685 .ct_group_ops = &connectors_group_operations,
686 .ct_owner = THIS_MODULE,
687 };
688
device_enabled_show(struct config_item * item,char * page)689 static 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
device_enabled_store(struct config_item * item,const char * page,size_t count)702 static 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
732 CONFIGFS_ATTR(device_, enabled);
733
734 static struct configfs_attribute *device_item_attrs[] = {
735 &device_attr_enabled,
736 NULL,
737 };
738
device_release(struct config_item * item)739 static 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
753 static struct configfs_item_operations device_item_operations = {
754 .release = &device_release,
755 };
756
757 static 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
make_device_group(struct config_group * group,const char * name)763 static 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_obj(*dev);
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
805 static struct configfs_group_operations device_group_ops = {
806 .make_group = &make_device_group,
807 };
808
809 static const struct config_item_type device_group_type = {
810 .ct_group_ops = &device_group_ops,
811 .ct_owner = THIS_MODULE,
812 };
813
814 static 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
vkms_configfs_register(void)824 int 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
vkms_configfs_unregister(void)839 void vkms_configfs_unregister(void)
840 {
841 if (is_configfs_registered)
842 configfs_unregister_subsystem(&vkms_subsys);
843 }
844