1
2
3
4
5
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
15struct 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
34static struct list_head mdev_link_list;
35
36static 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
42static 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
48static 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
54static 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
60static 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
66static int set_cfg_direction(struct mdev_link *link)
67{
68 return most_set_cfg_direction(link->device, link->channel,
69 link->direction);
70}
71
72static int set_cfg_datatype(struct mdev_link *link)
73{
74 return most_set_cfg_datatype(link->device, link->channel,
75 link->datatype);
76}
77
78static 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
88static struct mdev_link *to_mdev_link(struct config_item *item)
89{
90 return container_of(item, struct mdev_link, item);
91}
92
93static 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
111static 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
131static 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
153static 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
158static 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
170static 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
175static 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
188static 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
193static 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
202static 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
207static 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
216static 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
221static 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
230static 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
236static 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
245static 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
251static 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
263static 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
269static 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
281static 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
288static 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
300static 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
307static 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
319static 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
324static 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
336CONFIGFS_ATTR_WO(mdev_link_, create_link);
337CONFIGFS_ATTR_WO(mdev_link_, destroy_link);
338CONFIGFS_ATTR(mdev_link_, device);
339CONFIGFS_ATTR(mdev_link_, channel);
340CONFIGFS_ATTR(mdev_link_, comp);
341CONFIGFS_ATTR(mdev_link_, comp_params);
342CONFIGFS_ATTR(mdev_link_, num_buffers);
343CONFIGFS_ATTR(mdev_link_, buffer_size);
344CONFIGFS_ATTR(mdev_link_, subbuffer_size);
345CONFIGFS_ATTR(mdev_link_, packets_per_xact);
346CONFIGFS_ATTR(mdev_link_, datatype);
347CONFIGFS_ATTR(mdev_link_, direction);
348CONFIGFS_ATTR(mdev_link_, dbr_size);
349
350static 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
367static 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
382static struct configfs_item_operations mdev_link_item_ops = {
383 .release = mdev_link_release,
384};
385
386static 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
392struct most_common {
393 struct config_group group;
394};
395
396static 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
401static 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
423static void most_common_release(struct config_item *item)
424{
425 kfree(to_most_common(item));
426}
427
428static struct configfs_item_operations most_common_item_ops = {
429 .release = most_common_release,
430};
431
432static struct configfs_group_operations most_common_group_ops = {
433 .make_item = most_common_make_item,
434};
435
436static 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
442static 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
451static 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
460static 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
469struct most_snd_grp {
470 struct config_group group;
471 bool create_card;
472 struct list_head list;
473};
474
475static 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
480static 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
496static 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
515CONFIGFS_ATTR_WO(most_snd_grp_, create_card);
516
517static struct configfs_attribute *most_snd_grp_attrs[] = {
518 &most_snd_grp_attr_create_card,
519 NULL,
520};
521
522static 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
530static struct configfs_item_operations most_snd_grp_item_ops = {
531 .release = most_snd_grp_release,
532};
533
534static struct configfs_group_operations most_snd_grp_group_ops = {
535 .make_item = most_snd_grp_make_item,
536};
537
538static 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
545struct most_sound {
546 struct configfs_subsystem subsys;
547 struct list_head soundcard_list;
548};
549
550static 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
572static struct configfs_group_operations most_sound_group_ops = {
573 .make_group = most_sound_make_group,
574};
575
576static const struct config_item_type most_sound_type = {
577 .ct_group_ops = &most_sound_group_ops,
578 .ct_owner = THIS_MODULE,
579};
580
581static 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
592int 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}
613EXPORT_SYMBOL_GPL(most_register_configfs_subsys);
614
615void 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
631void 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}
642EXPORT_SYMBOL_GPL(most_deregister_configfs_subsys);
643
644int __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