Linux Audio

Check our new training course

Linux BSP upgrade and security maintenance

Need help to get security updates for your Linux BSP?
Loading...
Note: File does not exist in v6.8.
  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
 15struct 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
 34static struct list_head mdev_link_list;
 35
 36static 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
 42static 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
 48static 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
 54static 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
 60static 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
 66static int set_cfg_direction(struct mdev_link *link)
 67{
 68	return most_set_cfg_direction(link->device, link->channel,
 69				      link->direction);
 70}
 71
 72static int set_cfg_datatype(struct mdev_link *link)
 73{
 74	return most_set_cfg_datatype(link->device, link->channel,
 75				     link->datatype);
 76}
 77
 78static 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
 88static struct mdev_link *to_mdev_link(struct config_item *item)
 89{
 90	return container_of(item, struct mdev_link, item);
 91}
 92
 93static 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
111static 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
131static 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
153static 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
158static 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
170static 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
175static 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
188static 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
193static 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
202static 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
207static 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
216static 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
221static 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
230static 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
236static 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
245static 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
251static 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
263static 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
269static 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
281static 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
288static 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
300static 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
307static 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
319static 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
324static 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
336CONFIGFS_ATTR_WO(mdev_link_, create_link);
337CONFIGFS_ATTR_WO(mdev_link_, destroy_link);
338CONFIGFS_ATTR(mdev_link_, device);
339CONFIGFS_ATTR(mdev_link_, channel);
340CONFIGFS_ATTR(mdev_link_, comp);
341CONFIGFS_ATTR(mdev_link_, comp_params);
342CONFIGFS_ATTR(mdev_link_, num_buffers);
343CONFIGFS_ATTR(mdev_link_, buffer_size);
344CONFIGFS_ATTR(mdev_link_, subbuffer_size);
345CONFIGFS_ATTR(mdev_link_, packets_per_xact);
346CONFIGFS_ATTR(mdev_link_, datatype);
347CONFIGFS_ATTR(mdev_link_, direction);
348CONFIGFS_ATTR(mdev_link_, dbr_size);
349
350static 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
367static 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
382static struct configfs_item_operations mdev_link_item_ops = {
383	.release		= mdev_link_release,
384};
385
386static 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
392struct most_common {
393	struct config_group group;
394};
395
396static 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
401static 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
423static void most_common_release(struct config_item *item)
424{
425	kfree(to_most_common(item));
426}
427
428static struct configfs_item_operations most_common_item_ops = {
429	.release	= most_common_release,
430};
431
432static struct configfs_group_operations most_common_group_ops = {
433	.make_item	= most_common_make_item,
434};
435
436static 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
442static 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
451static 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
460static 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
469struct most_snd_grp {
470	struct config_group group;
471	bool create_card;
472	struct list_head list;
473};
474
475static 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
480static 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
496static 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
515CONFIGFS_ATTR_WO(most_snd_grp_, create_card);
516
517static struct configfs_attribute *most_snd_grp_attrs[] = {
518	&most_snd_grp_attr_create_card,
519	NULL,
520};
521
522static 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
530static struct configfs_item_operations most_snd_grp_item_ops = {
531	.release	= most_snd_grp_release,
532};
533
534static struct configfs_group_operations most_snd_grp_group_ops = {
535	.make_item	= most_snd_grp_make_item,
536};
537
538static 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
545struct most_sound {
546	struct configfs_subsystem subsys;
547	struct list_head soundcard_list;
548};
549
550static 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
572static struct configfs_group_operations most_sound_group_ops = {
573	.make_group	= most_sound_make_group,
574};
575
576static const struct config_item_type most_sound_type = {
577	.ct_group_ops	= &most_sound_group_ops,
578	.ct_owner	= THIS_MODULE,
579};
580
581static 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
592int 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}
613EXPORT_SYMBOL_GPL(most_register_configfs_subsys);
614
615void 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
631void 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}
642EXPORT_SYMBOL_GPL(most_deregister_configfs_subsys);
643
644int __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}