This patch extends the driver with the possibility of automatic
configuration. This covers channel settings and connection establishing of
a MOST device interface while it is registered with the core.

Making use of auto configuration will significantly cut the start-up
overhead and the duration until the driver is available in userspace.
Since the configuration depends on the type of network interface controller
its setup and the peripheral interface, it can _not_ be part of the kernel
and needs to be added once the system has been engineered.

Signed-off-by: Andrey Shvetsov <andrey.shvet...@k2l.de>
Signed-off-by: Christian Gromm <christian.gr...@microchip.com>
---
 drivers/staging/most/mostcore/core.c     | 120 ++++++++++++++++++++++++++-----
 drivers/staging/most/mostcore/mostcore.h |  66 ++++++++++++++++-
 2 files changed, 167 insertions(+), 19 deletions(-)

diff --git a/drivers/staging/most/mostcore/core.c 
b/drivers/staging/most/mostcore/core.c
index 675b2a9..cd2d20a 100644
--- a/drivers/staging/most/mostcore/core.c
+++ b/drivers/staging/most/mostcore/core.c
@@ -36,6 +36,8 @@
 static struct device *core_dev;
 static struct ida mdev_id;
 static int dummy_num_buffers;
+static struct list_head config_probes;
+struct mutex config_probes_mt; /* config_probes */
 
 struct most_c_aim_obj {
        struct most_aim *ptr;
@@ -926,6 +928,30 @@ most_c_obj *get_channel_by_name(char *mdev, char *mdev_ch)
        return c;
 }
 
