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
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.
10 Signed-off-by: Christian Gromm <christian.gromm@microchip.com>
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
19 diff --git a/Makefile b/Makefile
20 index e77a4b6..6d74ebe 100644
23 @@ -6,6 +6,9 @@ obj-m := mostcore.o
24 mostcore-y := mostcore/core.o
25 CFLAGS_core.o := -I$(src)/include/
27 +obj-m += default_conf.o
28 +CFLAGL_default_conf.o := -I$(src)/include
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
35 index 0000000..adb1786
40 + * default_conf.c - Default configuration for the MOST channels.
42 + * Copyright (C) 2017, Microchip Technology Germany II GmbH & Co. KG
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.
49 + * This file is licensed under GPLv2.
52 +#include "include/mostcore.h"
53 +#include <linux/module.h>
55 +static struct most_config_probe config_probes[] = {
57 + /* OS81118 Control */
61 + .direction = MOST_CH_RX,
62 + .data_type = MOST_CH_CONTROL,
67 + .aim_param = "inic-usb-crx",
72 + .direction = MOST_CH_TX,
73 + .data_type = MOST_CH_CONTROL,
78 + .aim_param = "inic-usb-ctx",
84 + .direction = MOST_CH_RX,
85 + .data_type = MOST_CH_ASYNC,
87 + .buffer_size = 1522,
89 + .aim_name = "networking",
90 + .aim_param = "inic-usb-arx",
95 + .direction = MOST_CH_TX,
96 + .data_type = MOST_CH_ASYNC,
98 + .buffer_size = 1522,
100 + .aim_name = "networking",
101 + .aim_param = "inic-usb-atx",
103 + /* OS81210 Control */
107 + .direction = MOST_CH_RX,
108 + .data_type = MOST_CH_CONTROL,
112 + .aim_name = "cdev",
113 + .aim_param = "inic-usb-crx",
118 + .direction = MOST_CH_TX,
119 + .data_type = MOST_CH_CONTROL,
123 + .aim_name = "cdev",
124 + .aim_param = "inic-usb-ctx",
126 + /* OS81210 Async */
130 + .direction = MOST_CH_RX,
131 + .data_type = MOST_CH_ASYNC,
133 + .buffer_size = 1522,
135 + .aim_name = "networking",
136 + .aim_param = "inic-usb-arx",
141 + .direction = MOST_CH_TX,
142 + .data_type = MOST_CH_ASYNC,
144 + .buffer_size = 1522,
146 + .aim_name = "networking",
147 + .aim_param = "inic-usb-atx",
149 + /* Streaming channels (common for all INICs) */
153 + .direction = MOST_CH_TX,
154 + .data_type = MOST_CH_SYNC,
156 + .buffer_size = 2 * 12 * 42,
157 + .subbuffer_size = 12,
158 + .packets_per_xact = 42,
160 + .aim_name = "sound",
161 + .aim_param = "ep01-6ch.6x16",
166 + .direction = MOST_CH_TX,
167 + .data_type = MOST_CH_ISOC,
169 + .buffer_size = 40 * 188,
170 + .subbuffer_size = 188,
171 + .packets_per_xact = 2,
173 + .aim_name = "cdev",
174 + .aim_param = "inic-usb-itx1",
181 +static struct most_config_set config_set = {
182 + .probes = config_probes
185 +static int __init mod_init(void)
187 + most_register_config_set(&config_set);
191 +static void __exit mod_exit(void)
193 + most_deregister_config_set(&config_set);
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 {
210 + * struct most_config_probe - matching rule, channel configuration and
211 + * the optional AIM name used for the automatic configuration and linking
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.)
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;
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
237 +struct most_config_set {
238 + const struct most_config_probe *probes;
239 + struct list_head list;
243 * struct mbo - MOST Buffer Object.
244 * @context: context for core completion handler
245 @@ -285,6 +318,37 @@ struct most_aim {
249 + * most_register_config_set - registers the configuration set
251 + * @cfg_set: configuration set to be registered for the future probes
253 + * The function registers the given configuration set.
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.
260 + * The only the first matched configuration is applied for each
263 + * The configuration for the channel is applied at the time of
264 + * registration of the parent most_interface.
266 +void most_register_config_set(struct most_config_set *cfg_set);
269 + * most_deregister_config_set - deregisters the prior registered
270 + * configuration set
272 + * @cfg_set: configuration set to be deregistered
274 + * The calling of this function does not change the current
275 + * configuration of the channels.
277 +void most_deregister_config_set(struct most_config_set *cfg_set);
280 * most_register_interface - Registers instance of the interface.
281 * @iface: Pointer to the interface instance description.
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 */
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)
300 +static int link_channel_to_aim(struct most_c_obj *c, struct most_aim *aim,
304 + struct most_aim **aim_ptr;
307 + aim_ptr = &c->aim0.ptr;
308 + else if (!c->aim1.ptr)
309 + aim_ptr = &c->aim1.ptr;
314 + ret = aim->probe_channel(c->iface, c->channel_id,
315 + &c->cfg, &c->kobj, aim_param);
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,
330 struct most_c_obj *c;
331 - struct most_aim **aim_ptr;
332 char buffer[STRING_SIZE];
337 char devnod_buf[STRING_SIZE];
339 size_t max_len = min_t(size_t, len + 1, STRING_SIZE);
341 strlcpy(buffer, buf, max_len);
343 - ret = split_string(buffer, &mdev, &mdev_ch, &mdev_devnod);
344 + ret = split_string(buffer, &mdev, &mdev_ch, &aim_param);
348 - if (!mdev_devnod || *mdev_devnod == 0) {
349 + if (!aim_param || *aim_param == 0) {
350 snprintf(devnod_buf, sizeof(devnod_buf), "%s-%s", mdev,
352 - mdev_devnod = devnod_buf;
353 + aim_param = devnod_buf;
356 c = get_channel_by_name(mdev, mdev_ch);
361 - aim_ptr = &c->aim0.ptr;
362 - else if (!c->aim1.ptr)
363 - aim_ptr = &c->aim1.ptr;
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);
372 + ret = link_channel_to_aim(c, aim_obj->driver, aim_param);
379 @@ -1679,6 +1693,73 @@ int most_deregister_aim(struct most_aim *aim)
381 EXPORT_SYMBOL_GPL(most_deregister_aim);
383 +void most_register_config_set(struct most_config_set *cfg_set)
385 + mutex_lock(&config_probes_mt);
386 + list_add(&cfg_set->list, &config_probes);
387 + mutex_unlock(&config_probes_mt);
389 +EXPORT_SYMBOL(most_register_config_set);
391 +void most_deregister_config_set(struct most_config_set *cfg_set)
393 + mutex_lock(&config_probes_mt);
394 + list_del(&cfg_set->list);
395 + mutex_unlock(&config_probes_mt);
397 +EXPORT_SYMBOL(most_deregister_config_set);
399 +static int probe_aim(struct most_c_obj *c,
400 + const char *aim_name, const char *aim_param)
402 + struct most_aim_obj *aim_obj;
403 + char buf[STRING_SIZE];
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);
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)
420 + for (; p->ch_name; p++) {
421 + if ((p->dev_name && strcmp(dev_name, p->dev_name)) ||
422 + strcmp(ch_name, p->ch_name))
427 + err = probe_aim(c, p->aim_name, p->aim_param);
429 + pr_err("failed to autolink %s to %s: %d\n",
430 + ch_name, p->aim_name, err);
437 +static void find_configuration(struct most_c_obj *c, const char *dev_name,
438 + const char *ch_name)
440 + struct most_config_set *plist;
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))
447 + mutex_unlock(&config_probes_mt);
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);
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)
463 INIT_LIST_HEAD(&instance_list);
464 INIT_LIST_HEAD(&aim_list);
465 + INIT_LIST_HEAD(&config_probes);
466 + mutex_init(&config_probes_mt);
469 err = bus_register(&most_bus);