xref: /linux/drivers/most/configfs.c (revision 24ce659dcc02c21f8d6c0a7589c3320a4dfa8152)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * configfs.c - Implementation of configfs interface to the driver stack
4  *
5  * Copyright (C) 2013-2015 Microchip Technology Germany II GmbH & Co. KG
6  */
7 
8 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
9 #include <linux/module.h>
10 #include <linux/slab.h>
11 #include <linux/init.h>
12 #include <linux/configfs.h>
13 #include <linux/most.h>
14 
15 #define MAX_STRING_SIZE 80
16 
17 struct mdev_link {
18 	struct config_item item;
19 	struct list_head list;
20 	bool create_link;
21 	bool destroy_link;
22 	u16 num_buffers;
23 	u16 buffer_size;
24 	u16 subbuffer_size;
25 	u16 packets_per_xact;
26 	u16 dbr_size;
27 	char datatype[MAX_STRING_SIZE];
28 	char direction[MAX_STRING_SIZE];
29 	char name[MAX_STRING_SIZE];
30 	char device[MAX_STRING_SIZE];
31 	char channel[MAX_STRING_SIZE];
32 	char comp[MAX_STRING_SIZE];
33 	char comp_params[MAX_STRING_SIZE];
34 };
35 
36 static struct list_head mdev_link_list;
37 
38 static int set_cfg_buffer_size(struct mdev_link *link)
39 {
40 	return most_set_cfg_buffer_size(link->device, link->channel,
41 					link->buffer_size);
42 }
43 
44 static int set_cfg_subbuffer_size(struct mdev_link *link)
45 {
46 	return most_set_cfg_subbuffer_size(link->device, link->channel,
47 					   link->subbuffer_size);
48 }
49 
50 static int set_cfg_dbr_size(struct mdev_link *link)
51 {
52 	return most_set_cfg_dbr_size(link->device, link->channel,
53 				     link->dbr_size);
54 }
55 
56 static int set_cfg_num_buffers(struct mdev_link *link)
57 {
58 	return most_set_cfg_num_buffers(link->device, link->channel,
59 					link->num_buffers);
60 }
61 
62 static int set_cfg_packets_xact(struct mdev_link *link)
63 {
64 	return most_set_cfg_packets_xact(link->device, link->channel,
65 					 link->packets_per_xact);
66 }
67 
68 static int set_cfg_direction(struct mdev_link *link)
69 {
70 	return most_set_cfg_direction(link->device, link->channel,
71 				      link->direction);
72 }
73 
74 static int set_cfg_datatype(struct mdev_link *link)
75 {
76 	return most_set_cfg_datatype(link->device, link->channel,
77 				     link->datatype);
78 }
79 
80 static int (*set_config_val[])(struct mdev_link *link) = {
81 	set_cfg_buffer_size,
82 	set_cfg_subbuffer_size,
83 	set_cfg_dbr_size,
84 	set_cfg_num_buffers,
85 	set_cfg_packets_xact,
86 	set_cfg_direction,
87 	set_cfg_datatype,
88 };
89 
90 static struct mdev_link *to_mdev_link(struct config_item *item)
91 {
92 	return container_of(item, struct mdev_link, item);
93 }
94 
95 static int set_config_and_add_link(struct mdev_link *mdev_link)
96 {
97 	int i;
98 	int ret;
99 
100 	for (i = 0; i < ARRAY_SIZE(set_config_val); i++) {
101 		ret = set_config_val[i](mdev_link);
102 		if (ret < 0 && ret != -ENODEV) {
103 			pr_err("Config failed\n");
104 			return ret;
105 		}
106 	}
107 
108 	return most_add_link(mdev_link->device, mdev_link->channel,
109 			     mdev_link->comp, mdev_link->name,
110 			     mdev_link->comp_params);
111 }
112 
113 static ssize_t mdev_link_create_link_store(struct config_item *item,
114 					   const char *page, size_t count)
115 {
116 	struct mdev_link *mdev_link = to_mdev_link(item);
117 	bool tmp;
118 	int ret;
119 
120 	ret = kstrtobool(page, &tmp);
121 	if (ret)
122 		return ret;
123 	if (!tmp)
124 		return count;
125 	ret = set_config_and_add_link(mdev_link);
126 	if (ret && ret != -ENODEV)
127 		return ret;
128 	list_add_tail(&mdev_link->list, &mdev_link_list);
129 	mdev_link->create_link = tmp;
130 	mdev_link->destroy_link = false;
131 
132 	return count;
133 }
134 
135 static ssize_t mdev_link_destroy_link_store(struct config_item *item,
136 					    const char *page, size_t count)
137 {
138 	struct mdev_link *mdev_link = to_mdev_link(item);
139 	bool tmp;
140 	int ret;
141 
142 	ret = kstrtobool(page, &tmp);
143 	if (ret)
144 		return ret;
145 	if (!tmp)
146 		return count;
147 
148 	ret = most_remove_link(mdev_link->device, mdev_link->channel,
149 			       mdev_link->comp);
150 	if (ret)
151 		return ret;
152 	if (!list_empty(&mdev_link_list))
153 		list_del(&mdev_link->list);
154 
155 	mdev_link->destroy_link = tmp;
156 
157 	return count;
158 }
159 
160 static ssize_t mdev_link_direction_show(struct config_item *item, char *page)
161 {
162 	return snprintf(page, PAGE_SIZE, "%s\n", to_mdev_link(item)->direction);
163 }
164 
165 static ssize_t mdev_link_direction_store(struct config_item *item,
166 					 const char *page, size_t count)
167 {
168 	struct mdev_link *mdev_link = to_mdev_link(item);
169 
170 	if (!sysfs_streq(page, "dir_rx") && !sysfs_streq(page, "rx") &&
171 	    !sysfs_streq(page, "dir_tx") && !sysfs_streq(page, "tx"))
172 		return -EINVAL;
173 	strcpy(mdev_link->direction, page);
174 	strim(mdev_link->direction);
175 	return count;
176 }
177 
178 static ssize_t mdev_link_datatype_show(struct config_item *item, char *page)
179 {
180 	return snprintf(page, PAGE_SIZE, "%s\n", to_mdev_link(item)->datatype);
181 }
182 
183 static ssize_t mdev_link_datatype_store(struct config_item *item,
184 					const char *page, size_t count)
185 {
186 	struct mdev_link *mdev_link = to_mdev_link(item);
187 
188 	if (!sysfs_streq(page, "control") && !sysfs_streq(page, "async") &&
189 	    !sysfs_streq(page, "sync") && !sysfs_streq(page, "isoc") &&
190 	    !sysfs_streq(page, "isoc_avp"))
191 		return -EINVAL;
192 	strcpy(mdev_link->datatype, page);
193 	strim(mdev_link->datatype);
194 	return count;
195 }
196 
197 static ssize_t mdev_link_device_show(struct config_item *item, char *page)
198 {
199 	return snprintf(page, PAGE_SIZE, "%s\n", to_mdev_link(item)->device);
200 }
201 
202 static ssize_t mdev_link_device_store(struct config_item *item,
203 				      const char *page, size_t count)
204 {
205 	struct mdev_link *mdev_link = to_mdev_link(item);
206 
207 	strlcpy(mdev_link->device, page, sizeof(mdev_link->device));
208 	strim(mdev_link->device);
209 	return count;
210 }
211 
212 static ssize_t mdev_link_channel_show(struct config_item *item, char *page)
213 {
214 	return snprintf(page, PAGE_SIZE, "%s\n", to_mdev_link(item)->channel);
215 }
216 
217 static ssize_t mdev_link_channel_store(struct config_item *item,
218 				       const char *page, size_t count)
219 {
220 	struct mdev_link *mdev_link = to_mdev_link(item);
221 
222 	strlcpy(mdev_link->channel, page, sizeof(mdev_link->channel));
223 	strim(mdev_link->channel);
224 	return count;
225 }
226 
227 static ssize_t mdev_link_comp_show(struct config_item *item, char *page)
228 {
229 	return snprintf(page, PAGE_SIZE, "%s\n", to_mdev_link(item)->comp);
230 }
231 
232 static ssize_t mdev_link_comp_store(struct config_item *item,
233 				    const char *page, size_t count)
234 {
235 	struct mdev_link *mdev_link = to_mdev_link(item);
236 
237 	strlcpy(mdev_link->comp, page, sizeof(mdev_link->comp));
238 	strim(mdev_link->comp);
239 	return count;
240 }
241 
242 static ssize_t mdev_link_comp_params_show(struct config_item *item, char *page)
243 {
244 	return snprintf(page, PAGE_SIZE, "%s\n",
245 			to_mdev_link(item)->comp_params);
246 }
247 
248 static ssize_t mdev_link_comp_params_store(struct config_item *item,
249 					   const char *page, size_t count)
250 {
251 	struct mdev_link *mdev_link = to_mdev_link(item);
252 
253 	strlcpy(mdev_link->comp_params, page, sizeof(mdev_link->comp_params));
254 	strim(mdev_link->comp_params);
255 	return count;
256 }
257 
258 static ssize_t mdev_link_num_buffers_show(struct config_item *item, char *page)
259 {
260 	return snprintf(page, PAGE_SIZE, "%d\n",
261 			to_mdev_link(item)->num_buffers);
262 }
263 
264 static ssize_t mdev_link_num_buffers_store(struct config_item *item,
265 					   const char *page, size_t count)
266 {
267 	struct mdev_link *mdev_link = to_mdev_link(item);
268 	int ret;
269 
270 	ret = kstrtou16(page, 0, &mdev_link->num_buffers);
271 	if (ret)
272 		return ret;
273 	return count;
274 }
275 
276 static ssize_t mdev_link_buffer_size_show(struct config_item *item, char *page)
277 {
278 	return snprintf(page, PAGE_SIZE, "%d\n",
279 			to_mdev_link(item)->buffer_size);
280 }
281 
282 static ssize_t mdev_link_buffer_size_store(struct config_item *item,
283 					   const char *page, size_t count)
284 {
285 	struct mdev_link *mdev_link = to_mdev_link(item);
286 	int ret;
287 
288 	ret = kstrtou16(page, 0, &mdev_link->buffer_size);
289 	if (ret)
290 		return ret;
291 	return count;
292 }
293 
294 static ssize_t mdev_link_subbuffer_size_show(struct config_item *item,
295 					     char *page)
296 {
297 	return snprintf(page, PAGE_SIZE, "%d\n",
298 			to_mdev_link(item)->subbuffer_size);
299 }
300 
301 static ssize_t mdev_link_subbuffer_size_store(struct config_item *item,
302 					      const char *page, size_t count)
303 {
304 	struct mdev_link *mdev_link = to_mdev_link(item);
305 	int ret;
306 
307 	ret = kstrtou16(page, 0, &mdev_link->subbuffer_size);
308 	if (ret)
309 		return ret;
310 	return count;
311 }
312 
313 static ssize_t mdev_link_packets_per_xact_show(struct config_item *item,
314 					       char *page)
315 {
316 	return snprintf(page, PAGE_SIZE, "%d\n",
317 			to_mdev_link(item)->packets_per_xact);
318 }
319 
320 static ssize_t mdev_link_packets_per_xact_store(struct config_item *item,
321 						const char *page, size_t count)
322 {
323 	struct mdev_link *mdev_link = to_mdev_link(item);
324 	int ret;
325 
326 	ret = kstrtou16(page, 0, &mdev_link->packets_per_xact);
327 	if (ret)
328 		return ret;
329 	return count;
330 }
331 
332 static ssize_t mdev_link_dbr_size_show(struct config_item *item, char *page)
333 {
334 	return snprintf(page, PAGE_SIZE, "%d\n", to_mdev_link(item)->dbr_size);
335 }
336 
337 static ssize_t mdev_link_dbr_size_store(struct config_item *item,
338 					const char *page, size_t count)
339 {
340 	struct mdev_link *mdev_link = to_mdev_link(item);
341 	int ret;
342 
343 	ret = kstrtou16(page, 0, &mdev_link->dbr_size);
344 	if (ret)
345 		return ret;
346 	return count;
347 }
348 
349 CONFIGFS_ATTR_WO(mdev_link_, create_link);
350 CONFIGFS_ATTR_WO(mdev_link_, destroy_link);
351 CONFIGFS_ATTR(mdev_link_, device);
352 CONFIGFS_ATTR(mdev_link_, channel);
353 CONFIGFS_ATTR(mdev_link_, comp);
354 CONFIGFS_ATTR(mdev_link_, comp_params);
355 CONFIGFS_ATTR(mdev_link_, num_buffers);
356 CONFIGFS_ATTR(mdev_link_, buffer_size);
357 CONFIGFS_ATTR(mdev_link_, subbuffer_size);
358 CONFIGFS_ATTR(mdev_link_, packets_per_xact);
359 CONFIGFS_ATTR(mdev_link_, datatype);
360 CONFIGFS_ATTR(mdev_link_, direction);
361 CONFIGFS_ATTR(mdev_link_, dbr_size);
362 
363 static struct configfs_attribute *mdev_link_attrs[] = {
364 	&mdev_link_attr_create_link,
365 	&mdev_link_attr_destroy_link,
366 	&mdev_link_attr_device,
367 	&mdev_link_attr_channel,
368 	&mdev_link_attr_comp,
369 	&mdev_link_attr_comp_params,
370 	&mdev_link_attr_num_buffers,
371 	&mdev_link_attr_buffer_size,
372 	&mdev_link_attr_subbuffer_size,
373 	&mdev_link_attr_packets_per_xact,
374 	&mdev_link_attr_datatype,
375 	&mdev_link_attr_direction,
376 	&mdev_link_attr_dbr_size,
377 	NULL,
378 };
379 
380 static void mdev_link_release(struct config_item *item)
381 {
382 	struct mdev_link *mdev_link = to_mdev_link(item);
383 	int ret;
384 
385 	if (mdev_link->destroy_link)
386 		goto free_item;
387 
388 	ret = most_remove_link(mdev_link->device, mdev_link->channel,
389 			       mdev_link->comp);
390 	if (ret) {
391 		pr_err("Removing link failed.\n");
392 		goto free_item;
393 	}
394 
395 	if (!list_empty(&mdev_link_list))
396 		list_del(&mdev_link->list);
397 
398 free_item:
399 	kfree(to_mdev_link(item));
400 }
401 
402 static struct configfs_item_operations mdev_link_item_ops = {
403 	.release		= mdev_link_release,
404 };
405 
406 static const struct config_item_type mdev_link_type = {
407 	.ct_item_ops	= &mdev_link_item_ops,
408 	.ct_attrs	= mdev_link_attrs,
409 	.ct_owner	= THIS_MODULE,
410 };
411 
412 struct most_common {
413 	struct config_group group;
414 	struct module *mod;
415 	struct configfs_subsystem subsys;
416 };
417 
418 static struct most_common *to_most_common(struct configfs_subsystem *subsys)
419 {
420 	return container_of(subsys, struct most_common, subsys);
421 }
422 
423 static struct config_item *most_common_make_item(struct config_group *group,
424 						 const char *name)
425 {
426 	struct mdev_link *mdev_link;
427 	struct most_common *mc = to_most_common(group->cg_subsys);
428 
429 	mdev_link = kzalloc(sizeof(*mdev_link), GFP_KERNEL);
430 	if (!mdev_link)
431 		return ERR_PTR(-ENOMEM);
432 
433 	if (!try_module_get(mc->mod)) {
434 		kfree(mdev_link);
435 		return ERR_PTR(-ENOLCK);
436 	}
437 	config_item_init_type_name(&mdev_link->item, name,
438 				   &mdev_link_type);
439 
440 	if (!strcmp(group->cg_item.ci_namebuf, "most_cdev"))
441 		strcpy(mdev_link->comp, "cdev");
442 	else if (!strcmp(group->cg_item.ci_namebuf, "most_net"))
443 		strcpy(mdev_link->comp, "net");
444 	else if (!strcmp(group->cg_item.ci_namebuf, "most_video"))
445 		strcpy(mdev_link->comp, "video");
446 	strcpy(mdev_link->name, name);
447 	return &mdev_link->item;
448 }
449 
450 static void most_common_release(struct config_item *item)
451 {
452 	struct config_group *group = to_config_group(item);
453 
454 	kfree(to_most_common(group->cg_subsys));
455 }
456 
457 static struct configfs_item_operations most_common_item_ops = {
458 	.release	= most_common_release,
459 };
460 
461 static void most_common_disconnect(struct config_group *group,
462 				   struct config_item *item)
463 {
464 	struct most_common *mc = to_most_common(group->cg_subsys);
465 
466 	module_put(mc->mod);
467 }
468 
469 static struct configfs_group_operations most_common_group_ops = {
470 	.make_item	= most_common_make_item,
471 	.disconnect_notify = most_common_disconnect,
472 };
473 
474 static const struct config_item_type most_common_type = {
475 	.ct_item_ops	= &most_common_item_ops,
476 	.ct_group_ops	= &most_common_group_ops,
477 	.ct_owner	= THIS_MODULE,
478 };
479 
480 static struct most_common most_cdev = {
481 	.subsys = {
482 		.su_group = {
483 			.cg_item = {
484 				.ci_namebuf = "most_cdev",
485 				.ci_type = &most_common_type,
486 			},
487 		},
488 	},
489 };
490 
491 static struct most_common most_net = {
492 	.subsys = {
493 		.su_group = {
494 			.cg_item = {
495 				.ci_namebuf = "most_net",
496 				.ci_type = &most_common_type,
497 			},
498 		},
499 	},
500 };
501 
502 static struct most_common most_video = {
503 	.subsys = {
504 		.su_group = {
505 			.cg_item = {
506 				.ci_namebuf = "most_video",
507 				.ci_type = &most_common_type,
508 			},
509 		},
510 	},
511 };
512 
513 struct most_snd_grp {
514 	struct config_group group;
515 	bool create_card;
516 	struct list_head list;
517 };
518 
519 static struct most_snd_grp *to_most_snd_grp(struct config_item *item)
520 {
521 	return container_of(to_config_group(item), struct most_snd_grp, group);
522 }
523 
524 static struct config_item *most_snd_grp_make_item(struct config_group *group,
525 						  const char *name)
526 {
527 	struct mdev_link *mdev_link;
528 
529 	mdev_link = kzalloc(sizeof(*mdev_link), GFP_KERNEL);
530 	if (!mdev_link)
531 		return ERR_PTR(-ENOMEM);
532 
533 	config_item_init_type_name(&mdev_link->item, name, &mdev_link_type);
534 	mdev_link->create_link = false;
535 	strcpy(mdev_link->name, name);
536 	strcpy(mdev_link->comp, "sound");
537 	return &mdev_link->item;
538 }
539 
540 static ssize_t most_snd_grp_create_card_store(struct config_item *item,
541 					      const char *page, size_t count)
542 {
543 	struct most_snd_grp *snd_grp = to_most_snd_grp(item);
544 	int ret;
545 	bool tmp;
546 
547 	ret = kstrtobool(page, &tmp);
548 	if (ret)
549 		return ret;
550 	if (tmp) {
551 		ret = most_cfg_complete("sound");
552 		if (ret)
553 			return ret;
554 	}
555 	snd_grp->create_card = tmp;
556 	return count;
557 }
558 
559 CONFIGFS_ATTR_WO(most_snd_grp_, create_card);
560 
561 static struct configfs_attribute *most_snd_grp_attrs[] = {
562 	&most_snd_grp_attr_create_card,
563 	NULL,
564 };
565 
566 static void most_snd_grp_release(struct config_item *item)
567 {
568 	struct most_snd_grp *group = to_most_snd_grp(item);
569 
570 	list_del(&group->list);
571 	kfree(group);
572 }
573 
574 static struct configfs_item_operations most_snd_grp_item_ops = {
575 	.release	= most_snd_grp_release,
576 };
577 
578 static struct configfs_group_operations most_snd_grp_group_ops = {
579 	.make_item	= most_snd_grp_make_item,
580 };
581 
582 static const struct config_item_type most_snd_grp_type = {
583 	.ct_item_ops	= &most_snd_grp_item_ops,
584 	.ct_group_ops	= &most_snd_grp_group_ops,
585 	.ct_attrs	= most_snd_grp_attrs,
586 	.ct_owner	= THIS_MODULE,
587 };
588 
589 struct most_sound {
590 	struct configfs_subsystem subsys;
591 	struct list_head soundcard_list;
592 	struct module *mod;
593 };
594 
595 static struct config_group *most_sound_make_group(struct config_group *group,
596 						  const char *name)
597 {
598 	struct most_snd_grp *most;
599 	struct most_sound *ms = container_of(group->cg_subsys,
600 					     struct most_sound, subsys);
601 
602 	list_for_each_entry(most, &ms->soundcard_list, list) {
603 		if (!most->create_card) {
604 			pr_info("adapter configuration still in progress.\n");
605 			return ERR_PTR(-EPROTO);
606 		}
607 	}
608 	if (!try_module_get(ms->mod))
609 		return ERR_PTR(-ENOLCK);
610 	most = kzalloc(sizeof(*most), GFP_KERNEL);
611 	if (!most) {
612 		module_put(ms->mod);
613 		return ERR_PTR(-ENOMEM);
614 	}
615 	config_group_init_type_name(&most->group, name, &most_snd_grp_type);
616 	list_add_tail(&most->list, &ms->soundcard_list);
617 	return &most->group;
618 }
619 
620 static void most_sound_disconnect(struct config_group *group,
621 				  struct config_item *item)
622 {
623 	struct most_sound *ms = container_of(group->cg_subsys,
624 					     struct most_sound, subsys);
625 	module_put(ms->mod);
626 }
627 
628 static struct configfs_group_operations most_sound_group_ops = {
629 	.make_group	= most_sound_make_group,
630 	.disconnect_notify = most_sound_disconnect,
631 };
632 
633 static const struct config_item_type most_sound_type = {
634 	.ct_group_ops	= &most_sound_group_ops,
635 	.ct_owner	= THIS_MODULE,
636 };
637 
638 static struct most_sound most_sound_subsys = {
639 	.subsys = {
640 		.su_group = {
641 			.cg_item = {
642 				.ci_namebuf = "most_sound",
643 				.ci_type = &most_sound_type,
644 			},
645 		},
646 	},
647 };
648 
649 int most_register_configfs_subsys(struct most_component *c)
650 {
651 	int ret;
652 
653 	if (!strcmp(c->name, "cdev")) {
654 		most_cdev.mod = c->mod;
655 		ret = configfs_register_subsystem(&most_cdev.subsys);
656 	} else if (!strcmp(c->name, "net")) {
657 		most_net.mod = c->mod;
658 		ret = configfs_register_subsystem(&most_net.subsys);
659 	} else if (!strcmp(c->name, "video")) {
660 		most_video.mod = c->mod;
661 		ret = configfs_register_subsystem(&most_video.subsys);
662 	} else if (!strcmp(c->name, "sound")) {
663 		most_sound_subsys.mod = c->mod;
664 		ret = configfs_register_subsystem(&most_sound_subsys.subsys);
665 	} else {
666 		return -ENODEV;
667 	}
668 
669 	if (ret) {
670 		pr_err("Error %d while registering subsystem %s\n",
671 		       ret, c->name);
672 	}
673 	return ret;
674 }
675 EXPORT_SYMBOL_GPL(most_register_configfs_subsys);
676 
677 void most_interface_register_notify(const char *mdev)
678 {
679 	bool register_snd_card = false;
680 	struct mdev_link *mdev_link;
681 
682 	list_for_each_entry(mdev_link, &mdev_link_list, list) {
683 		if (!strcmp(mdev_link->device, mdev)) {
684 			set_config_and_add_link(mdev_link);
685 			if (!strcmp(mdev_link->comp, "sound"))
686 				register_snd_card = true;
687 		}
688 	}
689 	if (register_snd_card)
690 		most_cfg_complete("sound");
691 }
692 
693 void most_deregister_configfs_subsys(struct most_component *c)
694 {
695 	if (!strcmp(c->name, "cdev"))
696 		configfs_unregister_subsystem(&most_cdev.subsys);
697 	else if (!strcmp(c->name, "net"))
698 		configfs_unregister_subsystem(&most_net.subsys);
699 	else if (!strcmp(c->name, "video"))
700 		configfs_unregister_subsystem(&most_video.subsys);
701 	else if (!strcmp(c->name, "sound"))
702 		configfs_unregister_subsystem(&most_sound_subsys.subsys);
703 }
704 EXPORT_SYMBOL_GPL(most_deregister_configfs_subsys);
705 
706 int __init configfs_init(void)
707 {
708 	config_group_init(&most_cdev.subsys.su_group);
709 	mutex_init(&most_cdev.subsys.su_mutex);
710 
711 	config_group_init(&most_net.subsys.su_group);
712 	mutex_init(&most_net.subsys.su_mutex);
713 
714 	config_group_init(&most_video.subsys.su_group);
715 	mutex_init(&most_video.subsys.su_mutex);
716 
717 	config_group_init(&most_sound_subsys.subsys.su_group);
718 	mutex_init(&most_sound_subsys.subsys.su_mutex);
719 
720 	INIT_LIST_HEAD(&most_sound_subsys.soundcard_list);
721 	INIT_LIST_HEAD(&mdev_link_list);
722 
723 	return 0;
724 }
725