mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Tomas Winkler <tomas.winkler@intel.com>
To: gregkh@linuxfoundation.org
Cc: arnd@arndb.de, linux-kernel@vger.kernel.org,
	Tomas Winkler <tomas.winkler@intel.com>
Subject: [char-misc-next 03/15 V2] mei: bus: move driver api functions at the start of the file
Date: Mon, 15 Jun 2015 21:56:43 +0300	[thread overview]
Message-ID: <1434394615-3754-4-git-send-email-tomas.winkler@intel.com> (raw)
In-Reply-To: <1434394615-3754-1-git-send-email-tomas.winkler@intel.com>

To make the file more organize move mei client driver api
to the start of the file and add Kdoc.

There are no functional changes in this patch.

Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
---
V2: Resend
 drivers/misc/mei/bus.c | 798 +++++++++++++++++++++++++++----------------------
 1 file changed, 443 insertions(+), 355 deletions(-)

diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
index a40be68dd7aa..d5c6ab3c856d 100644
--- a/drivers/misc/mei/bus.c
+++ b/drivers/misc/mei/bus.c
@@ -30,527 +30,615 @@
 #define to_mei_cl_driver(d) container_of(d, struct mei_cl_driver, driver)
 #define to_mei_cl_device(d) container_of(d, struct mei_cl_device, dev)
 
-static int mei_cl_device_match(struct device *dev, struct device_driver *drv)
+/**
+ * __mei_cl_send - internal client send (write)
+ *
+ * @cl: host client
+ * @buf: buffer to send
+ * @length: buffer length
+ * @blocking: wait for write completion
+ *
+ * Return: written size bytes or < 0 on error
+ */
+ssize_t __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length,
+			bool blocking)
 {
-	struct mei_cl_device *cldev = to_mei_cl_device(dev);
-	struct mei_cl_driver *cldrv = to_mei_cl_driver(drv);
-	const struct mei_cl_device_id *id;
-	const uuid_le *uuid;
-	const char *name;
-
-	if (!cldev)
-		return 0;
+	struct mei_device *bus;
+	struct mei_cl_cb *cb = NULL;
+	ssize_t rets;
 
-	uuid = mei_me_cl_uuid(cldev->me_cl);
-	name = cldev->name;
+	if (WARN_ON(!cl || !cl->dev))
+		return -ENODEV;
 
-	if (!cldrv || !cldrv->id_table)
-		return 0;
+	bus = cl->dev;
 
-	id = cldrv->id_table;
+	mutex_lock(&bus->device_lock);
+	if (!mei_cl_is_connected(cl)) {
+		rets = -ENODEV;
+		goto out;
+	}
 
-	while (uuid_le_cmp(NULL_UUID_LE, id->uuid)) {
+	/* Check if we have an ME client device */
+	if (!mei_me_cl_is_active(cl->me_cl)) {
+		rets = -ENOTTY;
+		goto out;
+	}
 
-		if (!uuid_le_cmp(*uuid, id->uuid)) {
-			if (id->name[0]) {
-				if (!strncmp(name, id->name, sizeof(id->name)))
-					return 1;
-			} else {
-				return 1;
-			}
-		}
+	if (length > mei_cl_mtu(cl)) {
+		rets = -EFBIG;
+		goto out;
+	}
 
-		id++;
+	cb = mei_cl_alloc_cb(cl, length, MEI_FOP_WRITE, NULL);
+	if (!cb) {
+		rets = -ENOMEM;
+		goto out;
 	}
 
-	return 0;
+	memcpy(cb->buf.data, buf, length);
+
+	rets = mei_cl_write(cl, cb, blocking);
+
+out:
+	mutex_unlock(&bus->device_lock);
+	if (rets < 0)
+		mei_io_cb_free(cb);
+
+	return rets;
 }
 
-static int mei_cl_device_probe(struct device *dev)
+/**
+ * __mei_cl_recv - internal client receive (read)
+ *
+ * @cl: host client
+ * @buf: buffer to send
+ * @length: buffer length
+ *
+ * Return: read size in bytes of < 0 on error
+ */
+ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length)
 {
-	struct mei_cl_device *cldev = to_mei_cl_device(dev);
-	struct mei_cl_driver *cldrv;
-	struct mei_cl_device_id id;
-
-	if (!cldev)
-		return 0;
+	struct mei_device *bus;
+	struct mei_cl_cb *cb;
+	size_t r_length;
+	ssize_t rets;
 
-	cldrv = to_mei_cl_driver(dev->driver);
-	if (!cldrv || !cldrv->probe)
+	if (WARN_ON(!cl || !cl->dev))
 		return -ENODEV;
 
-	dev_dbg(dev, "Device probe\n");
+	bus = cl->dev;
 
-	strlcpy(id.name, cldev->name, sizeof(id.name));
+	mutex_lock(&bus->device_lock);
 
-	return cldrv->probe(cldev, &id);
-}
+	cb = mei_cl_read_cb(cl, NULL);
+	if (cb)
+		goto copy;
 
