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