+static int link_channel_to_aim(struct most_c_obj *c, struct most_aim *aim,
+                              char *aim_param)
+{
+       int ret;
+       struct most_aim **aim_ptr;
+
+       if (!c->aim0.ptr)
+               aim_ptr = &c->aim0.ptr;
+       else if (!c->aim1.ptr)
+               aim_ptr = &c->aim1.ptr;
+       else
+               return -ENOSPC;
+
+       *aim_ptr = aim;
+       ret = aim->probe_channel(c->iface, c->channel_id,
+                                &c->cfg, &c->kobj, aim_param);
+       if (ret) {
+               *aim_ptr = NULL;
+               return ret;
+       }
+
+       return 0;
+}
+
 /**
  * add_link_store - store() function for add_link attribute
  * @aim_obj: pointer to AIM object
@@ -954,45 +980,33 @@ static ssize_t add_link_store(struct most_aim_obj 
*aim_obj,
                              size_t len)
 {
        struct most_c_obj *c;
-       struct most_aim **aim_ptr;
        char buffer[STRING_SIZE];
        char *mdev;
        char *mdev_ch;
-       char *mdev_devnod;
+       char *aim_param;
        char devnod_buf[STRING_SIZE];
        int ret;
        size_t max_len = min_t(size_t, len + 1, STRING_SIZE);
 
        strlcpy(buffer, buf, max_len);
 
-       ret = split_string(buffer, &mdev, &mdev_ch, &mdev_devnod);
+       ret = split_string(buffer, &mdev, &mdev_ch, &aim_param);
        if (ret)
                return ret;
 
-       if (!mdev_devnod || *mdev_devnod == 0) {
+       if (!aim_param || *aim_param == 0) {
                snprintf(devnod_buf, sizeof(devnod_buf), "%s-%s", mdev,
                         mdev_ch);
-               mdev_devnod = devnod_buf;
+               aim_param = devnod_buf;
        }
 
        c = get_channel_by_name(mdev, mdev_ch);
        if (IS_ERR(c))
                return -ENODEV;
 
-       if (!c->aim0.ptr)
-               aim_ptr = &c->aim0.ptr;
-       else if (!c->aim1.ptr)
-               aim_ptr = &c->aim1.ptr;
-       else
-               return -ENOSPC;
-
-       *aim_ptr = aim_obj->driver;
-       ret = aim_obj->driver->probe_channel(c->iface, c->channel_id,
-                                            &c->cfg, &c->kobj, mdev_devnod);
-       if (ret) {
-               *aim_ptr = NULL;
+       ret = link_channel_to_aim(c, aim_obj->driver, aim_param);
+       if (ret)
                return ret;
-       }
 
        return len;
 }
@@ -1685,6 +1699,73 @@ int most_deregister_aim(struct most_aim *aim)
 }
 EXPORT_SYMBOL_GPL(most_deregister_aim);
 
+void most_register_config_set(struct most_config_set *cfg_set)
+{
+       mutex_lock(&config_probes_mt);
+       list_add(&cfg_set->list, &config_probes);
+       mutex_unlock(&config_probes_mt);
+}
+EXPORT_SYMBOL(most_register_config_set);
+
+void most_deregister_config_set(struct most_config_set *cfg_set)
+{
+       mutex_lock(&config_probes_mt);
+       list_del(&cfg_set->list);
+       mutex_unlock(&config_probes_mt);
+}
+EXPORT_SYMBOL(most_deregister_config_set);
+
+static int probe_aim(struct most_c_obj *c,
+                    const char *aim_name, const char *aim_param)
+{
+       struct most_aim_obj *aim_obj;
+       char buf[STRING_SIZE];
+
+       list_for_each_entry(aim_obj, &aim_list, list) {
+               if (!strcmp(aim_obj->driver->name, aim_name)) {
+                       strlcpy(buf, aim_param ? aim_param : "", sizeof(buf));
+                       return link_channel_to_aim(c, aim_obj->driver, buf);
+               }
+       }
+       return 0;
+}
+
+static bool probe_config_set(struct most_c_obj *c,
+                            const char *dev_name, const char *ch_name,
+                            const struct most_config_probe *p)
+{
+       int err;
+
+       for (; p->ch_name; p++) {
+               if ((p->dev_name && strcmp(dev_name, p->dev_name)) ||
+                   strcmp(ch_name, p->ch_name))
+                       continue;
+
+               c->cfg = p->cfg;
+               if (p->aim_name) {
+                       err = probe_aim(c, p->aim_name, p->aim_param);
+                       if (err)
+                               pr_err("failed to autolink %s to %s: %d\n",
+                                      ch_name, p->aim_name, err);
+               }
+               return true;
+       }
+       return false;
+}
+
+static void find_configuration(struct most_c_obj *c, const char *dev_name,
+                              const char *ch_name)
+{
+       struct most_config_set *plist;
+
+       mutex_lock(&config_probes_mt);
+       list_for_each_entry(plist, &config_probes, list) {
+               if (probe_config_set(c, dev_name, ch_name, plist->probes))
+                       break;
+       }
+       mutex_unlock(&config_probes_mt);
+}
+
 /**
  * most_register_interface - registers an interface with core
  * @iface: pointer to the instance of the interface description.
@@ -1762,6 +1843,7 @@ struct kobject *most_register_interface(struct 
most_interface *iface)
                mutex_init(&c->start_mutex);
                mutex_init(&c->nq_mutex);
                list_add_tail(&c->list, &inst->channel_list);
+               find_configuration(c, iface->description, channel_name);
        }
        pr_info("registered new MOST device mdev%d (%s)\n",
                inst->dev_id, iface->description);
@@ -1865,6 +1947,8 @@ static int __init most_init(void)
        pr_info("init()\n");
        INIT_LIST_HEAD(&instance_list);
        INIT_LIST_HEAD(&aim_list);
+       INIT_LIST_HEAD(&config_probes);
+       mutex_init(&config_probes_mt);
        ida_init(&mdev_id);
 
        err = bus_register(&most_bus);
diff --git a/drivers/staging/most/mostcore/mostcore.h 
b/drivers/staging/most/mostcore/mostcore.h
index 5f8339b..bad7cc4 100644
--- a/drivers/staging/most/mostcore/mostcore.h
+++ b/drivers/staging/most/mostcore/mostcore.h
@@ -2,7 +2,7 @@
  * mostcore.h - Interface between MostCore,
  *   Hardware Dependent Module (HDM) and Application Interface Module (AIM).
  *
- * Copyright (C) 2013-2015, Microchip Technology Germany II GmbH & Co. KG
+ * Copyright (C) 2013-2017, Microchip Technology Germany II GmbH & Co. KG
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -143,6 +143,39 @@ struct most_channel_config {
        u16 packets_per_xact;
 };
 
+/**
+ * struct most_config_probe - matching rule, channel configuration and
+ *     the optional AIM name used for the automatic configuration and linking
+ *     of the channel
+ * @dev_name: optional mathing device id
+ *     ("usb_device 1-1:1.0," "dim2-12345678", etc.)
+ * @ch_name: matching channel name ("ep8f", "ca2", etc.)
+ * @cfg: configuration that will be applied for the found channel
+ * @aim_name: optional name of the AIM that will be linked to the channel
+ *     ("cdev", "networking", "v4l", "sound")
+ * @aim_param: AIM dependent parameter (it is the character device name
+ *     for the cdev AIM, PCM format for the audio AIM, etc.)
+ */
+struct most_config_probe {
+       const char *dev_name;
+       const char *ch_name;
+       struct most_channel_config cfg;
+       const char *aim_name;
+       const char *aim_param;
+};
+
+/**
+ * struct most_config_set - the configuration set containing
+ *     several automatic configurations for the different channels
+ * @probes: list of the matching rules and the confugurations,
+ *     that must be ended with the empty structure
+ * @list: list head used by the MostCore
+ */
+struct most_config_set {
+       const struct most_config_probe *probes;
+       struct list_head list;
+};
+
 /*
  * struct mbo - MOST Buffer Object.
  * @context: context for core completion handler
@@ -272,6 +305,37 @@ struct most_aim {
 };
 
 /**
+ * most_register_config_set - registers the configuration set
+ *
+ * @cfg_set: configuration set to be registered for the future probes
+ *
+ * The function registers the given configuration set.
+ *
+ * It is possible to register or deregister several configuration sets
+ * independently.  Different configuration sets may contain the
+ * overlapped matching rules but later registered configuration set has
+ * the higher priority over the prior registered set.
+ *
+ * The only the first matched configuration is appliead for each
+ * channel.
+ *
+ * The configuration for the channel is applied at the time of
+ * registration of the parent most_interface.
+ */
+void most_register_config_set(struct most_config_set *cfg_set);
+
+/**
+ * most_deregister_config_set - deregisters the prior registered
+ *     configuration set
+ *
+ * @cfg_set: configuration set to be deregistered
+ *
+ * The calling of this function does not change the current
+ * configuration of the cahnnels.
+ */
+void most_deregister_config_set(struct most_config_set *cfg_set);
+
+/**
  * most_register_interface - Registers instance of the interface.
  * @iface: Pointer to the interface instance description.
  *
-- 
1.9.1

_______________________________________________
devel mailing list
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel

Reply via email to