-static int mei_cl_device_remove(struct device *dev)
-{
-	struct mei_cl_device *cldev = to_mei_cl_device(dev);
-	struct mei_cl_driver *cldrv;
+	rets = mei_cl_read_start(cl, length, NULL);
+	if (rets && rets != -EBUSY)
+		goto out;
 
-	if (!cldev || !dev->driver)
-		return 0;
+	if (list_empty(&cl->rd_completed) && !waitqueue_active(&cl->rx_wait)) {
 
-	if (cldev->event_cb) {
-		cldev->event_cb = NULL;
-		cancel_work_sync(&cldev->event_work);
-	}
+		mutex_unlock(&bus->device_lock);
 
-	cldrv = to_mei_cl_driver(dev->driver);
-	if (!cldrv->remove) {
-		dev->driver = NULL;
+		if (wait_event_interruptible(cl->rx_wait,
+				(!list_empty(&cl->rd_completed)) ||
+				(!mei_cl_is_connected(cl)))) {
 
-		return 0;
+			if (signal_pending(current))
+				return -EINTR;
+			return -ERESTARTSYS;
+		}
+
+		mutex_lock(&bus->device_lock);
+
+		if (!mei_cl_is_connected(cl)) {
+			rets = -EBUSY;
+			goto out;
+		}
 	}
 
-	return cldrv->remove(cldev);
-}
+	cb = mei_cl_read_cb(cl, NULL);
+	if (!cb) {
+		rets = 0;
+		goto out;
+	}
 
-static ssize_t name_show(struct device *dev, struct device_attribute *a,
-			     char *buf)
-{
-	struct mei_cl_device *cldev = to_mei_cl_device(dev);
-	size_t len;
+copy:
+	if (cb->status) {
+		rets = cb->status;
+		goto free;
+	}
 
-	len = snprintf(buf, PAGE_SIZE, "%s", cldev->name);
+	r_length = min_t(size_t, length, cb->buf_idx);
+	memcpy(buf, cb->buf.data, r_length);
+	rets = r_length;
 
-	return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
+free:
+	mei_io_cb_free(cb);
+out:
+	mutex_unlock(&bus->device_lock);
+
+	return rets;
 }
-static DEVICE_ATTR_RO(name);
 
-static ssize_t uuid_show(struct device *dev, struct device_attribute *a,
-			     char *buf)
+/**
+ * mei_cl_send - me device send  (write)
+ *
+ * @cldev: me client device
+ * @buf: buffer to send
+ * @length: buffer length
+ *
+ * Return: written size in bytes or < 0 on error
+ */
+ssize_t mei_cl_send(struct mei_cl_device *cldev, u8 *buf, size_t length)
 {
-	struct mei_cl_device *cldev = to_mei_cl_device(dev);
-	const uuid_le *uuid = mei_me_cl_uuid(cldev->me_cl);
-	size_t len;
+	struct mei_cl *cl = cldev->cl;
 
-	len = snprintf(buf, PAGE_SIZE, "%pUl", uuid);
+	if (cl == NULL)
+		return -ENODEV;
 
-	return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
+	return __mei_cl_send(cl, buf, length, 1);
 }
-static DEVICE_ATTR_RO(uuid);
+EXPORT_SYMBOL_GPL(mei_cl_send);
 
-static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
-			     char *buf)
+/**
+ * mei_cl_recv - client receive (read)
+ *
+ * @cldev: me client device
+ * @buf: buffer to send
+ * @length: buffer length
+ *
+ * Return: read size in bytes of < 0 on error
+ */
+ssize_t mei_cl_recv(struct mei_cl_device *cldev, u8 *buf, size_t length)
 {
-	struct mei_cl_device *cldev = to_mei_cl_device(dev);
-	const uuid_le *uuid = mei_me_cl_uuid(cldev->me_cl);
-	size_t len;
+	struct mei_cl *cl = cldev->cl;
 
-	len = snprintf(buf, PAGE_SIZE, "mei:%s:" MEI_CL_UUID_FMT ":",
-		cldev->name, MEI_CL_UUID_ARGS(uuid->b));
+	if (cl == NULL)
+		return -ENODEV;
 
-	return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
+	return __mei_cl_recv(cl, buf, length);
 }
