dd811c81bdcddb73df94607ad527f37197025834
[AGL/meta-agl-demo.git] / recipes-kernel / most / files / 0002-src-most-add-auto-conf-feature.patch
1 From 9cb7cb85f59509ac445116e9458c502cf6cb74e6 Mon Sep 17 00:00:00 2001
2 From: Christian Gromm <christian.gromm@microchip.com>
3 Date: Thu, 9 Nov 2017 13:20:23 +0100
4 Subject: [PATCH 2/2] src: most: add auto conf feature
5
6 This patch adds the auto configuration feature to the driver
7 sources. It is needed to have the driver configured automatically
8 upon start up w/o the need for userspace to set up sysfs.
9
10 Signed-off-by: Christian Gromm <christian.gromm@microchip.com>
11 ---
12  driver/Makefile           |   3 +
13  driver/default_conf.c     | 162 ++++++++++++++++++++++++++++++++++++++++++++++
14  driver/include/mostcore.h |  64 ++++++++++++++++++
15  driver/mostcore/core.c    | 120 ++++++++++++++++++++++++++++------
16  4 files changed, 331 insertions(+), 18 deletions(-)
17  create mode 100644 driver/default_conf.c
18
19 diff --git a/Makefile b/Makefile
20 index e77a4b6..6d74ebe 100644
21 --- a/Makefile
22 +++ b/Makefile
23 @@ -6,6 +6,9 @@ obj-m := mostcore.o
24  mostcore-y := mostcore/core.o
25  CFLAGS_core.o := -I$(src)/include/
26  
27 +obj-m += default_conf.o
28 +CFLAGL_default_conf.o := -I$(src)/include
29 +
30  obj-m += aim_cdev.o
31  aim_cdev-y := aim-cdev/cdev.o
32  CFLAGS_cdev.o := -I$(src)/include/
33 diff --git a/default_conf.c b/default_conf.c
34 new file mode 100644
35 index 0000000..adb1786
36 --- /dev/null
37 +++ b/default_conf.c
38 @@ -0,0 +1,162 @@
39 +/*
40 + * default_conf.c - Default configuration for the MOST channels.
41 + *
42 + * Copyright (C) 2017, Microchip Technology Germany II GmbH & Co. KG
43 + *
44 + * This program is distributed in the hope that it will be useful,
45 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
46 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
47 + * GNU General Public License for more details.
48 + *
49 + * This file is licensed under GPLv2.
50 + */
51 +
52 +#include "include/mostcore.h"
53 +#include <linux/module.h>
54 +
55 +static struct most_config_probe config_probes[] = {
56 +
57 +       /* OS81118 Control */
58 +       {
59 +               .ch_name = "ep8f",
60 +               .cfg = {
61 +                       .direction = MOST_CH_RX,
62 +                       .data_type = MOST_CH_CONTROL,
63 +                       .num_buffers = 16,
64 +                       .buffer_size = 64,
65 +               },
66 +               .aim_name = "cdev",
67 +               .aim_param = "inic-usb-crx",
68 +       },
69 +       {
70 +               .ch_name = "ep0f",
71 +               .cfg = {
72 +                       .direction = MOST_CH_TX,
73 +                       .data_type = MOST_CH_CONTROL,
74 +                       .num_buffers = 16,
75 +                       .buffer_size = 64,
76 +               },
77 +               .aim_name = "cdev",
78 +               .aim_param = "inic-usb-ctx",
79 +       },
80 +       /* OS81118 Async */
81 +       {
82 +               .ch_name = "ep8e",
83 +               .cfg = {
84 +                       .direction = MOST_CH_RX,
85 +                       .data_type = MOST_CH_ASYNC,
86 +                       .num_buffers = 20,
87 +                       .buffer_size = 1522,
88 +               },
89 +               .aim_name = "networking",
90 +               .aim_param = "inic-usb-arx",
91 +       },
92 +       {
93 +               .ch_name = "ep0e",
94 +               .cfg = {
95 +                       .direction = MOST_CH_TX,
96 +                       .data_type = MOST_CH_ASYNC,
97 +                       .num_buffers = 20,
98 +                       .buffer_size = 1522,
99 +               },
100 +               .aim_name = "networking",
101 +               .aim_param = "inic-usb-atx",
102 +       },
103 +       /* OS81210 Control */
104 +       {
105 +               .ch_name = "ep87",
106 +               .cfg = {
107 +                       .direction = MOST_CH_RX,
108 +                       .data_type = MOST_CH_CONTROL,
109 +                       .num_buffers = 16,
110 +                       .buffer_size = 64,
111 +               },
112 +               .aim_name = "cdev",
113 +               .aim_param = "inic-usb-crx",
114 +       },
115 +       {
116 +               .ch_name = "ep07",
117 +               .cfg = {
118 +                       .direction = MOST_CH_TX,
119 +                       .data_type = MOST_CH_CONTROL,
120 +                       .num_buffers = 16,
121 +                       .buffer_size = 64,
122 +               },
123 +               .aim_name = "cdev",
124 +               .aim_param = "inic-usb-ctx",
125 +       },
126 +       /* OS81210 Async */
127 +       {
128 +               .ch_name = "ep86",
129 +               .cfg = {
130 +                       .direction = MOST_CH_RX,
131 +                       .data_type = MOST_CH_ASYNC,
132 +                       .num_buffers = 20,
133 +                       .buffer_size = 1522,
134 +               },
135 +               .aim_name = "networking",
136 +               .aim_param = "inic-usb-arx",
137 +       },
138 +       {
139 +               .ch_name = "ep06",
140 +               .cfg = {
141 +                       .direction = MOST_CH_TX,
142 +                       .data_type = MOST_CH_ASYNC,
143 +                       .num_buffers = 20,
144 +                       .buffer_size = 1522,
145 +               },
146 +               .aim_name = "networking",
147 +               .aim_param = "inic-usb-atx",
148 +       },
149 +       /* Streaming channels (common for all INICs) */
150 +       {
151 +               .ch_name = "ep01",
152 +               .cfg = {
153 +                       .direction = MOST_CH_TX,
154 +                       .data_type = MOST_CH_SYNC,
155 +                       .num_buffers = 8,
156 +                       .buffer_size = 2 * 12 * 42,
157 +                       .subbuffer_size = 12,
158 +                       .packets_per_xact = 42,
159 +               },
160 +               .aim_name = "sound",
161 +               .aim_param = "ep01-6ch.6x16",
162 +       },
163 +       {
164 +               .ch_name = "ep02",
165 +               .cfg = {
166 +                       .direction = MOST_CH_TX,
167 +                       .data_type = MOST_CH_ISOC,
168 +                       .num_buffers = 8,
169 +                       .buffer_size = 40 * 188,
170 +                       .subbuffer_size = 188,
171 +                       .packets_per_xact = 2,
172 +               },
173 +               .aim_name = "cdev",
174 +               .aim_param = "inic-usb-itx1",
175 +       },
176 +       
177 +       /* sentinel */
178 +       {}
179 +};
180 +
181 +static struct most_config_set config_set = {
182 +       .probes = config_probes
183 +};
184 +
185 +static int __init mod_init(void)
186 +{
187 +       most_register_config_set(&config_set);
188 +       return 0;
189 +}
190 +
191 +static void __exit mod_exit(void)
192 +{
193 +       most_deregister_config_set(&config_set);
194 +}
195 +
196 +module_init(mod_init);
197 +module_exit(mod_exit);
198 +MODULE_LICENSE("GPL");
199 +MODULE_AUTHOR("Andrey Shvetsov <andrey.shvetsov@k2l.de>");
200 +MODULE_DESCRIPTION("Default configuration for the MOST channels");
201 diff --git a/include/mostcore.h b/include/mostcore.h
202 index dc87121..3c00efb 100644
203 --- a/include/mostcore.h
204 +++ b/include/mostcore.h
205 @@ -145,6 +145,39 @@ struct most_channel_config {
206         u16 dbr_size;
207  };
208  
209 +/**
210 + * struct most_config_probe - matching rule, channel configuration and
211 + *     the optional AIM name used for the automatic configuration and linking
212 + *     of the channel
213 + * @dev_name: optional matching device id
214 + *     ("usb_device 1-1:1.0," "dim2-12345678", etc.)
215 + * @ch_name: matching channel name ("ep8f", "ca2", etc.)
216 + * @cfg: configuration that will be applied for the found channel
217 + * @aim_name: optional name of the AIM that will be linked to the channel
218 + *     ("cdev", "networking", "v4l", "sound")
219 + * @aim_param: AIM dependent parameter (it is the character device name
220 + *     for the cdev AIM, PCM format for the audio AIM, etc.)
221 + */
222 +struct most_config_probe {
223 +       const char *dev_name;
224 +       const char *ch_name;
225 +       struct most_channel_config cfg;
226 +       const char *aim_name;
227 +       const char *aim_param;
228 +};
229 +
230 +/**
231 + * struct most_config_set - the configuration set containing
232 + *     several automatic configurations for the different channels
233 + * @probes: list of the matching rules and the configurations,
234 + *     that must be ended with the empty structure
235 + * @list: list head used by the MostCore
236 + */
237 +struct most_config_set {
238 +       const struct most_config_probe *probes;
239 +       struct list_head list;
240 +};
241 +
242  /*
243   * struct mbo - MOST Buffer Object.
244   * @context: context for core completion handler
245 @@ -285,6 +318,37 @@ struct most_aim {
246  };
247  
248  /**
249 + * most_register_config_set - registers the configuration set
250 + *
251 + * @cfg_set: configuration set to be registered for the future probes
252 + *
253 + * The function registers the given configuration set.
254 + *
255 + * It is possible to register or deregister several configuration sets
256 + * independently.  Different configuration sets may contain the
257 + * overlapped matching rules but later registered configuration set has
258 + * the higher priority over the prior registered set.
259 + *
260 + * The only the first matched configuration is applied for each
261 + * channel.
262 + *
263 + * The configuration for the channel is applied at the time of
264 + * registration of the parent most_interface.
265 + */
266 +void most_register_config_set(struct most_config_set *cfg_set);
267 +
268 +/**
269 + * most_deregister_config_set - deregisters the prior registered
270 + *     configuration set
271 + *
272 + * @cfg_set: configuration set to be deregistered
273 + *
274 + * The calling of this function does not change the current
275 + * configuration of the channels.
276 + */
277 +void most_deregister_config_set(struct most_config_set *cfg_set);
278 +
279 +/**
280   * most_register_interface - Registers instance of the interface.
281   * @iface: Pointer to the interface instance description.
282   *
283 diff --git a/mostcore/core.c b/mostcore/core.c
284 index 9e0a352..6035cf0 100644
285 --- a/mostcore/core.c
286 +++ b/mostcore/core.c
287 @@ -36,6 +36,8 @@ static struct class *most_class;
288  static struct device *core_dev;
289  static struct ida mdev_id;
290  static int dummy_num_buffers;
291 +static struct list_head config_probes;
292 +struct mutex config_probes_mt; /* config_probes */
293  
294  struct most_c_aim_obj {
295         struct most_aim *ptr;
296 @@ -918,6 +920,30 @@ most_c_obj *get_channel_by_name(char *mdev, char *mdev_ch)
297         return c;
298  }
299  
300 +static int link_channel_to_aim(struct most_c_obj *c, struct most_aim *aim,
301 +                              char *aim_param)
302 +{
303 +       int ret;
304 +       struct most_aim **aim_ptr;
305 +
306 +       if (!c->aim0.ptr)
307 +               aim_ptr = &c->aim0.ptr;
308 +       else if (!c->aim1.ptr)
309 +               aim_ptr = &c->aim1.ptr;
310 +       else
311 +               return -ENOSPC;
312 +
313 +       *aim_ptr = aim;
314 +       ret = aim->probe_channel(c->iface, c->channel_id,
315 +                                &c->cfg, &c->kobj, aim_param);
316 +       if (ret) {
317 +               *aim_ptr = NULL;
318 +               return ret;
319 +       }
320 +
321 +       return 0;
322 +}
323 +
324  /**
325   * add_link_store - store() function for add_link attribute
326   * @aim_obj: pointer to AIM object
327 @@ -946,45 +972,33 @@ static ssize_t add_link_store(struct most_aim_obj *aim_obj,
328                               size_t len)
329  {
330         struct most_c_obj *c;
331 -       struct most_aim **aim_ptr;
332         char buffer[STRING_SIZE];
333         char *mdev;
334         char *mdev_ch;
335 -       char *mdev_devnod;
336 +       char *aim_param;
337         char devnod_buf[STRING_SIZE];
338         int ret;
339         size_t max_len = min_t(size_t, len + 1, STRING_SIZE);
340  
341         strlcpy(buffer, buf, max_len);
342  
343 -       ret = split_string(buffer, &mdev, &mdev_ch, &mdev_devnod);
344 +       ret = split_string(buffer, &mdev, &mdev_ch, &aim_param);
345         if (ret)
346                 return ret;
347  
348 -       if (!mdev_devnod || *mdev_devnod == 0) {
349 +       if (!aim_param || *aim_param == 0) {
350                 snprintf(devnod_buf, sizeof(devnod_buf), "%s-%s", mdev,
351                          mdev_ch);
352 -               mdev_devnod = devnod_buf;
353 +               aim_param = devnod_buf;
354         }
355  
356         c = get_channel_by_name(mdev, mdev_ch);
357         if (IS_ERR(c))
358                 return -ENODEV;
359  
360 -       if (!c->aim0.ptr)
361 -               aim_ptr = &c->aim0.ptr;
362 -       else if (!c->aim1.ptr)
363 -               aim_ptr = &c->aim1.ptr;
364 -       else
365 -               return -ENOSPC;
366 -
367 -       *aim_ptr = aim_obj->driver;
368 -       ret = aim_obj->driver->probe_channel(c->iface, c->channel_id,
369 -                                            &c->cfg, &c->kobj, mdev_devnod);
370 -       if (ret) {
371 -               *aim_ptr = NULL;
372 +       ret = link_channel_to_aim(c, aim_obj->driver, aim_param);
373 +       if (ret)
374                 return ret;
375 -       }
376  
377         return len;
378  }
379 @@ -1679,6 +1693,73 @@ int most_deregister_aim(struct most_aim *aim)
380  }
381  EXPORT_SYMBOL_GPL(most_deregister_aim);
382  
383 +void most_register_config_set(struct most_config_set *cfg_set)
384 +{
385 +       mutex_lock(&config_probes_mt);
386 +       list_add(&cfg_set->list, &config_probes);
387 +       mutex_unlock(&config_probes_mt);
388 +}
389 +EXPORT_SYMBOL(most_register_config_set);
390 +
391 +void most_deregister_config_set(struct most_config_set *cfg_set)
392 +{
393 +       mutex_lock(&config_probes_mt);
394 +       list_del(&cfg_set->list);
395 +       mutex_unlock(&config_probes_mt);
396 +}
397 +EXPORT_SYMBOL(most_deregister_config_set);
398 +
399 +static int probe_aim(struct most_c_obj *c,
400 +                    const char *aim_name, const char *aim_param)
401 +{
402 +       struct most_aim_obj *aim_obj;
403 +       char buf[STRING_SIZE];
404 +
405 +       list_for_each_entry(aim_obj, &aim_list, list) {
406 +               if (!strcmp(aim_obj->driver->name, aim_name)) {
407 +                       strlcpy(buf, aim_param ? aim_param : "", sizeof(buf));
408 +                       return link_channel_to_aim(c, aim_obj->driver, buf);
409 +               }
410 +       }
411 +       return 0;
412 +}
413 +
414 +static bool probe_config_set(struct most_c_obj *c,
415 +                            const char *dev_name, const char *ch_name,
416 +                            const struct most_config_probe *p)
417 +{
418 +       int err;
419 +
420 +       for (; p->ch_name; p++) {
421 +               if ((p->dev_name && strcmp(dev_name, p->dev_name)) ||
422 +                   strcmp(ch_name, p->ch_name))
423 +                       continue;
424 +
425 +               c->cfg = p->cfg;
426 +               if (p->aim_name) {
427 +                       err = probe_aim(c, p->aim_name, p->aim_param);
428 +                       if (err)
429 +                               pr_err("failed to autolink %s to %s: %d\n",
430 +                                      ch_name, p->aim_name, err);
431 +               }
432 +               return true;
433 +       }
434 +       return false;
435 +}
436 +
437 +static void find_configuration(struct most_c_obj *c, const char *dev_name,
438 +                              const char *ch_name)
439 +{
440 +       struct most_config_set *plist;
441 +
442 +       mutex_lock(&config_probes_mt);
443 +       list_for_each_entry(plist, &config_probes, list) {
444 +               if (probe_config_set(c, dev_name, ch_name, plist->probes))
445 +                       break;
446 +       }
447 +       mutex_unlock(&config_probes_mt);
448 +}
449 +
450  /**
451   * most_register_interface - registers an interface with core
452   * @iface: pointer to the instance of the interface description.
453 @@ -1777,6 +1858,7 @@ struct kobject *most_register_interface(struct most_interface *iface)
454                 mutex_init(&c->start_mutex);
455                 mutex_init(&c->nq_mutex);
456                 list_add_tail(&c->list, &inst->channel_list);
457 +               find_configuration(c, iface->description, channel_name);
458         }
459         pr_info("registered new MOST device mdev%d (%s)\n",
460                 inst->dev_id, iface->description);
461 @@ -1880,6 +1962,8 @@ static int __init most_init(void)
462         pr_info("init()\n");
463         INIT_LIST_HEAD(&instance_list);
464         INIT_LIST_HEAD(&aim_list);
465 +       INIT_LIST_HEAD(&config_probes);
466 +       mutex_init(&config_probes_mt);
467         ida_init(&mdev_id);
468  
469         err = bus_register(&most_bus);
470 -- 
471 2.7.4
472