]> asedeno.scripts.mit.edu Git - linux.git/blob - drivers/staging/most/configfs.c
Merge branch 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[linux.git] / drivers / staging / most / configfs.c
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
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
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
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
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
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
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
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
88 static struct mdev_link *to_mdev_link(struct config_item *item)
89 {
90         return container_of(item, struct mdev_link, item);
91 }
92
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
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
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
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
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         strim(mdev_link->direction);
168         return count;
169 }
170
171 static ssize_t mdev_link_datatype_show(struct config_item *item, char *page)
172 {
173         return snprintf(page, PAGE_SIZE, "%s\n", to_mdev_link(item)->datatype);
174 }
175
176 static ssize_t mdev_link_datatype_store(struct config_item *item,
177                                         const char *page, size_t count)
178 {
179         struct mdev_link *mdev_link = to_mdev_link(item);
180
181         if (!sysfs_streq(page, "control") && !sysfs_streq(page, "async") &&
182             !sysfs_streq(page, "sync") && !sysfs_streq(page, "isoc") &&
183             !sysfs_streq(page, "isoc_avp"))
184                 return -EINVAL;
185         strcpy(mdev_link->datatype, page);
186         strim(mdev_link->datatype);
187         return count;
188 }
189
190 static ssize_t mdev_link_device_show(struct config_item *item, char *page)
191 {
192         return snprintf(page, PAGE_SIZE, "%s\n", to_mdev_link(item)->device);
193 }
194
195 static ssize_t mdev_link_device_store(struct config_item *item,
196                                       const char *page, size_t count)
197 {
198         struct mdev_link *mdev_link = to_mdev_link(item);
199
200         strcpy(mdev_link->device, page);
201         strim(mdev_link->device);
202         return count;
203 }
204
205 static ssize_t mdev_link_channel_show(struct config_item *item, char *page)
206 {
207         return snprintf(page, PAGE_SIZE, "%s\n", to_mdev_link(item)->channel);
208 }
209
210 static ssize_t mdev_link_channel_store(struct config_item *item,
211                                        const char *page, size_t count)
212 {
213         struct mdev_link *mdev_link = to_mdev_link(item);
214
215         strcpy(mdev_link->channel, page);
216         strim(mdev_link->channel);
217         return count;
218 }
219
220 static ssize_t mdev_link_comp_show(struct config_item *item, char *page)
221 {
222         return snprintf(page, PAGE_SIZE, "%s\n", to_mdev_link(item)->comp);
223 }
224
225 static ssize_t mdev_link_comp_store(struct config_item *item,
226                                     const char *page, size_t count)
227 {
228         struct mdev_link *mdev_link = to_mdev_link(item);
229
230         strcpy(mdev_link->comp, page);
231         return count;
232 }
233
234 static ssize_t mdev_link_comp_params_show(struct config_item *item, char *page)
235 {
236         return snprintf(page, PAGE_SIZE, "%s\n",
237                         to_mdev_link(item)->comp_params);
238 }
239
240 static ssize_t mdev_link_comp_params_store(struct config_item *item,
241                                            const char *page, size_t count)
242 {
243         struct mdev_link *mdev_link = to_mdev_link(item);
244
245         strcpy(mdev_link->comp_params, page);
246         return count;
247 }
248
249 static ssize_t mdev_link_num_buffers_show(struct config_item *item, char *page)
250 {
251         return snprintf(page, PAGE_SIZE, "%d\n",
252                         to_mdev_link(item)->num_buffers);
253 }
254
255 static ssize_t mdev_link_num_buffers_store(struct config_item *item,
256                                            const char *page, size_t count)
257 {
258         struct mdev_link *mdev_link = to_mdev_link(item);
259         int ret;
260
261         ret = kstrtou16(page, 0, &mdev_link->num_buffers);
262         if (ret)
263                 return ret;
264         return count;
265 }
266
267 static ssize_t mdev_link_buffer_size_show(struct config_item *item, char *page)
268 {
269         return snprintf(page, PAGE_SIZE, "%d\n",
270                         to_mdev_link(item)->buffer_size);
271 }
272
273 static ssize_t mdev_link_buffer_size_store(struct config_item *item,
274                                            const char *page, size_t count)
275 {
276         struct mdev_link *mdev_link = to_mdev_link(item);
277         int ret;
278
279         ret = kstrtou16(page, 0, &mdev_link->buffer_size);
280         if (ret)
281                 return ret;
282         return count;
283 }
284
285 static ssize_t mdev_link_subbuffer_size_show(struct config_item *item,
286                                              char *page)
287 {
288         return snprintf(page, PAGE_SIZE, "%d\n",
289                         to_mdev_link(item)->subbuffer_size);
290 }
291
292 static ssize_t mdev_link_subbuffer_size_store(struct config_item *item,
293                                               const char *page, size_t count)
294 {
295         struct mdev_link *mdev_link = to_mdev_link(item);
296         int ret;
297
298         ret = kstrtou16(page, 0, &mdev_link->subbuffer_size);
299         if (ret)
300                 return ret;
301         return count;
302 }
303
304 static ssize_t mdev_link_packets_per_xact_show(struct config_item *item,
305                                                char *page)
306 {
307         return snprintf(page, PAGE_SIZE, "%d\n",
308                         to_mdev_link(item)->packets_per_xact);
309 }
310
311 static ssize_t mdev_link_packets_per_xact_store(struct config_item *item,
312                                                 const char *page, size_t count)
313 {
314         struct mdev_link *mdev_link = to_mdev_link(item);
315         int ret;
316
317         ret = kstrtou16(page, 0, &mdev_link->packets_per_xact);
318         if (ret)
319                 return ret;
320         return count;
321 }
322
323 static ssize_t mdev_link_dbr_size_show(struct config_item *item, char *page)
324 {
325         return snprintf(page, PAGE_SIZE, "%d\n", to_mdev_link(item)->dbr_size);
326 }
327
328 static ssize_t mdev_link_dbr_size_store(struct config_item *item,
329                                         const char *page, size_t count)
330 {
331         struct mdev_link *mdev_link = to_mdev_link(item);
332         int ret;
333
334         ret = kstrtou16(page, 0, &mdev_link->dbr_size);
335         if (ret)
336                 return ret;
337         return count;
338 }
339
340 CONFIGFS_ATTR_WO(mdev_link_, create_link);
341 CONFIGFS_ATTR_WO(mdev_link_, destroy_link);
342 CONFIGFS_ATTR(mdev_link_, device);
343 CONFIGFS_ATTR(mdev_link_, channel);
344 CONFIGFS_ATTR(mdev_link_, comp);
345 CONFIGFS_ATTR(mdev_link_, comp_params);
346 CONFIGFS_ATTR(mdev_link_, num_buffers);
347 CONFIGFS_ATTR(mdev_link_, buffer_size);
348 CONFIGFS_ATTR(mdev_link_, subbuffer_size);
349 CONFIGFS_ATTR(mdev_link_, packets_per_xact);
350 CONFIGFS_ATTR(mdev_link_, datatype);
351 CONFIGFS_ATTR(mdev_link_, direction);
352 CONFIGFS_ATTR(mdev_link_, dbr_size);
353
354 static struct configfs_attribute *mdev_link_attrs[] = {
355         &mdev_link_attr_create_link,
356         &mdev_link_attr_destroy_link,
357         &mdev_link_attr_device,
358         &mdev_link_attr_channel,
359         &mdev_link_attr_comp,
360         &mdev_link_attr_comp_params,
361         &mdev_link_attr_num_buffers,
362         &mdev_link_attr_buffer_size,
363         &mdev_link_attr_subbuffer_size,
364         &mdev_link_attr_packets_per_xact,
365         &mdev_link_attr_datatype,
366         &mdev_link_attr_direction,
367         &mdev_link_attr_dbr_size,
368         NULL,
369 };
370
371 static void mdev_link_release(struct config_item *item)
372 {
373         struct mdev_link *mdev_link = to_mdev_link(item);
374         int ret;
375
376         if (!list_empty(&mdev_link_list)) {
377                 ret = most_remove_link(mdev_link->device, mdev_link->channel,
378                                        mdev_link->comp);
379                 if (ret && (ret != -ENODEV))
380                         pr_err("Removing link failed.\n");
381                 list_del(&mdev_link->list);
382         }
383         kfree(to_mdev_link(item));
384 }
385
386 static struct configfs_item_operations mdev_link_item_ops = {
387         .release                = mdev_link_release,
388 };
389
390 static const struct config_item_type mdev_link_type = {
391         .ct_item_ops    = &mdev_link_item_ops,
392         .ct_attrs       = mdev_link_attrs,
393         .ct_owner       = THIS_MODULE,
394 };
395
396 struct most_common {
397         struct config_group group;
398         struct module *mod;
399         struct configfs_subsystem subsys;
400 };
401
402 static struct most_common *to_most_common(struct configfs_subsystem *subsys)
403 {
404         return container_of(subsys, struct most_common, subsys);
405 }
406
407 static struct config_item *most_common_make_item(struct config_group *group,
408                                                  const char *name)
409 {
410         struct mdev_link *mdev_link;
411         struct most_common *mc = to_most_common(group->cg_subsys);
412
413         mdev_link = kzalloc(sizeof(*mdev_link), GFP_KERNEL);
414         if (!mdev_link)
415                 return ERR_PTR(-ENOMEM);
416
417         if (!try_module_get(mc->mod)) {
418                 kfree(mdev_link);
419                 return ERR_PTR(-ENOLCK);
420         }
421         config_item_init_type_name(&mdev_link->item, name,
422                                    &mdev_link_type);
423
424         if (!strcmp(group->cg_item.ci_namebuf, "most_cdev"))
425                 strcpy(mdev_link->comp, "cdev");
426         else if (!strcmp(group->cg_item.ci_namebuf, "most_net"))
427                 strcpy(mdev_link->comp, "net");
428         else if (!strcmp(group->cg_item.ci_namebuf, "most_video"))
429                 strcpy(mdev_link->comp, "video");
430         strcpy(mdev_link->name, name);
431         return &mdev_link->item;
432 }
433
434 static void most_common_release(struct config_item *item)
435 {
436         struct config_group *group = to_config_group(item);
437
438         kfree(to_most_common(group->cg_subsys));
439 }
440
441 static struct configfs_item_operations most_common_item_ops = {
442         .release        = most_common_release,
443 };
444
445 static void most_common_disconnect(struct config_group *group,
446                                    struct config_item *item)
447 {
448         struct most_common *mc = to_most_common(group->cg_subsys);
449
450         module_put(mc->mod);
451 }
452
453 static struct configfs_group_operations most_common_group_ops = {
454         .make_item      = most_common_make_item,
455         .disconnect_notify = most_common_disconnect,
456 };
457
458 static const struct config_item_type most_common_type = {
459         .ct_item_ops    = &most_common_item_ops,
460         .ct_group_ops   = &most_common_group_ops,
461         .ct_owner       = THIS_MODULE,
462 };
463
464 static struct most_common most_cdev = {
465         .subsys = {
466                 .su_group = {
467                         .cg_item = {
468                                 .ci_namebuf = "most_cdev",
469                                 .ci_type = &most_common_type,
470                         },
471                 },
472         },
473 };
474
475 static struct most_common most_net = {
476         .subsys = {
477                 .su_group = {
478                         .cg_item = {
479                                 .ci_namebuf = "most_net",
480                                 .ci_type = &most_common_type,
481                         },
482                 },
483         },
484 };
485
486 static struct most_common most_video = {
487         .subsys = {
488                 .su_group = {
489                         .cg_item = {
490                                 .ci_namebuf = "most_video",
491                                 .ci_type = &most_common_type,
492                         },
493                 },
494         },
495 };
496
497 struct most_snd_grp {
498         struct config_group group;
499         bool create_card;
500         struct list_head list;
501 };
502
503 static struct most_snd_grp *to_most_snd_grp(struct config_item *item)
504 {
505         return container_of(to_config_group(item), struct most_snd_grp, group);
506 }
507
508 static struct config_item *most_snd_grp_make_item(struct config_group *group,
509                                                   const char *name)
510 {
511         struct mdev_link *mdev_link;
512
513         mdev_link = kzalloc(sizeof(*mdev_link), GFP_KERNEL);
514         if (!mdev_link)
515                 return ERR_PTR(-ENOMEM);
516
517         config_item_init_type_name(&mdev_link->item, name, &mdev_link_type);
518         mdev_link->create_link = false;
519         strcpy(mdev_link->name, name);
520         strcpy(mdev_link->comp, "sound");
521         return &mdev_link->item;
522 }
523
524 static ssize_t most_snd_grp_create_card_store(struct config_item *item,
525                                               const char *page, size_t count)
526 {
527         struct most_snd_grp *snd_grp = to_most_snd_grp(item);
528         int ret;
529         bool tmp;
530
531         ret = kstrtobool(page, &tmp);
532         if (ret)
533                 return ret;
534         if (tmp) {
535                 ret = most_cfg_complete("sound");
536                 if (ret)
537                         return ret;
538         }
539         snd_grp->create_card = tmp;
540         return count;
541 }
542
543 CONFIGFS_ATTR_WO(most_snd_grp_, create_card);
544
545 static struct configfs_attribute *most_snd_grp_attrs[] = {
546         &most_snd_grp_attr_create_card,
547         NULL,
548 };
549
550 static void most_snd_grp_release(struct config_item *item)
551 {
552         struct most_snd_grp *group = to_most_snd_grp(item);
553
554         list_del(&group->list);
555         kfree(group);
556 }
557
558 static struct configfs_item_operations most_snd_grp_item_ops = {
559         .release        = most_snd_grp_release,
560 };
561
562 static struct configfs_group_operations most_snd_grp_group_ops = {
563         .make_item      = most_snd_grp_make_item,
564 };
565
566 static const struct config_item_type most_snd_grp_type = {
567         .ct_item_ops    = &most_snd_grp_item_ops,
568         .ct_group_ops   = &most_snd_grp_group_ops,
569         .ct_attrs       = most_snd_grp_attrs,
570         .ct_owner       = THIS_MODULE,
571 };
572
573 struct most_sound {
574         struct configfs_subsystem subsys;
575         struct list_head soundcard_list;
576         struct module *mod;
577 };
578
579 static struct config_group *most_sound_make_group(struct config_group *group,
580                                                   const char *name)
581 {
582         struct most_snd_grp *most;
583         struct most_sound *ms = container_of(group->cg_subsys,
584                                              struct most_sound, subsys);
585
586         list_for_each_entry(most, &ms->soundcard_list, list) {
587                 if (!most->create_card) {
588                         pr_info("adapter configuration still in progress.\n");
589                         return ERR_PTR(-EPROTO);
590                 }
591         }
592         if (!try_module_get(ms->mod))
593                 return ERR_PTR(-ENOLCK);
594         most = kzalloc(sizeof(*most), GFP_KERNEL);
595         if (!most) {
596                 module_put(ms->mod);
597                 return ERR_PTR(-ENOMEM);
598         }
599         config_group_init_type_name(&most->group, name, &most_snd_grp_type);
600         list_add_tail(&most->list, &ms->soundcard_list);
601         return &most->group;
602 }
603
604 static void most_sound_disconnect(struct config_group *group,
605                                   struct config_item *item)
606 {
607         struct most_sound *ms = container_of(group->cg_subsys,
608                                              struct most_sound, subsys);
609         module_put(ms->mod);
610 }
611
612 static struct configfs_group_operations most_sound_group_ops = {
613         .make_group     = most_sound_make_group,
614         .disconnect_notify = most_sound_disconnect,
615 };
616
617 static const struct config_item_type most_sound_type = {
618         .ct_group_ops   = &most_sound_group_ops,
619         .ct_owner       = THIS_MODULE,
620 };
621
622 static struct most_sound most_sound_subsys = {
623         .subsys = {
624                 .su_group = {
625                         .cg_item = {
626                                 .ci_namebuf = "most_sound",
627                                 .ci_type = &most_sound_type,
628                         },
629                 },
630         },
631 };
632
633 int most_register_configfs_subsys(struct core_component *c)
634 {
635         int ret;
636
637         if (!strcmp(c->name, "cdev")) {
638                 most_cdev.mod = c->mod;
639                 ret = configfs_register_subsystem(&most_cdev.subsys);
640         } else if (!strcmp(c->name, "net")) {
641                 most_net.mod = c->mod;
642                 ret = configfs_register_subsystem(&most_net.subsys);
643         } else if (!strcmp(c->name, "video")) {
644                 most_video.mod = c->mod;
645                 ret = configfs_register_subsystem(&most_video.subsys);
646         } else if (!strcmp(c->name, "sound")) {
647                 most_sound_subsys.mod = c->mod;
648                 ret = configfs_register_subsystem(&most_sound_subsys.subsys);
649         } else {
650                 return -ENODEV;
651         }
652
653         if (ret) {
654                 pr_err("Error %d while registering subsystem %s\n",
655                        ret, c->name);
656         }
657         return ret;
658 }
659 EXPORT_SYMBOL_GPL(most_register_configfs_subsys);
660
661 void most_interface_register_notify(const char *mdev)
662 {
663         bool register_snd_card = false;
664         struct mdev_link *mdev_link;
665
666         list_for_each_entry(mdev_link, &mdev_link_list, list) {
667                 if (!strcmp(mdev_link->device, mdev)) {
668                         set_config_and_add_link(mdev_link);
669                         if (!strcmp(mdev_link->comp, "sound"))
670                                 register_snd_card = true;
671                 }
672         }
673         if (register_snd_card)
674                 most_cfg_complete("sound");
675 }
676
677 void most_deregister_configfs_subsys(struct core_component *c)
678 {
679         if (!strcmp(c->name, "cdev"))
680                 configfs_unregister_subsystem(&most_cdev.subsys);
681         else if (!strcmp(c->name, "net"))
682                 configfs_unregister_subsystem(&most_net.subsys);
683         else if (!strcmp(c->name, "video"))
684                 configfs_unregister_subsystem(&most_video.subsys);
685         else if (!strcmp(c->name, "sound"))
686                 configfs_unregister_subsystem(&most_sound_subsys.subsys);
687 }
688 EXPORT_SYMBOL_GPL(most_deregister_configfs_subsys);
689
690 int __init configfs_init(void)
691 {
692         config_group_init(&most_cdev.subsys.su_group);
693         mutex_init(&most_cdev.subsys.su_mutex);
694
695         config_group_init(&most_net.subsys.su_group);
696         mutex_init(&most_net.subsys.su_mutex);
697
698         config_group_init(&most_video.subsys.su_group);
699         mutex_init(&most_video.subsys.su_mutex);
700
701         config_group_init(&most_sound_subsys.subsys.su_group);
702         mutex_init(&most_sound_subsys.subsys.su_mutex);
703
704         INIT_LIST_HEAD(&most_sound_subsys.soundcard_list);
705         INIT_LIST_HEAD(&mdev_link_list);
706
707         return 0;
708 }