[PATCH] staging: most: core: add autoconf ability

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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.shvetsov@xxxxxx>
Signed-off-by: Christian Gromm <christian.gromm@xxxxxxxxxxxxx>
---
 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
devel@xxxxxxxxxxxxxxxxxxxxxx
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel



[Index of Archives]     [Linux Driver Backports]     [DMA Engine]     [Linux GPIO]     [Linux SPI]     [Video for Linux]     [Linux USB Devel]     [Linux Coverity]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux