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 <most/core.h>
16 struct config_item item
;
17 struct list_head list
;
25 char datatype
[PAGE_SIZE
];
26 char direction
[PAGE_SIZE
];
28 char device
[PAGE_SIZE
];
29 char channel
[PAGE_SIZE
];
31 char comp_params
[PAGE_SIZE
];
34 static struct list_head mdev_link_list
;
36 static int set_cfg_buffer_size(struct mdev_link
*link
)
38 return most_set_cfg_buffer_size(link
->device
, link
->channel
,
42 static int set_cfg_subbuffer_size(struct mdev_link
*link
)
44 return most_set_cfg_subbuffer_size(link
->device
, link
->channel
,
45 link
->subbuffer_size
);
48 static int set_cfg_dbr_size(struct mdev_link
*link
)
50 return most_set_cfg_dbr_size(link
->device
, link
->channel
,
54 static int set_cfg_num_buffers(struct mdev_link
*link
)
56 return most_set_cfg_num_buffers(link
->device
, link
->channel
,
60 static int set_cfg_packets_xact(struct mdev_link
*link
)
62 return most_set_cfg_packets_xact(link
->device
, link
->channel
,
63 link
->packets_per_xact
);
66 static int set_cfg_direction(struct mdev_link
*link
)
68 return most_set_cfg_direction(link
->device
, link
->channel
,
72 static int set_cfg_datatype(struct mdev_link
*link
)
74 return most_set_cfg_datatype(link
->device
, link
->channel
,
78 static int (*set_config_val
[])(struct mdev_link
*link
) = {
80 set_cfg_subbuffer_size
,
88 static struct mdev_link
*to_mdev_link(struct config_item
*item
)
90 return container_of(item
, struct mdev_link
, item
);
93 static int set_config_and_add_link(struct mdev_link
*mdev_link
)
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");
106 return most_add_link(mdev_link
->device
, mdev_link
->channel
,
107 mdev_link
->comp
, mdev_link
->name
,
108 mdev_link
->comp_params
);
111 static ssize_t
mdev_link_create_link_store(struct config_item
*item
,
112 const char *page
, size_t count
)
114 struct mdev_link
*mdev_link
= to_mdev_link(item
);
118 ret
= kstrtobool(page
, &tmp
);
123 ret
= set_config_and_add_link(mdev_link
);
124 if (ret
&& ret
!= -ENODEV
)
126 list_add_tail(&mdev_link
->list
, &mdev_link_list
);
127 mdev_link
->create_link
= tmp
;
131 static ssize_t
mdev_link_destroy_link_store(struct config_item
*item
,
132 const char *page
, size_t count
)
134 struct mdev_link
*mdev_link
= to_mdev_link(item
);
138 ret
= kstrtobool(page
, &tmp
);
143 mdev_link
->destroy_link
= tmp
;
144 ret
= most_remove_link(mdev_link
->device
, mdev_link
->channel
,
148 if (!list_empty(&mdev_link_list
))
149 list_del(&mdev_link
->list
);
153 static ssize_t
mdev_link_direction_show(struct config_item
*item
, char *page
)
155 return snprintf(page
, PAGE_SIZE
, "%s\n", to_mdev_link(item
)->direction
);
158 static ssize_t
mdev_link_direction_store(struct config_item
*item
,
159 const char *page
, size_t count
)
161 struct mdev_link
*mdev_link
= to_mdev_link(item
);
163 if (!sysfs_streq(page
, "dir_rx") && !sysfs_streq(page
, "rx") &&
164 !sysfs_streq(page
, "dir_tx") && !sysfs_streq(page
, "tx"))
166 strcpy(mdev_link
->direction
, page
);
167 strim(mdev_link
->direction
);
171 static ssize_t
mdev_link_datatype_show(struct config_item
*item
, char *page
)
173 return snprintf(page
, PAGE_SIZE
, "%s\n", to_mdev_link(item
)->datatype
);
176 static ssize_t
mdev_link_datatype_store(struct config_item
*item
,
177 const char *page
, size_t count
)
179 struct mdev_link
*mdev_link
= to_mdev_link(item
);
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"))
185 strcpy(mdev_link
->datatype
, page
);
186 strim(mdev_link
->datatype
);
190 static ssize_t
mdev_link_device_show(struct config_item
*item
, char *page
)
192 return snprintf(page
, PAGE_SIZE
, "%s\n", to_mdev_link(item
)->device
);
195 static ssize_t
mdev_link_device_store(struct config_item
*item
,
196 const char *page
, size_t count
)
198 struct mdev_link
*mdev_link
= to_mdev_link(item
);
200 strcpy(mdev_link
->device
, page
);
201 strim(mdev_link
->device
);
205 static ssize_t
mdev_link_channel_show(struct config_item
*item
, char *page
)
207 return snprintf(page
, PAGE_SIZE
, "%s\n", to_mdev_link(item
)->channel
);
210 static ssize_t
mdev_link_channel_store(struct config_item
*item
,
211 const char *page
, size_t count
)
213 struct mdev_link
*mdev_link
= to_mdev_link(item
);
215 strcpy(mdev_link
->channel
, page
);
216 strim(mdev_link
->channel
);
220 static ssize_t
mdev_link_comp_show(struct config_item
*item
, char *page
)
222 return snprintf(page
, PAGE_SIZE
, "%s\n", to_mdev_link(item
)->comp
);
225 static ssize_t
mdev_link_comp_store(struct config_item
*item
,
226 const char *page
, size_t count
)
228 struct mdev_link
*mdev_link
= to_mdev_link(item
);
230 strcpy(mdev_link
->comp
, page
);
234 static ssize_t
mdev_link_comp_params_show(struct config_item
*item
, char *page
)
236 return snprintf(page
, PAGE_SIZE
, "%s\n",
237 to_mdev_link(item
)->comp_params
);
240 static ssize_t
mdev_link_comp_params_store(struct config_item
*item
,
241 const char *page
, size_t count
)
243 struct mdev_link
*mdev_link
= to_mdev_link(item
);
245 strcpy(mdev_link
->comp_params
, page
);
249 static ssize_t
mdev_link_num_buffers_show(struct config_item
*item
, char *page
)
251 return snprintf(page
, PAGE_SIZE
, "%d\n",
252 to_mdev_link(item
)->num_buffers
);
255 static ssize_t
mdev_link_num_buffers_store(struct config_item
*item
,
256 const char *page
, size_t count
)
258 struct mdev_link
*mdev_link
= to_mdev_link(item
);
261 ret
= kstrtou16(page
, 0, &mdev_link
->num_buffers
);
267 static ssize_t
mdev_link_buffer_size_show(struct config_item
*item
, char *page
)
269 return snprintf(page
, PAGE_SIZE
, "%d\n",
270 to_mdev_link(item
)->buffer_size
);
273 static ssize_t
mdev_link_buffer_size_store(struct config_item
*item
,
274 const char *page
, size_t count
)
276 struct mdev_link
*mdev_link
= to_mdev_link(item
);
279 ret
= kstrtou16(page
, 0, &mdev_link
->buffer_size
);
285 static ssize_t
mdev_link_subbuffer_size_show(struct config_item
*item
,
288 return snprintf(page
, PAGE_SIZE
, "%d\n",
289 to_mdev_link(item
)->subbuffer_size
);
292 static ssize_t
mdev_link_subbuffer_size_store(struct config_item
*item
,
293 const char *page
, size_t count
)
295 struct mdev_link
*mdev_link
= to_mdev_link(item
);
298 ret
= kstrtou16(page
, 0, &mdev_link
->subbuffer_size
);
304 static ssize_t
mdev_link_packets_per_xact_show(struct config_item
*item
,
307 return snprintf(page
, PAGE_SIZE
, "%d\n",
308 to_mdev_link(item
)->packets_per_xact
);
311 static ssize_t
mdev_link_packets_per_xact_store(struct config_item
*item
,
312 const char *page
, size_t count
)
314 struct mdev_link
*mdev_link
= to_mdev_link(item
);
317 ret
= kstrtou16(page
, 0, &mdev_link
->packets_per_xact
);
323 static ssize_t
mdev_link_dbr_size_show(struct config_item
*item
, char *page
)
325 return snprintf(page
, PAGE_SIZE
, "%d\n", to_mdev_link(item
)->dbr_size
);
328 static ssize_t
mdev_link_dbr_size_store(struct config_item
*item
,
329 const char *page
, size_t count
)
331 struct mdev_link
*mdev_link
= to_mdev_link(item
);
334 ret
= kstrtou16(page
, 0, &mdev_link
->dbr_size
);
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
);
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
,
371 static void mdev_link_release(struct config_item
*item
)
373 struct mdev_link
*mdev_link
= to_mdev_link(item
);
376 if (!list_empty(&mdev_link_list
)) {
377 ret
= most_remove_link(mdev_link
->device
, mdev_link
->channel
,
379 if (ret
&& (ret
!= -ENODEV
))
380 pr_err("Removing link failed.\n");
381 list_del(&mdev_link
->list
);
383 kfree(to_mdev_link(item
));
386 static struct configfs_item_operations mdev_link_item_ops
= {
387 .release
= mdev_link_release
,
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
,
397 struct config_group group
;
399 struct configfs_subsystem subsys
;
402 static struct most_common
*to_most_common(struct configfs_subsystem
*subsys
)
404 return container_of(subsys
, struct most_common
, subsys
);
407 static struct config_item
*most_common_make_item(struct config_group
*group
,
410 struct mdev_link
*mdev_link
;
411 struct most_common
*mc
= to_most_common(group
->cg_subsys
);
413 mdev_link
= kzalloc(sizeof(*mdev_link
), GFP_KERNEL
);
415 return ERR_PTR(-ENOMEM
);
417 if (!try_module_get(mc
->mod
)) {
419 return ERR_PTR(-ENOLCK
);
421 config_item_init_type_name(&mdev_link
->item
, name
,
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
;
434 static void most_common_release(struct config_item
*item
)
436 struct config_group
*group
= to_config_group(item
);
438 kfree(to_most_common(group
->cg_subsys
));
441 static struct configfs_item_operations most_common_item_ops
= {
442 .release
= most_common_release
,
445 static void most_common_disconnect(struct config_group
*group
,
446 struct config_item
*item
)
448 struct most_common
*mc
= to_most_common(group
->cg_subsys
);
453 static struct configfs_group_operations most_common_group_ops
= {
454 .make_item
= most_common_make_item
,
455 .disconnect_notify
= most_common_disconnect
,
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
,
464 static struct most_common most_cdev
= {
468 .ci_namebuf
= "most_cdev",
469 .ci_type
= &most_common_type
,
475 static struct most_common most_net
= {
479 .ci_namebuf
= "most_net",
480 .ci_type
= &most_common_type
,
486 static struct most_common most_video
= {
490 .ci_namebuf
= "most_video",
491 .ci_type
= &most_common_type
,
497 struct most_snd_grp
{
498 struct config_group group
;
500 struct list_head list
;
503 static struct most_snd_grp
*to_most_snd_grp(struct config_item
*item
)
505 return container_of(to_config_group(item
), struct most_snd_grp
, group
);
508 static struct config_item
*most_snd_grp_make_item(struct config_group
*group
,
511 struct mdev_link
*mdev_link
;
513 mdev_link
= kzalloc(sizeof(*mdev_link
), GFP_KERNEL
);
515 return ERR_PTR(-ENOMEM
);
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
;
524 static ssize_t
most_snd_grp_create_card_store(struct config_item
*item
,
525 const char *page
, size_t count
)
527 struct most_snd_grp
*snd_grp
= to_most_snd_grp(item
);
531 ret
= kstrtobool(page
, &tmp
);
535 ret
= most_cfg_complete("sound");
539 snd_grp
->create_card
= tmp
;
543 CONFIGFS_ATTR_WO(most_snd_grp_
, create_card
);
545 static struct configfs_attribute
*most_snd_grp_attrs
[] = {
546 &most_snd_grp_attr_create_card
,
550 static void most_snd_grp_release(struct config_item
*item
)
552 struct most_snd_grp
*group
= to_most_snd_grp(item
);
554 list_del(&group
->list
);
558 static struct configfs_item_operations most_snd_grp_item_ops
= {
559 .release
= most_snd_grp_release
,
562 static struct configfs_group_operations most_snd_grp_group_ops
= {
563 .make_item
= most_snd_grp_make_item
,
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
,
574 struct configfs_subsystem subsys
;
575 struct list_head soundcard_list
;
579 static struct config_group
*most_sound_make_group(struct config_group
*group
,
582 struct most_snd_grp
*most
;
583 struct most_sound
*ms
= container_of(group
->cg_subsys
,
584 struct most_sound
, subsys
);
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
);
592 if (!try_module_get(ms
->mod
))
593 return ERR_PTR(-ENOLCK
);
594 most
= kzalloc(sizeof(*most
), GFP_KERNEL
);
597 return ERR_PTR(-ENOMEM
);
599 config_group_init_type_name(&most
->group
, name
, &most_snd_grp_type
);
600 list_add_tail(&most
->list
, &ms
->soundcard_list
);
604 static void most_sound_disconnect(struct config_group
*group
,
605 struct config_item
*item
)
607 struct most_sound
*ms
= container_of(group
->cg_subsys
,
608 struct most_sound
, subsys
);
612 static struct configfs_group_operations most_sound_group_ops
= {
613 .make_group
= most_sound_make_group
,
614 .disconnect_notify
= most_sound_disconnect
,
617 static const struct config_item_type most_sound_type
= {
618 .ct_group_ops
= &most_sound_group_ops
,
619 .ct_owner
= THIS_MODULE
,
622 static struct most_sound most_sound_subsys
= {
626 .ci_namebuf
= "most_sound",
627 .ci_type
= &most_sound_type
,
633 int most_register_configfs_subsys(struct core_component
*c
)
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
);
654 pr_err("Error %d while registering subsystem %s\n",
659 EXPORT_SYMBOL_GPL(most_register_configfs_subsys
);
661 void most_interface_register_notify(const char *mdev
)
663 bool register_snd_card
= false;
664 struct mdev_link
*mdev_link
;
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;
673 if (register_snd_card
)
674 most_cfg_complete("sound");
677 void most_deregister_configfs_subsys(struct core_component
*c
)
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
);
688 EXPORT_SYMBOL_GPL(most_deregister_configfs_subsys
);
690 int __init
configfs_init(void)
692 config_group_init(&most_cdev
.subsys
.su_group
);
693 mutex_init(&most_cdev
.subsys
.su_mutex
);
695 config_group_init(&most_net
.subsys
.su_group
);
696 mutex_init(&most_net
.subsys
.su_mutex
);
698 config_group_init(&most_video
.subsys
.su_group
);
699 mutex_init(&most_video
.subsys
.su_mutex
);
701 config_group_init(&most_sound_subsys
.subsys
.su_group
);
702 mutex_init(&most_sound_subsys
.subsys
.su_mutex
);
704 INIT_LIST_HEAD(&most_sound_subsys
.soundcard_list
);
705 INIT_LIST_HEAD(&mdev_link_list
);