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