-static DEVICE_ATTR_RO(modalias);
-
-static struct attribute *mei_cl_dev_attrs[] = {
-	&dev_attr_name.attr,
-	&dev_attr_uuid.attr,
-	&dev_attr_modalias.attr,
-	NULL,
-};
-ATTRIBUTE_GROUPS(mei_cl_dev);
+EXPORT_SYMBOL_GPL(mei_cl_recv);
 
-static int mei_cl_uevent(struct device *dev, struct kobj_uevent_env *env)
+/**
+ * mei_bus_event_work  - dispatch rx event for a bus device
+ *    and schedule new work
+ *
+ * @work: work
+ */
+static void mei_bus_event_work(struct work_struct *work)
 {
-	struct mei_cl_device *cldev = to_mei_cl_device(dev);
-	const uuid_le *uuid = mei_me_cl_uuid(cldev->me_cl);
+	struct mei_cl_device *cldev;
 
-	if (add_uevent_var(env, "MEI_CL_UUID=%pUl", uuid))
-		return -ENOMEM;
+	cldev = container_of(work, struct mei_cl_device, event_work);
 
-	if (add_uevent_var(env, "MEI_CL_NAME=%s", cldev->name))
-		return -ENOMEM;
+	if (cldev->event_cb)
+		cldev->event_cb(cldev, cldev->events, cldev->event_context);
 
-	if (add_uevent_var(env, "MODALIAS=mei:%s:" MEI_CL_UUID_FMT ":",
-		cldev->name, MEI_CL_UUID_ARGS(uuid->b)))
-		return -ENOMEM;
+	cldev->events = 0;
 
-	return 0;
+	/* Prepare for the next read */
+	mei_cl_read_start(cldev->cl, 0, NULL);
 }
 
-static struct bus_type mei_cl_bus_type = {
-	.name		= "mei",
-	.dev_groups	= mei_cl_dev_groups,
-	.match		= mei_cl_device_match,
-	.probe		= mei_cl_device_probe,
-	.remove		= mei_cl_device_remove,
-	.uevent		= mei_cl_uevent,
-};
-
-static void mei_cl_dev_release(struct device *dev)
+/**
+ * mei_cl_bus_rx_event  - schedule rx evenet
+ *
+ * @cl: host client
+ */
+void mei_cl_bus_rx_event(struct mei_cl *cl)
 {
-	struct mei_cl_device *cldev = to_mei_cl_device(dev);
+	struct mei_cl_device *cldev = cl->cldev;
 
-	if (!cldev)
+	if (!cldev || !cldev->event_cb)
 		return;
 
-	mei_me_cl_put(cldev->me_cl);
-	kfree(cldev);
-}
-
-static struct device_type mei_cl_device_type = {
-	.release	= mei_cl_dev_release,
-};
-
-struct mei_cl *mei_cl_bus_find_cl_by_uuid(struct mei_device *bus,
-					 uuid_le uuid)
-{
-	struct mei_cl *cl;
-
-	list_for_each_entry(cl, &bus->device_list, device_link) {
-		if (cl->cldev && cl->cldev->me_cl &&
-		    !uuid_le_cmp(uuid, *mei_me_cl_uuid(cl->cldev->me_cl)))
-			return cl;
-	}
+	set_bit(MEI_CL_EVENT_RX, &cldev->events);
 
-	return NULL;
+	schedule_work(&cldev->event_work);
 }
 
