configfs.c 18 KB

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