diff options
author | Tomas Winkler <tomas.winkler@intel.com> | 2015-07-23 12:08:35 (GMT) |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2015-08-04 00:20:26 (GMT) |
commit | 6238299774377b12c3e24507b100b2687eb5ea32 (patch) | |
tree | 85026e36dc2a11904171591525a66da5e94d638d /drivers/misc/mei/bus.c | |
parent | a0a785c4ab91656a5413b4cd5bb8ed59f39f7446 (diff) | |
download | linux-6238299774377b12c3e24507b100b2687eb5ea32.tar.xz |
mei: bus: move driver api functions at the start of the file
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>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/misc/mei/bus.c')
-rw-r--r-- | drivers/misc/mei/bus.c | 613 |
1 files changed, 351 insertions, 262 deletions
diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c index 18c37af..6ea8a40 100644 --- a/drivers/misc/mei/bus.c +++ b/drivers/misc/mei/bus.c @@ -30,263 +30,16 @@ #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) -{ - 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; - - uuid = mei_me_cl_uuid(cldev->me_cl); - name = cldev->name; - - if (!cldrv || !cldrv->id_table) - return 0; - - id = cldrv->id_table; - - while (uuid_le_cmp(NULL_UUID_LE, id->uuid)) { - - if (!uuid_le_cmp(*uuid, id->uuid)) { - if (id->name[0]) { - if (!strncmp(name, id->name, sizeof(id->name))) - return 1; - } else { - return 1; - } - } - - id++; - } - - return 0; -} - -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; - - if (!cldev) - return 0; - - 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); -} - -static int mei_cl_device_remove(struct device *dev) -{ - struct mei_cl_device *cldev = to_mei_cl_device(dev); - struct mei_cl_driver *cldrv; - - if (!cldev || !dev->driver) - return 0; - - if (cldev->event_cb) { - cldev->event_cb = NULL; - cancel_work_sync(&cldev->event_work); - } - - cldrv = to_mei_cl_driver(dev->driver); - if (!cldrv->remove) { - dev->driver = NULL; - - return 0; - } - - return cldrv->remove(cldev); -} - -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; - - len = snprintf(buf, PAGE_SIZE, "%s", cldev->name); - - return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len; -} -static DEVICE_ATTR_RO(name); - -static ssize_t uuid_show(struct device *dev, struct device_attribute *a, - char *buf) -{ - struct mei_cl_device *cldev = to_mei_cl_device(dev); - const uuid_le *uuid = mei_me_cl_uuid(cldev->me_cl); - size_t len; - - len = snprintf(buf, PAGE_SIZE, "%pUl", uuid); - - return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len; -} -static DEVICE_ATTR_RO(uuid); - -static ssize_t modalias_show(struct device *dev, struct device_attribute *a, - char *buf) -{ - struct mei_cl_device *cldev = to_mei_cl_device(dev); - const uuid_le *uuid = mei_me_cl_uuid(cldev->me_cl); - size_t len; - - len = snprintf(buf, PAGE_SIZE, "mei:%s:" MEI_CL_UUID_FMT ":", - cldev->name, MEI_CL_UUID_ARGS(uuid->b)); - - return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len; -} -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); - -static int mei_cl_uevent(struct device *dev, struct kobj_uevent_env *env) -{ - struct mei_cl_device *cldev = to_mei_cl_device(dev); - const uuid_le *uuid = mei_me_cl_uuid(cldev->me_cl); - - if (add_uevent_var(env, "MEI_CL_UUID=%pUl", uuid)) - return -ENOMEM; - - 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; -} - -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) -{ - struct mei_cl_device *cldev = to_mei_cl_device(dev); - - if (!cldev) - 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; - } - - return NULL; -} - -struct mei_cl_device *mei_cl_add_device(struct mei_device *bus, - struct mei_me_client *me_cl, - struct mei_cl *cl, - char *name) -{ - 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)); - - 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; - } - - cl->cldev = cldev; - - dev_dbg(&cldev->dev, "client %s registered\n", name); - - return cldev; -} -EXPORT_SYMBOL_GPL(mei_cl_add_device); - -void mei_cl_remove_device(struct mei_cl_device *cldev) -{ - device_unregister(&cldev->dev); -} -EXPORT_SYMBOL_GPL(mei_cl_remove_device); - -int __mei_cl_driver_register(struct mei_cl_driver *cldrv, struct module *owner) -{ - int err; - - cldrv->driver.name = cldrv->name; - cldrv->driver.owner = owner; - cldrv->driver.bus = &mei_cl_bus_type; - - err = driver_register(&cldrv->driver); - if (err) - return err; - - pr_debug("mei: driver [%s] registered\n", cldrv->driver.name); - - return 0; -} -EXPORT_SYMBOL_GPL(__mei_cl_driver_register); - -void mei_cl_driver_unregister(struct mei_cl_driver *cldrv) -{ - driver_unregister(&cldrv->driver); - - pr_debug("mei: driver [%s] unregistered\n", cldrv->driver.name); -} -EXPORT_SYMBOL_GPL(mei_cl_driver_unregister); - +/** + * __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) { @@ -334,6 +87,15 @@ out: return rets; } +/** + * __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_device *bus; @@ -356,6 +118,7 @@ ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length) if (rets && rets != -EBUSY) goto out; + /* wait on event only if there is no other waiter */ if (list_empty(&cl->rd_completed) && !waitqueue_active(&cl->rx_wait)) { mutex_unlock(&bus->device_lock); @@ -401,6 +164,15 @@ out: return rets; } +/** + * 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 *cl = cldev->cl; @@ -412,6 +184,15 @@ ssize_t mei_cl_send(struct mei_cl_device *cldev, u8 *buf, size_t length) } EXPORT_SYMBOL_GPL(mei_cl_send); +/** + * 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 *cl = cldev->cl; @@ -423,6 +204,12 @@ ssize_t mei_cl_recv(struct mei_cl_device *cldev, u8 *buf, size_t length) } EXPORT_SYMBOL_GPL(mei_cl_recv); +/** + * 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; @@ -438,6 +225,34 @@ static void mei_bus_event_work(struct work_struct *work) mei_cl_read_start(cldev->cl, 0, NULL); } +/** + * 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 = cl->cldev; + + if (!cldev || !cldev->event_cb) + return; + + set_bit(MEI_CL_EVENT_RX, &cldev->events); + + schedule_work(&cldev->event_work); +} + +/** + * 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) { @@ -455,18 +270,39 @@ int mei_cl_register_event_cb(struct mei_cl_device *cldev, } EXPORT_SYMBOL_GPL(mei_cl_register_event_cb); +/** + * 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_get_drvdata); +/** + * 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) { dev_set_drvdata(&cldev->dev, data); } EXPORT_SYMBOL_GPL(mei_cl_set_drvdata); +/** + * 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; @@ -503,6 +339,14 @@ int mei_cl_enable_device(struct mei_cl_device *cldev) } EXPORT_SYMBOL_GPL(mei_cl_enable_device); +/** + * 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; @@ -540,17 +384,262 @@ out: } EXPORT_SYMBOL_GPL(mei_cl_disable_device); -void mei_cl_bus_rx_event(struct mei_cl *cl) +static int mei_cl_device_match(struct device *dev, struct device_driver *drv) { - struct mei_cl_device *cldev = cl->cldev; + 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 || !cldev->event_cb) + if (!cldev) + return 0; + + uuid = mei_me_cl_uuid(cldev->me_cl); + name = cldev->name; + + if (!cldrv || !cldrv->id_table) + return 0; + + id = cldrv->id_table; + + while (uuid_le_cmp(NULL_UUID_LE, id->uuid)) { + + if (!uuid_le_cmp(*uuid, id->uuid)) { + if (id->name[0]) { + if (!strncmp(name, id->name, sizeof(id->name))) + return 1; + } else { + return 1; + } + } + + id++; + } + + return 0; +} + +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; + + if (!cldev) + return 0; + + 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); +} + +static int mei_cl_device_remove(struct device *dev) +{ + struct mei_cl_device *cldev = to_mei_cl_device(dev); + struct mei_cl_driver *cldrv; + + if (!cldev || !dev->driver) + return 0; + + if (cldev->event_cb) { + cldev->event_cb = NULL; + cancel_work_sync(&cldev->event_work); + } + + cldrv = to_mei_cl_driver(dev->driver); + if (!cldrv->remove) { + dev->driver = NULL; + + return 0; + } + + return cldrv->remove(cldev); +} + +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; + + len = snprintf(buf, PAGE_SIZE, "%s", cldev->name); + + return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len; +} +static DEVICE_ATTR_RO(name); + +static ssize_t uuid_show(struct device *dev, struct device_attribute *a, + char *buf) +{ + struct mei_cl_device *cldev = to_mei_cl_device(dev); + const uuid_le *uuid = mei_me_cl_uuid(cldev->me_cl); + size_t len; + + len = snprintf(buf, PAGE_SIZE, "%pUl", uuid); + + return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len; +} +static DEVICE_ATTR_RO(uuid); + +static ssize_t modalias_show(struct device *dev, struct device_attribute *a, + char *buf) +{ + struct mei_cl_device *cldev = to_mei_cl_device(dev); + const uuid_le *uuid = mei_me_cl_uuid(cldev->me_cl); + size_t len; + + len = snprintf(buf, PAGE_SIZE, "mei:%s:" MEI_CL_UUID_FMT ":", + cldev->name, MEI_CL_UUID_ARGS(uuid->b)); + + return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len; +} +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); + +static int mei_cl_uevent(struct device *dev, struct kobj_uevent_env *env) +{ + struct mei_cl_device *cldev = to_mei_cl_device(dev); + const uuid_le *uuid = mei_me_cl_uuid(cldev->me_cl); + + if (add_uevent_var(env, "MEI_CL_UUID=%pUl", uuid)) + return -ENOMEM; + + 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; +} + +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) +{ + struct mei_cl_device *cldev = to_mei_cl_device(dev); + + if (!cldev) return; - set_bit(MEI_CL_EVENT_RX, &cldev->events); + mei_me_cl_put(cldev->me_cl); + kfree(cldev); +} - schedule_work(&cldev->event_work); +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; + } + + return NULL; +} + +struct mei_cl_device *mei_cl_add_device(struct mei_device *bus, + struct mei_me_client *me_cl, + struct mei_cl *cl, + char *name) +{ + 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)); + + 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; + } + + cl->cldev = cldev; + + dev_dbg(&cldev->dev, "client %s registered\n", name); + + return cldev; +} +EXPORT_SYMBOL_GPL(mei_cl_add_device); + +void mei_cl_remove_device(struct mei_cl_device *cldev) +{ + device_unregister(&cldev->dev); +} +EXPORT_SYMBOL_GPL(mei_cl_remove_device); + +int __mei_cl_driver_register(struct mei_cl_driver *cldrv, struct module *owner) +{ + int err; + + cldrv->driver.name = cldrv->name; + cldrv->driver.owner = owner; + cldrv->driver.bus = &mei_cl_bus_type; + + err = driver_register(&cldrv->driver); + if (err) + return err; + + pr_debug("mei: driver [%s] registered\n", cldrv->driver.name); + + return 0; } +EXPORT_SYMBOL_GPL(__mei_cl_driver_register); + +void mei_cl_driver_unregister(struct mei_cl_driver *cldrv) +{ + driver_unregister(&cldrv->driver); + + pr_debug("mei: driver [%s] unregistered\n", cldrv->driver.name); +} +EXPORT_SYMBOL_GPL(mei_cl_driver_unregister); int __init mei_cl_bus_init(void) { |