summaryrefslogtreecommitdiffstats
path: root/drivers/misc/mei/bus.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/misc/mei/bus.c')
-rw-r--r--drivers/misc/mei/bus.c99
1 files changed, 98 insertions, 1 deletions
diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
index 6badfa1110e9..834ceeb69cbf 100644
--- a/drivers/misc/mei/bus.c
+++ b/drivers/misc/mei/bus.c
@@ -153,7 +153,8 @@ static struct mei_cl *mei_bus_find_mei_cl_by_uuid(struct mei_device *dev,
return NULL;
}
struct mei_cl_device *mei_cl_add_device(struct mei_device *dev,
- uuid_le uuid, char *name)
+ uuid_le uuid, char *name,
+ struct mei_cl_ops *ops)
{
struct mei_cl_device *device;
struct mei_cl *cl;
@@ -168,6 +169,7 @@ struct mei_cl_device *mei_cl_add_device(struct mei_device *dev,
return NULL;
device->cl = cl;
+ device->ops = ops;
device->dev.parent = &dev->pdev->dev;
device->dev.bus = &mei_cl_bus_type;
@@ -408,6 +410,101 @@ void mei_cl_set_drvdata(struct mei_cl_device *device, void *data)
}
EXPORT_SYMBOL_GPL(mei_cl_set_drvdata);
+int mei_cl_enable_device(struct mei_cl_device *device)
+{
+ int err;
+ struct mei_device *dev;
+ struct mei_cl *cl = device->cl;
+
+ if (cl == NULL)
+ return -ENODEV;
+
+ dev = cl->dev;
+
+ mutex_lock(&dev->device_lock);
+
+ cl->state = MEI_FILE_CONNECTING;
+
+ err = mei_cl_connect(cl, NULL);
+ if (err < 0) {
+ mutex_unlock(&dev->device_lock);
+ dev_err(&dev->pdev->dev, "Could not connect to the ME client");
+
+ return err;
+ }
+
+ mutex_unlock(&dev->device_lock);
+
+ if (device->event_cb && !cl->read_cb)
+ mei_cl_read_start(device->cl);
+
+ if (!device->ops || !device->ops->enable)
+ return 0;
+
+ return device->ops->enable(device);
+}
+EXPORT_SYMBOL_GPL(mei_cl_enable_device);
+
+int mei_cl_disable_device(struct mei_cl_device *device)
+{
+ int err;
+ struct mei_device *dev;
+ struct mei_cl *cl = device->cl;
+
+ if (cl == NULL)
+ return -ENODEV;
+
+ dev = cl->dev;
+
+ mutex_lock(&dev->device_lock);
+
+ if (cl->state != MEI_FILE_CONNECTED) {
+ mutex_unlock(&dev->device_lock);
+ dev_err(&dev->pdev->dev, "Already disconnected");
+
+ return 0;
+ }
+
+ cl->state = MEI_FILE_DISCONNECTING;
+
+ err = mei_cl_disconnect(cl);
+ if (err < 0) {
+ mutex_unlock(&dev->device_lock);
+ dev_err(&dev->pdev->dev,
+ "Could not disconnect from the ME client");
+
+ return err;
+ }
+
+ /* Flush queues and remove any pending read */
+ mei_cl_flush_queues(cl);
+
+ if (cl->read_cb) {
+ struct mei_cl_cb *cb = NULL;
+
+ cb = mei_cl_find_read_cb(cl);
+ /* Remove entry from read list */
+ if (cb)
+ list_del(&cb->list);
+
+ cb = cl->read_cb;
+ cl->read_cb = NULL;
+
+ if (cb) {
+ mei_io_cb_free(cb);
+ cb = NULL;
+ }
+ }
+
+ mutex_unlock(&dev->device_lock);
+
+ if (!device->ops || !device->ops->disable)
+ return 0;
+
+ return device->ops->disable(device);
+}
+EXPORT_SYMBOL_GPL(mei_cl_disable_device);
+
void mei_cl_bus_rx_event(struct mei_cl *cl)
{
struct mei_cl_device *device = cl->device;