1 // SPDX-License-Identifier: GPL-2.0
3 * configfs.c - Implementation of configfs interface to the driver stack
5 * Copyright (C) 2013-2015 Microchip Technology Germany II GmbH & Co. KG
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>
15 #define MAX_STRING_SIZE 80
18 struct config_item item
;
19 struct list_head list
;
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
];
36 static struct list_head mdev_link_list
;
38 static int set_cfg_buffer_size(struct mdev_link
*link
)
40 return most_set_cfg_buffer_size(link
->device
, link
->channel
,
44 static int set_cfg_subbuffer_size(struct mdev_link
*link
)
46 return most_set_cfg_subbuffer_size(link
->device
, link
->channel
,
47 link
->subbuffer_size
);
50 static int set_cfg_dbr_size(struct mdev_link
*link
)
52 return most_set_cfg_dbr_size(link
->device
, link
->channel
,
56 static int set_cfg_num_buffers(struct mdev_link
*link
)
58 return most_set_cfg_num_buffers(link
->device
, link
->channel
,
62 static int set_cfg_packets_xact(struct mdev_link
*link
)
64 return most_set_cfg_packets_xact(link
->device
, link
->channel
,
65 link
->packets_per_xact
);
68 static int set_cfg_direction(struct mdev_link
*link
)
70 return most_set_cfg_direction(link
->device
, link
->channel
,
74 static int set_cfg_datatype(struct mdev_link
*link
)
76 return most_set_cfg_datatype(link
->device
, link
->channel
,
80 static int (*set_config_val
[])(struct mdev_link
*link
) = {
82 set_cfg_subbuffer_size
,
90 static struct mdev_link
*to_mdev_link(struct config_item
*item
)
92 return container_of(item
, struct mdev_link
, item
);
95 static int set_config_and_add_link(struct mdev_link
*mdev_link
)
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");
108 return most_add_link(mdev_link
->device
, mdev_link
->channel
,
109 mdev_link
->comp
, mdev_link
->name
,
110 mdev_link
->comp_params
);
113 static ssize_t
mdev_link_create_link_store(struct config_item
*item
,
114 const char *page
, size_t count
)
116 struct mdev_link
*mdev_link
= to_mdev_link(item
);
120 ret
= kstrtobool(page
, &tmp
);
125 ret
= set_config_and_add_link(mdev_link
);
126 if (ret
&& ret
!= -ENODEV
)
128 list_add_tail(&mdev_link
->list
, &mdev_link_list
);
129 mdev_link
->create_link
= tmp
;
130 mdev_link
->destroy_link
= false;
135 static ssize_t
mdev_link_destroy_link_store(struct config_item
*item
,
136 const char *page
, size_t count
)
138 struct mdev_link
*mdev_link
= to_mdev_link(item
);
142 ret
= kstrtobool(page
, &tmp
);
148 ret
= most_remove_link(mdev_link
->device
, mdev_link
->channel
,
152 if (!list_empty(&mdev_link_list
))
153 list_del(&mdev_link
->list
);
155 mdev_link
->destroy_link
= tmp
;
160 static ssize_t
mdev_link_direction_show(struct config_item
*item
, char *page
)
162 return snprintf(page
, PAGE_SIZE
, "%s\n", to_mdev_link(item
)->direction
);
165 static ssize_t
mdev_link_direction_store(struct config_item
*item
,
166 const char *page
, size_t count
)
168 struct mdev_link
*mdev_link
= to_mdev_link(item
);
170 if (!sysfs_streq(page
, "dir_rx") && !sysfs_streq(page
, "rx") &&
171 !sysfs_streq(page
, "dir_tx") && !sysfs_streq(page
, "tx"))
173 strcpy(mdev_link
->direction
, page
);
174 strim(mdev_link
->direction
);
178 static ssize_t
mdev_link_datatype_show(struct config_item
*item
, char *page
)
180 return snprintf(page
, PAGE_SIZE
, "%s\n", to_mdev_link(item
)->datatype
);
183 static ssize_t
mdev_link_datatype_store(struct config_item
*item
,
184 const char *page
, size_t count
)
186 struct mdev_link
*mdev_link
= to_mdev_link(item
);
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"))
192 strcpy(mdev_link
->datatype
, page
);
193 strim(mdev_link
->datatype
);
197 static ssize_t
mdev_link_device_show(struct config_item
*item
, char *page
)
199 return snprintf(page
, PAGE_SIZE
, "%s\n", to_mdev_link(item
)->device
);
202 static ssize_t
mdev_link_device_store(struct config_item
*item
,
203 const char *page
, size_t count
)
205 struct mdev_link
*mdev_link
= to_mdev_link(item
);
207 strscpy(mdev_link
->device
, page
, sizeof(mdev_link
->device
));
208 strim(mdev_link
->device
);
212 static ssize_t
mdev_link_channel_show(struct config_item
*item
, char *page
)
214 return snprintf(page
, PAGE_SIZE
, "%s\n", to_mdev_link(item
)->channel
);
217 static ssize_t
mdev_link_channel_store(struct config_item
*item
,
218 const char *page
, size_t count
)
220 struct mdev_link
*mdev_link
= to_mdev_link(item
);
222 strscpy(mdev_link
->channel
, page
, sizeof(mdev_link
->channel
));
223 strim(mdev_link
->channel
);
227 static ssize_t
mdev_link_comp_show(struct config_item
*item
, char *page
)
229 return snprintf(page
, PAGE_SIZE
, "%s\n", to_mdev_link(item
)->comp
);
232 static ssize_t
mdev_link_comp_store(struct config_item
*item
,
233 const char *page
, size_t count
)
235 struct mdev_link
*mdev_link
= to_mdev_link(item
);
237 strscpy(mdev_link
->comp
, page
, sizeof(mdev_link
->comp
));
238 strim(mdev_link
->comp
);
242 static ssize_t
mdev_link_comp_params_show(struct config_item
*item
, char *page
)
244 return snprintf(page
, PAGE_SIZE
, "%s\n",
245 to_mdev_link(item
)->comp_params
);
248 static ssize_t
mdev_link_comp_params_store(struct config_item
*item
,
249 const char *page
, size_t count
)
251 struct mdev_link
*mdev_link
= to_mdev_link(item
);
253 strscpy(mdev_link
->comp_params
, page
, sizeof(mdev_link
->comp_params
));
254 strim(mdev_link
->comp_params
);
258 static ssize_t
mdev_link_num_buffers_show(struct config_item
*item
, char *page
)
260 return snprintf(page
, PAGE_SIZE
, "%d\n",
261 to_mdev_link(item
)->num_buffers
);
264 static ssize_t
mdev_link_num_buffers_store(struct config_item
*item
,
265 const char *page
, size_t count
)
267 struct mdev_link
*mdev_link
= to_mdev_link(item
);
270 ret
= kstrtou16(page
, 0, &mdev_link
->num_buffers
);
276 static ssize_t
mdev_link_buffer_size_show(struct config_item
*item
, char *page
)
278 return snprintf(page
, PAGE_SIZE
, "%d\n",
279 to_mdev_link(item
)->buffer_size
);
282 static ssize_t
mdev_link_buffer_size_store(struct config_item
*item
,
283 const char *page
, size_t count
)
285 struct mdev_link
*mdev_link
= to_mdev_link(item
);
288 ret
= kstrtou16(page
, 0, &mdev_link
->buffer_size
);
294 static ssize_t
mdev_link_subbuffer_size_show(struct config_item
*item
,
297 return snprintf(page
, PAGE_SIZE
, "%d\n",
298 to_mdev_link(item
)->subbuffer_size
);
301 static ssize_t
mdev_link_subbuffer_size_store(struct config_item
*item
,
302 const char *page
, size_t count
)
304 struct mdev_link
*mdev_link
= to_mdev_link(item
);
307 ret
= kstrtou16(page
, 0, &mdev_link
->subbuffer_size
);
313 static ssize_t
mdev_link_packets_per_xact_show(struct config_item
*item
,
316 return snprintf(page
, PAGE_SIZE
, "%d\n",
317 to_mdev_link(item
)->packets_per_xact
);
320 static ssize_t
mdev_link_packets_per_xact_store(struct config_item
*item
,
321 const char *page
, size_t count
)
323 struct mdev_link
*mdev_link
= to_mdev_link(item
);
326 ret
= kstrtou16(page
, 0, &mdev_link
->packets_per_xact
);
332 static ssize_t
mdev_link_dbr_size_show(struct config_item
*item
, char *page
)
334 return snprintf(page
, PAGE_SIZE
, "%d\n", to_mdev_link(item
)->dbr_size
);
337 static ssize_t
mdev_link_dbr_size_store(struct config_item
*item
,
338 const char *page
, size_t count
)
340 struct mdev_link
*mdev_link
= to_mdev_link(item
);
343 ret
= kstrtou16(page
, 0, &mdev_link
->dbr_size
);
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
);
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
,
380 static void mdev_link_release(struct config_item
*item
)
382 struct mdev_link
*mdev_link
= to_mdev_link(item
);
385 if (mdev_link
->destroy_link
)
388 ret
= most_remove_link(mdev_link
->device
, mdev_link
->channel
,
391 pr_err("Removing link failed.\n");
395 if (!list_empty(&mdev_link_list
))
396 list_del(&mdev_link
->list
);
399 kfree(to_mdev_link(item
));
402 static struct configfs_item_operations mdev_link_item_ops
= {
403 .release
= mdev_link_release
,
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
,
413 struct config_group group
;
415 struct configfs_subsystem subsys
;
418 static struct most_common
*to_most_common(struct configfs_subsystem
*subsys
)
420 return container_of(subsys
, struct most_common
, subsys
);
423 static struct config_item
*most_common_make_item(struct config_group
*group
,
426 struct mdev_link
*mdev_link
;
427 struct most_common
*mc
= to_most_common(group
->cg_subsys
);
429 mdev_link
= kzalloc(sizeof(*mdev_link
), GFP_KERNEL
);
431 return ERR_PTR(-ENOMEM
);
433 if (!try_module_get(mc
->mod
)) {
435 return ERR_PTR(-ENOLCK
);
437 config_item_init_type_name(&mdev_link
->item
, name
,
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
;
450 static void most_common_release(struct config_item
*item
)
452 struct config_group
*group
= to_config_group(item
);
454 kfree(to_most_common(group
->cg_subsys
));
457 static struct configfs_item_operations most_common_item_ops
= {
458 .release
= most_common_release
,
461 static void most_common_disconnect(struct config_group
*group
,
462 struct config_item
*item
)
464 struct most_common
*mc
= to_most_common(group
->cg_subsys
);
469 static struct configfs_group_operations most_common_group_ops
= {
470 .make_item
= most_common_make_item
,
471 .disconnect_notify
= most_common_disconnect
,
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
,
480 static struct most_common most_cdev
= {
484 .ci_namebuf
= "most_cdev",
485 .ci_type
= &most_common_type
,
491 static struct most_common most_net
= {
495 .ci_namebuf
= "most_net",
496 .ci_type
= &most_common_type
,
502 static struct most_common most_video
= {
506 .ci_namebuf
= "most_video",
507 .ci_type
= &most_common_type
,
513 struct most_snd_grp
{
514 struct config_group group
;
516 struct list_head list
;
519 static struct most_snd_grp
*to_most_snd_grp(struct config_item
*item
)
521 return container_of(to_config_group(item
), struct most_snd_grp
, group
);
524 static struct config_item
*most_snd_grp_make_item(struct config_group
*group
,
527 struct mdev_link
*mdev_link
;
529 mdev_link
= kzalloc(sizeof(*mdev_link
), GFP_KERNEL
);
531 return ERR_PTR(-ENOMEM
);
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
;
540 static ssize_t
most_snd_grp_create_card_store(struct config_item
*item
,
541 const char *page
, size_t count
)
543 struct most_snd_grp
*snd_grp
= to_most_snd_grp(item
);
547 ret
= kstrtobool(page
, &tmp
);
551 ret
= most_cfg_complete("sound");
555 snd_grp
->create_card
= tmp
;
559 CONFIGFS_ATTR_WO(most_snd_grp_
, create_card
);
561 static struct configfs_attribute
*most_snd_grp_attrs
[] = {
562 &most_snd_grp_attr_create_card
,
566 static void most_snd_grp_release(struct config_item
*item
)
568 struct most_snd_grp
*group
= to_most_snd_grp(item
);
570 list_del(&group
->list
);
574 static struct configfs_item_operations most_snd_grp_item_ops
= {
575 .release
= most_snd_grp_release
,
578 static struct configfs_group_operations most_snd_grp_group_ops
= {
579 .make_item
= most_snd_grp_make_item
,
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
,
590 struct configfs_subsystem subsys
;
591 struct list_head soundcard_list
;
595 static struct config_group
*most_sound_make_group(struct config_group
*group
,
598 struct most_snd_grp
*most
;
599 struct most_sound
*ms
= container_of(group
->cg_subsys
,
600 struct most_sound
, subsys
);
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
);
608 if (!try_module_get(ms
->mod
))
609 return ERR_PTR(-ENOLCK
);
610 most
= kzalloc(sizeof(*most
), GFP_KERNEL
);
613 return ERR_PTR(-ENOMEM
);
615 config_group_init_type_name(&most
->group
, name
, &most_snd_grp_type
);
616 list_add_tail(&most
->list
, &ms
->soundcard_list
);
620 static void most_sound_disconnect(struct config_group
*group
,
621 struct config_item
*item
)
623 struct most_sound
*ms
= container_of(group
->cg_subsys
,
624 struct most_sound
, subsys
);
628 static struct configfs_group_operations most_sound_group_ops
= {
629 .make_group
= most_sound_make_group
,
630 .disconnect_notify
= most_sound_disconnect
,
633 static const struct config_item_type most_sound_type
= {
634 .ct_group_ops
= &most_sound_group_ops
,
635 .ct_owner
= THIS_MODULE
,
638 static struct most_sound most_sound_subsys
= {
642 .ci_namebuf
= "most_sound",
643 .ci_type
= &most_sound_type
,
649 int most_register_configfs_subsys(struct most_component
*c
)
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
);
670 pr_err("Error %d while registering subsystem %s\n",
675 EXPORT_SYMBOL_GPL(most_register_configfs_subsys
);
677 void most_interface_register_notify(const char *mdev
)
679 bool register_snd_card
= false;
680 struct mdev_link
*mdev_link
;
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;
689 if (register_snd_card
)
690 most_cfg_complete("sound");
693 void most_deregister_configfs_subsys(struct most_component
*c
)
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
);
704 EXPORT_SYMBOL_GPL(most_deregister_configfs_subsys
);
706 int __init
configfs_init(void)
708 config_group_init(&most_cdev
.subsys
.su_group
);
709 mutex_init(&most_cdev
.subsys
.su_mutex
);
711 config_group_init(&most_net
.subsys
.su_group
);
712 mutex_init(&most_net
.subsys
.su_mutex
);
714 config_group_init(&most_video
.subsys
.su_group
);
715 mutex_init(&most_video
.subsys
.su_mutex
);
717 config_group_init(&most_sound_subsys
.subsys
.su_group
);
718 mutex_init(&most_sound_subsys
.subsys
.su_mutex
);
720 INIT_LIST_HEAD(&most_sound_subsys
.soundcard_list
);
721 INIT_LIST_HEAD(&mdev_link_list
);