aboutsummaryrefslogtreecommitdiff
path: root/drivers/misc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/misc')
-rw-r--r--drivers/misc/mei/bus.c99
-rw-r--r--drivers/misc/mei/mei_dev.h28
2 files changed, 115 insertions, 12 deletions
diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
index 6badfa1110e..834ceeb69cb 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;
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index d786da6aa25..c02967d0152 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -269,30 +269,36 @@ struct mei_hw_ops {
};
/* MEI bus API*/
-struct mei_cl_device *mei_cl_add_device(struct mei_device *dev,
- uuid_le uuid, char *name);
-void mei_cl_remove_device(struct mei_cl_device *device);
-
-int __mei_cl_async_send(struct mei_cl *cl, u8 *buf, size_t length);
-int __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length);
-int __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length);
/**
- * struct mei_cl_transport_ops - MEI CL device transport ops
+ * struct mei_cl_ops - MEI CL device ops
* This structure allows ME host clients to implement technology
- * specific transport layers.
+ * specific operations.
*
+ * @enable: Enable an MEI CL device. Some devices require specific
+ * HECI commands to initialize completely.
+ * @disable: Disable an MEI CL device.
* @send: Tx hook for the device. This allows ME host clients to trap
* the device driver buffers before actually physically
* pushing it to the ME.
* @recv: Rx hook for the device. This allows ME host clients to trap the
* ME buffers before forwarding them to the device driver.
*/
-struct mei_cl_transport_ops {
+struct mei_cl_ops {
+ int (*enable)(struct mei_cl_device *device);
+ int (*disable)(struct mei_cl_device *device);
int (*send)(struct mei_cl_device *device, u8 *buf, size_t length);
int (*recv)(struct mei_cl_device *device, u8 *buf, size_t length);
};
+struct mei_cl_device *mei_cl_add_device(struct mei_device *dev,
+ uuid_le uuid, char *name,
+ struct mei_cl_ops *ops);
+void mei_cl_remove_device(struct mei_cl_device *device);
+
+int __mei_cl_async_send(struct mei_cl *cl, u8 *buf, size_t length);
+int __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length);
+int __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length);
void mei_cl_bus_rx_event(struct mei_cl *cl);
int mei_cl_bus_init(void);
void mei_cl_bus_exit(void);
@@ -319,7 +325,7 @@ struct mei_cl_device {
struct mei_cl *cl;
- const struct mei_cl_transport_ops *ops;
+ const struct mei_cl_ops *ops;
struct work_struct event_work;
mei_cl_event_cb_t event_cb;