-struct mei_cl_device *mei_cl_add_device(struct mei_device *bus,
-					struct mei_me_client *me_cl,
-					struct mei_cl *cl,
-					char *name)
+/**
+ * mei_cl_register_event_cb - register event callback
+ *
+ * @cldev: me client devices
+ * @event_cb: callback function
+ * @context: driver context data
+ *
+ * Return: 0 on success
+ *         -EALREADY if an callback is already registered
+ *         <0 on other errors
+ */
+int mei_cl_register_event_cb(struct mei_cl_device *cldev,
+			  mei_cl_event_cb_t event_cb, void *context)
 {
-	struct mei_cl_device *cldev;
-	int status;
-
-	cldev = kzalloc(sizeof(struct mei_cl_device), GFP_KERNEL);
-	if (!cldev)
-		return NULL;
-
-	cldev->me_cl = mei_me_cl_get(me_cl);
-	if (!cldev->me_cl) {
-		kfree(cldev);
-		return NULL;
-	}
-
-	cldev->cl = cl;
-	cldev->dev.parent = bus->dev;
-	cldev->dev.bus = &mei_cl_bus_type;
-	cldev->dev.type = &mei_cl_device_type;
-
-	strlcpy(cldev->name, name, sizeof(cldev->name));
-
-	dev_set_name(&cldev->dev, "mei:%s:%pUl", name, mei_me_cl_uuid(me_cl));
+	if (cldev->event_cb)
+		return -EALREADY;
 
-	status = device_register(&cldev->dev);
-	if (status) {
-		dev_err(bus->dev, "Failed to register MEI device\n");
-		mei_me_cl_put(cldev->me_cl);
-		kfree(cldev);
-		return NULL;
-	}
+	cldev->events = 0;
+	cldev->event_cb = event_cb;
+	cldev->event_context = context;
+	INIT_WORK(&cldev->event_work, mei_bus_event_work);
 
-	cl->cldev = cldev;
+	mei_cl_read_start(cldev->cl, 0, NULL);
 
-	dev_dbg(&cldev->dev, "client %s registered\n", name);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(mei_cl_register_event_cb);
 
-	return cldev;
+/**
+ * mei_cl_get_drvdata - driver data getter
+ *
+ * @cldev: mei client device
+ *
+ * Return: driver private data
+ */
+void *mei_cl_get_drvdata(const struct mei_cl_device *cldev)
+{
+	return dev_get_drvdata(&cldev->dev);
 }
-EXPORT_SYMBOL_GPL(mei_cl_add_device);
+EXPORT_SYMBOL_GPL(mei_cl_get_drvdata);
 
-void mei_cl_remove_device(struct mei_cl_device *cldev)
+/**
+ * mei_cl_set_drvdata - driver data setter
+ *
+ * @cldev: mei client device
+ * @data: data to store
+ */
+void mei_cl_set_drvdata(struct mei_cl_device *cldev, void *data)
 {
-	device_unregister(&cldev->dev);
+	dev_set_drvdata(&cldev->dev, data);
 }
-EXPORT_SYMBOL_GPL(mei_cl_remove_device);
+EXPORT_SYMBOL_GPL(mei_cl_set_drvdata);
 
-int __mei_cl_driver_register(struct mei_cl_driver *cldrv, struct module *owner)
+/**
+ * mei_cl_enable_device - enable me client device
+ *     create connection with me client
+ *
+ * @cldev: me client device
+ *
+ * Return: 0 on success and < 0 on error
+ */
+int mei_cl_enable_device(struct mei_cl_device *cldev)
 {
 	int err;
+	struct mei_device *bus;
+	struct mei_cl *cl = cldev->cl;
 
-	cldrv->driver.name = cldrv->name;
-	cldrv->driver.owner = owner;
-	cldrv->driver.bus = &mei_cl_bus_type;
+	if (cl == NULL)
+		return -ENODEV;
 
-	err = driver_register(&cldrv->driver);
-	if (err)
-		return err;
+	bus = cl->dev;
 
-	pr_debug("mei: driver [%s] registered\n", cldrv->driver.name);
+	mutex_lock(&bus->device_lock);
 
-	return 0;
-}
-EXPORT_SYMBOL_GPL(__mei_cl_driver_register);
+	if (mei_cl_is_connected(cl)) {
+		mutex_unlock(&bus->device_lock);
+		dev_warn(bus->dev, "Already connected");
+		return -EBUSY;
+	}
 
-void mei_cl_driver_unregister(struct mei_cl_driver *cldrv)
-{
-	driver_unregister(&cldrv->driver);
+	err = mei_cl_connect(cl, cldev->me_cl, NULL);
+	if (err < 0) {
+		mutex_unlock(&bus->device_lock);
+		dev_err(bus->dev, "Could not connect to the ME client");
 
-	pr_debug("mei: driver [%s] unregistered\n", cldrv->driver.name);
+		return err;
+	}
+
+	mutex_unlock(&bus->device_lock);
+
+	if (cldev->event_cb)
+		mei_cl_read_start(cldev->cl, 0, NULL);
+
+	return 0;
 }
-EXPORT_SYMBOL_GPL(mei_cl_driver_unregister);
+EXPORT_SYMBOL_GPL(mei_cl_enable_device);
 
-ssize_t __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length,
-			bool blocking)
+/**
+ * mei_cl_disable_device - disable me client device
+ *     disconnect form the me client
+ *
+ * @cldev: me client device
+ *
+ * Return: 0 on success and < 0 on error
+ */
+int mei_cl_disable_device(struct mei_cl_device *cldev)
 {
+	int err;
 	struct mei_device *bus;
-	struct mei_cl_cb *cb = NULL;
-	ssize_t rets;
+	struct mei_cl *cl = cldev->cl;
 
-	if (WARN_ON(!cl || !cl->dev))
+	if (cl == NULL)
 		return -ENODEV;
 
 	bus = cl->dev;
 
-	mutex_lock(&bus->device_lock);
-	if (!mei_cl_is_connected(cl)) {
-		rets = -ENODEV;
-		goto out;
-	}
+	cldev->event_cb = NULL;
 
-	/* Check if we have an ME client device */
-	if (!mei_me_cl_is_active(cl->me_cl)) {
-		rets = -ENOTTY;
-		goto out;
-	}
+	mutex_lock(&bus->device_lock);
 
-	if (length > mei_cl_mtu(cl)) {
-		rets = -EFBIG;
+	if (!mei_cl_is_connected(cl)) {
+		dev_err(bus->dev, "Already disconnected");
+		err = 0;
 		goto out;
 	}
 
-	cb = mei_cl_alloc_cb(cl, length, MEI_FOP_WRITE, NULL);
-	if (!cb) {
-		rets = -ENOMEM;
+	err = mei_cl_disconnect(cl);
+	if (err < 0) {
+		dev_err(bus->dev, "Could not disconnect from the ME client");
 		goto out;
 	}
 
-	memcpy(cb->buf.data, buf, length);
-
-	rets = mei_cl_write(cl, cb, blocking);
+	/* Flush queues and remove any pending read */
+	mei_cl_flush_queues(cl, NULL);
 
 out:
 	mutex_unlock(&bus->device_lock);
-	if (rets < 0)
-		mei_io_cb_free(cb);
+	return err;
 
-	return rets;
 }
+EXPORT_SYMBOL_GPL(mei_cl_disable_device);
 
-ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length)
+static int mei_cl_device_match(struct device *dev, struct device_driver *drv)
 {
-	struct mei_device *bus;
-	struct mei_cl_cb *cb;
-	size_t r_length;
-	ssize_t rets;
+	struct mei_cl_device *cldev = to_mei_cl_device(dev);
+	struct mei_cl_driver *cldrv = to_mei_cl_driver(drv);
+	const struct mei_cl_device_id *id;
+	const uuid_le *uuid;
+	const char *name;
 
-	if (WARN_ON(!cl || !cl->dev))
-		return -ENODEV;
+	if (!cldev)
+		return 0;
 
-	bus = cl->dev;
+	uuid = mei_me_cl_uuid(cldev->me_cl);
+	name = cldev->name;
 
-	mutex_lock(&bus->device_lock);
+	if (!cldrv || !cldrv->id_table)
+		return 0;
 
-	cb = mei_cl_read_cb(cl, NULL);
-	if (cb)
-		goto copy;
+	id = cldrv->id_table;
 
-	rets = mei_cl_read_start(cl, length, NULL);
-	if (rets && rets != -EBUSY)
-		goto out;
+	while (uuid_le_cmp(NULL_UUID_LE, id->uuid)) {
 
-	if (list_empty(&cl->rd_completed) && !waitqueue_active(&cl->rx_wait)) {
+		if (!uuid_le_cmp(*uuid, id->uuid)) {
+			if (id->name[0]) {
+				if (!strncmp(name, id->name, sizeof(id->name)))
+					return 1;
+			} else {
+				return 1;
+			}
+		}
 
-		mutex_unlock(&bus->device_lock);
+		id++;
+	}
 
-		if (wait_event_interruptible(cl->rx_wait,
-				(!list_empty(&cl->rd_completed)) ||
-				(!mei_cl_is_connected(cl)))) {
+	return 0;
+}
 
-			if (signal_pending(current))
-				return -EINTR;
-			return -ERESTARTSYS;
-		}
+static int mei_cl_device_probe(struct device *dev)
+{
+	struct mei_cl_device *cldev = to_mei_cl_device(dev);
+	struct mei_cl_driver *cldrv;
+	struct mei_cl_device_id id;
 
-		mutex_lock(&bus->device_lock);
+	if (!cldev)
+		return 0;
 
-		if (!mei_cl_is_connected(cl)) {
-			rets = -EBUSY;
-			goto out;
-		}
-	}
+	cldrv = to_mei_cl_driver(dev->driver);
+	if (!cldrv || !cldrv->probe)
+		return -ENODEV;
+
+	dev_dbg(dev, "Device probe\n");
+
+	strlcpy(id.name, cldev->name, sizeof(id.name));
+
+	return cldrv->probe(cldev, &id);
+}
 
-	cb = mei_cl_read_cb(cl, NULL);
-	if (!cb) {
-		rets = 0;
-		goto out;
-	}
+static int mei_cl_device_remove(struct device *dev)
+{
+	struct mei_cl_device *cldev = to_mei_cl_device(dev);
+	struct mei_cl_driver *cldrv;
 
-copy:
-	if (cb->status) {
-		rets = cb->status;
-		goto free;
+	if (!cldev || !dev->driver)
+		return 0;
+
+	if (cldev->event_cb) {
+		cldev->event_cb = NULL;
+		cancel_work_sync(&cldev->event_work);
 	}
 
-	r_length = min_t(size_t, length, cb->buf_idx);
-	memcpy(buf, cb->buf.data, r_length);
-	rets = r_length;
+	cldrv = to_mei_cl_driver(dev->driver);
+	if (!cldrv->remove) {
+		dev->driver = NULL;
 
-free:
-	mei_io_cb_free(cb);
-out:
-	mutex_unlock(&bus->device_lock);
+		return 0;
+	}
 
-	return rets;
+	return cldrv->remove(cldev);
 }
 
-ssize_t mei_cl_send(struct mei_cl_device *cldev, u8 *buf, size_t length)
+static ssize_t name_show(struct device *dev, struct device_attribute *a,
+			     char *buf)
 {
-	struct mei_cl *cl = cldev->cl;
+	struct mei_cl_device *cldev = to_mei_cl_device(dev);
+	size_t len;
 
-	if (cl == NULL)
-		return -ENODEV;
+	len = snprintf(buf, PAGE_SIZE, "%s", cldev->name);
 
-	return __mei_cl_send(cl, buf, length, 1);
+	return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
 }
-EXPORT_SYMBOL_GPL(mei_cl_send);
+static DEVICE_ATTR_RO(name);
 
-ssize_t mei_cl_recv(struct mei_cl_device *cldev, u8 *buf, size_t length)
+static ssize_t uuid_show(struct device *dev, struct device_attribute *a,
+			     char *buf)
 {
-	struct mei_cl *cl = cldev->cl;
+	struct mei_cl_device *cldev = to_mei_cl_device(dev);
+	const uuid_le *uuid = mei_me_cl_uuid(cldev->me_cl);
+	size_t len;
 
-	if (cl == NULL)
-		return -ENODEV;
+	len = snprintf(buf, PAGE_SIZE, "%pUl", uuid);
 
-	return __mei_cl_recv(cl, buf, length);
+	return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
 }
-EXPORT_SYMBOL_GPL(mei_cl_recv);
+static DEVICE_ATTR_RO(uuid);
 
-static void mei_bus_event_work(struct work_struct *work)
+static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
+			     char *buf)
 {
-	struct mei_cl_device *cldev;
-
-	cldev = container_of(work, struct mei_cl_device, event_work);
-
-	if (cldev->event_cb)
-		cldev->event_cb(cldev, cldev->events, cldev->event_context);
+	struct mei_cl_device *cldev = to_mei_cl_device(dev);
+	const uuid_le *uuid = mei_me_cl_uuid(cldev->me_cl);
+	size_t len;
 
-	cldev->events = 0;
+	len = snprintf(buf, PAGE_SIZE, "mei:%s:" MEI_CL_UUID_FMT ":",
+		cldev->name, MEI_CL_UUID_ARGS(uuid->b));
 
-	/* Prepare for the next read */
-	mei_cl_read_start(cldev->cl, 0, NULL);
+	return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
 }
+static DEVICE_ATTR_RO(modalias);
 
-int mei_cl_register_event_cb(struct mei_cl_device *cldev,
-			  mei_cl_event_cb_t event_cb, void *context)
+static struct attribute *mei_cl_dev_attrs[] = {
+	&dev_attr_name.attr,
+	&dev_attr_uuid.attr,
+	&dev_attr_modalias.attr,
+	NULL,
+};
+ATTRIBUTE_GROUPS(mei_cl_dev);
+
+static int mei_cl_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
-	if (cldev->event_cb)
-		return -EALREADY;
+	struct mei_cl_device *cldev = to_mei_cl_device(dev);
+	const uuid_le *uuid = mei_me_cl_uuid(cldev->me_cl);
 
-	cldev->events = 0;
-	cldev->event_cb = event_cb;
-	cldev->event_context = context;
-	INIT_WORK(&cldev->event_work, mei_bus_event_work);
+	if (add_uevent_var(env, "MEI_CL_UUID=%pUl", uuid))
+		return -ENOMEM;
 
-	mei_cl_read_start(cldev->cl, 0, NULL);
+	if (add_uevent_var(env, "MEI_CL_NAME=%s", cldev->name))
+		return -ENOMEM;
+
+	if (add_uevent_var(env, "MODALIAS=mei:%s:" MEI_CL_UUID_FMT ":",
+		cldev->name, MEI_CL_UUID_ARGS(uuid->b)))
+		return -ENOMEM;
 
 	return 0;
 }
