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