Linux-libre 5.3.12-gnu
[librecmc/linux-libre.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         return count;
168 }
169
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 }