-EXPORT_SYMBOL_GPL(mei_cl_register_event_cb);
 
-void *mei_cl_get_drvdata(const struct mei_cl_device *cldev)
+static struct bus_type mei_cl_bus_type = {
+	.name		= "mei",
+	.dev_groups	= mei_cl_dev_groups,
+	.match		= mei_cl_device_match,
+	.probe		= mei_cl_device_probe,
+	.remove		= mei_cl_device_remove,
+	.uevent		= mei_cl_uevent,
+};
+
+static void mei_cl_dev_release(struct device *dev)
 {
-	return dev_get_drvdata(&cldev->dev);
+	struct mei_cl_device *cldev = to_mei_cl_device(dev);
+
+	if (!cldev)
+		return;
+
+	mei_me_cl_put(cldev->me_cl);
+	kfree(cldev);
 }
-EXPORT_SYMBOL_GPL(mei_cl_get_drvdata);
 
-void mei_cl_set_drvdata(struct mei_cl_device *cldev, void *data)
+static struct device_type mei_cl_device_type = {
+	.release	= mei_cl_dev_release,
+};
+
+struct mei_cl *mei_cl_bus_find_cl_by_uuid(struct mei_device *bus,
+					 uuid_le uuid)
 {
-	dev_set_drvdata(&cldev->dev, data);
+	struct mei_cl *cl;
+
+	list_for_each_entry(cl, &bus->device_list, device_link) {
+		if (cl->cldev && cl->cldev->me_cl &&
+		    !uuid_le_cmp(uuid, *mei_me_cl_uuid(cl->cldev->me_cl)))
+			return cl;
+	}
+
+	return NULL;
 }
-EXPORT_SYMBOL_GPL(mei_cl_set_drvdata);
 
-int mei_cl_enable_device(struct mei_cl_device *cldev)
+struct mei_cl_device *mei_cl_add_device(struct mei_device *bus,
+					struct mei_me_client *me_cl,
+					struct mei_cl *cl,
+					char *name)
 {
-	int err;
-	struct mei_device *bus;
-	struct mei_cl *cl = cldev->cl;
+	struct mei_cl_device *cldev;
+	int status;
 
-	if (cl == NULL)
-		return -ENODEV;
+	cldev = kzalloc(sizeof(struct mei_cl_device), GFP_KERNEL);
+	if (!cldev)
+		return NULL;
 
-	bus = cl->dev;
+	cldev->me_cl = mei_me_cl_get(me_cl);
+	if (!cldev->me_cl) {
+		kfree(cldev);
+		return NULL;
+	}
 
-	mutex_lock(&bus->device_lock);
+	cldev->cl = cl;
+	cldev->dev.parent = bus->dev;
+	cldev->dev.bus = &mei_cl_bus_type;
+	cldev->dev.type = &mei_cl_device_type;
 
-	if (mei_cl_is_connected(cl)) {
-		mutex_unlock(&bus->device_lock);
-		dev_warn(bus->dev, "Already connected");
-		return -EBUSY;
-	}
+	strlcpy(cldev->name, name, sizeof(cldev->name));
 
-	err = mei_cl_connect(cl, cldev->me_cl, NULL);
-	if (err < 0) {
-		mutex_unlock(&bus->device_lock);
-		dev_err(bus->dev, "Could not connect to the ME client");
+	dev_set_name(&cldev->dev, "mei:%s:%pUl", name, mei_me_cl_uuid(me_cl));
 
-		return err;
+	status = device_register(&cldev->dev);
+	if (status) {
+		dev_err(bus->dev, "Failed to register MEI device\n");
+		mei_me_cl_put(cldev->me_cl);
+		kfree(cldev);
+		return NULL;
 	}
 
-	mutex_unlock(&bus->device_lock);
+	cl->cldev = cldev;
 
-	if (cldev->event_cb)
-		mei_cl_read_start(cldev->cl, 0, NULL);
+	dev_dbg(&cldev->dev, "client %s registered\n", name);
 
-	return 0;
+	return cldev;
 }
-EXPORT_SYMBOL_GPL(mei_cl_enable_device);
+EXPORT_SYMBOL_GPL(mei_cl_add_device);
 
-int mei_cl_disable_device(struct mei_cl_device *cldev)
+void mei_cl_remove_device(struct mei_cl_device *cldev)
 {
-	int err;
-	struct mei_device *bus;
-	struct mei_cl *cl = cldev->cl;
-
-	if (cl == NULL)
-		return -ENODEV;
-
-	bus = cl->dev;
-
-	cldev->event_cb = NULL;
-
-	mutex_lock(&bus->device_lock);
+	device_unregister(&cldev->dev);
+}
+EXPORT_SYMBOL_GPL(mei_cl_remove_device);
 
-	if (!mei_cl_is_connected(cl)) {
-		dev_err(bus->dev, "Already disconnected");
-		err = 0;
-		goto out;
-	}
+int __mei_cl_driver_register(struct mei_cl_driver *cldrv, struct module *owner)
+{
+	int err;
 
-	err = mei_cl_disconnect(cl);
-	if (err < 0) {
-		dev_err(bus->dev, "Could not disconnect from the ME client");
-		goto out;
-	}
+	cldrv->driver.name = cldrv->name;
+	cldrv->driver.owner = owner;
+	cldrv->driver.bus = &mei_cl_bus_type;
 
-	/* Flush queues and remove any pending read */
-	mei_cl_flush_queues(cl, NULL);
+	err = driver_register(&cldrv->driver);
+	if (err)
+		return err;
 
-out:
-	mutex_unlock(&bus->device_lock);
-	return err;
+	pr_debug("mei: driver [%s] registered\n", cldrv->driver.name);
 
+	return 0;
 }
-EXPORT_SYMBOL_GPL(mei_cl_disable_device);
+EXPORT_SYMBOL_GPL(__mei_cl_driver_register);
 
-void mei_cl_bus_rx_event(struct mei_cl *cl)
+void mei_cl_driver_unregister(struct mei_cl_driver *cldrv)
 {
-	struct mei_cl_device *cldev = cl->cldev;
-
-	if (!cldev || !cldev->event_cb)
-		return;
-
-	set_bit(MEI_CL_EVENT_RX, &cldev->events);
+	driver_unregister(&cldrv->driver);
 
-	schedule_work(&cldev->event_work);
+	pr_debug("mei: driver [%s] unregistered\n", cldrv->driver.name);
 }
+EXPORT_SYMBOL_GPL(mei_cl_driver_unregister);
 
 void mei_cl_bus_remove_devices(struct mei_device *bus)
 {
-- 
2.4.3


  parent reply	other threads:[~2015-06-15 19:01 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-06-15 18:56 [char-misc-next 00/15 V2] revamp mei bus Tomas Winkler
2015-06-15 18:56 ` [char-misc-next 01/15 V2] mei: bus: fix drivers and devices names confusion Tomas Winkler
2015-07-23  4:30   ` Greg KH
2015-06-15 18:56 ` [char-misc-next 02/15 V2] mei: bus: rename nfc.c to bus-fixup.c Tomas Winkler
2015-06-15 18:56 ` Tomas Winkler [this message]
2015-06-15 18:56 ` [char-misc-next 04/15] mei: bus: rename uevent handler to mei_cl_device_uevent Tomas Winkler
2015-06-15 18:56 ` [char-misc-next 05/15 V2] mei: bus: don't enable events implicitly in device enable Tomas Winkler
2015-06-15 18:56 ` [char-misc-next 06/15 V2] mei: bus: report if event registration failed Tomas Winkler
2015-06-15 18:56 ` [char-misc-next 07/15 V2] mei: bus: revamp device matching Tomas Winkler
2015-06-15 18:56 ` [char-misc-next 08/15 V2] mei: bus: revamp probe and remove functions Tomas Winkler
2015-06-15 18:56 ` [char-misc-next 09/15 V2] mei: bus: add reference to bus device in struct mei_cl_client Tomas Winkler
2015-06-15 18:56 ` [char-misc-next 10/15 V2] mei: bus: add me client device list infrastructure Tomas Winkler
2015-06-15 18:56 ` [char-misc-next 11/15 V2] mei: bus: enable running fixup routines before device registration Tomas Winkler
2015-06-15 18:56 ` [char-misc-next 12/15] mei: bus: blacklist the nfc info client Tomas Winkler
2015-06-15 18:56 ` [char-misc-next 13/15] mei: bus: blacklist clients by number of connections Tomas Winkler
2015-06-15 18:56 ` [char-misc-next 14/15 V2] mei: bus: simplify how we build nfc bus name Tomas Winkler
2015-06-15 18:56 ` [char-misc-next 15/15 V2] mei: bus: link client devices instead of host clients Tomas Winkler

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1434394615-3754-4-git-send-email-tomas.winkler@intel.com \
    --to=tomas.winkler@intel.com \
    --cc=arnd@arndb.de \
    --cc=gregkh@linuxfoundation.org \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®