summaryrefslogtreecommitdiffstats
path: root/drivers/misc/mei/client.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/misc/mei/client.c')
-rw-r--r--drivers/misc/mei/client.c140
1 files changed, 125 insertions, 15 deletions
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index 1569afe935d..e310ca6ed1a 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -109,7 +109,7 @@ void mei_io_cb_free(struct mei_cl_cb *cb)
* mei_io_cb_init - allocate and initialize io callback
*
* @cl - mei client
- * @file: pointer to file structure
+ * @fp: pointer to file structure
*
* returns mei_cl_cb pointer or NULL;
*/
@@ -132,8 +132,8 @@ struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, struct file *fp)
/**
* mei_io_cb_alloc_req_buf - allocate request buffer
*
- * @cb - io callback structure
- * @size: size of the buffer
+ * @cb: io callback structure
+ * @length: size of the buffer
*
* returns 0 on success
* -EINVAL if cb is NULL
@@ -154,10 +154,10 @@ int mei_io_cb_alloc_req_buf(struct mei_cl_cb *cb, size_t length)
return 0;
}
/**
- * mei_io_cb_alloc_req_buf - allocate respose buffer
+ * mei_io_cb_alloc_resp_buf - allocate respose buffer
*
- * @cb - io callback structure
- * @size: size of the buffer
+ * @cb: io callback structure
+ * @length: size of the buffer
*
* returns 0 on success
* -EINVAL if cb is NULL
@@ -183,7 +183,6 @@ int mei_io_cb_alloc_resp_buf(struct mei_cl_cb *cb, size_t length)
/**
* mei_cl_flush_queues - flushes queue lists belonging to cl.
*
- * @dev: the device structure
* @cl: host client
*/
int mei_cl_flush_queues(struct mei_cl *cl)
@@ -216,6 +215,7 @@ void mei_cl_init(struct mei_cl *cl, struct mei_device *dev)
init_waitqueue_head(&cl->rx_wait);
init_waitqueue_head(&cl->tx_wait);
INIT_LIST_HEAD(&cl->link);
+ INIT_LIST_HEAD(&cl->device_link);
cl->reading_state = MEI_IDLE;
cl->writing_state = MEI_IDLE;
cl->dev = dev;
@@ -243,7 +243,8 @@ struct mei_cl *mei_cl_allocate(struct mei_device *dev)
/**
* mei_cl_find_read_cb - find this cl's callback in the read list
*
- * @dev: device structure
+ * @cl: host client
+ *
* returns cb on success, NULL on error
*/
struct mei_cl_cb *mei_cl_find_read_cb(struct mei_cl *cl)
@@ -262,6 +263,7 @@ struct mei_cl_cb *mei_cl_find_read_cb(struct mei_cl *cl)
*
* @cl - host client
* @id - fixed host id or -1 for genereting one
+ *
* returns 0 on success
* -EINVAL on incorrect values
* -ENONET if client not found
@@ -301,7 +303,7 @@ int mei_cl_link(struct mei_cl *cl, int id)
/**
* mei_cl_unlink - remove me_cl from the list
*
- * @dev: the device structure
+ * @cl: host client
*/
int mei_cl_unlink(struct mei_cl *cl)
{
@@ -357,6 +359,9 @@ void mei_host_client_init(struct work_struct *work)
mei_amthif_host_init(dev);
else if (!uuid_le_cmp(client_props->protocol_name, mei_wd_guid))
mei_wd_host_init(dev);
+ else if (!uuid_le_cmp(client_props->protocol_name, mei_nfc_guid))
+ mei_nfc_host_init(dev);
+
}
dev->dev_state = MEI_DEV_ENABLED;
@@ -534,7 +539,6 @@ out:
/**
* mei_cl_flow_ctrl_creds - checks flow_control credits for cl.
*
- * @dev: the device structure
* @cl: private data of the file object
*
* returns 1 if mei_flow_ctrl_creds >0, 0 - otherwise.
@@ -575,8 +579,8 @@ int mei_cl_flow_ctrl_creds(struct mei_cl *cl)
/**
* mei_cl_flow_ctrl_reduce - reduces flow_control.
*
- * @dev: the device structure
* @cl: private data of the file object
+ *
* @returns
* 0 on success
* -ENOENT when me client is not found
@@ -614,13 +618,13 @@ int mei_cl_flow_ctrl_reduce(struct mei_cl *cl)
}
/**
- * mei_cl_start_read - the start read client message function.
+ * mei_cl_read_start - the start read client message function.
*
* @cl: host client
*
* returns 0 on success, <0 on failure.
*/
-int mei_cl_read_start(struct mei_cl *cl)
+int mei_cl_read_start(struct mei_cl *cl, size_t length)
{
struct mei_device *dev;
struct mei_cl_cb *cb;
@@ -653,8 +657,9 @@ int mei_cl_read_start(struct mei_cl *cl)
if (!cb)
return -ENOMEM;
- rets = mei_io_cb_alloc_resp_buf(cb,
- dev->me_clients[i].props.max_msg_length);
+ /* always allocate at least client max message */
+ length = max_t(size_t, length, dev->me_clients[i].props.max_msg_length);
+ rets = mei_io_cb_alloc_resp_buf(cb, length);
if (rets)
goto err;
@@ -677,6 +682,111 @@ err:
}
/**
+ * mei_cl_write - submit a write cb to mei device
+ assumes device_lock is locked
+ *
+ * @cl: host client
+ * @cl: write callback with filled data
+ *
+ * returns numbe of bytes sent on success, <0 on failure.
+ */
+int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking)
+{
+ struct mei_device *dev;
+ struct mei_msg_data *buf;
+ struct mei_msg_hdr mei_hdr;
+ int rets;
+
+
+ if (WARN_ON(!cl || !cl->dev))
+ return -ENODEV;
+
+ if (WARN_ON(!cb))
+ return -EINVAL;
+
+ dev = cl->dev;
+
+
+ buf = &cb->request_buffer;
+
+ dev_dbg(&dev->pdev->dev, "mei_cl_write %d\n", buf->size);
+
+
+ cb->fop_type = MEI_FOP_WRITE;
+
+ rets = mei_cl_flow_ctrl_creds(cl);
+ if (rets < 0)
+ goto err;
+
+ /* Host buffer is not ready, we queue the request */
+ if (rets == 0 || !dev->hbuf_is_ready) {
+ cb->buf_idx = 0;
+ /* unseting complete will enqueue the cb for write */
+ mei_hdr.msg_complete = 0;
+ cl->writing_state = MEI_WRITING;
+ rets = buf->size;
+ goto out;
+ }
+
+ dev->hbuf_is_ready = false;
+
+ /* Check for a maximum length */
+ if (buf->size > mei_hbuf_max_len(dev)) {
+ mei_hdr.length = mei_hbuf_max_len(dev);
+ mei_hdr.msg_complete = 0;
+ } else {
+ mei_hdr.length = buf->size;
+ mei_hdr.msg_complete = 1;
+ }
+
+ mei_hdr.host_addr = cl->host_client_id;
+ mei_hdr.me_addr = cl->me_client_id;
+ mei_hdr.reserved = 0;
+
+ dev_dbg(&dev->pdev->dev, "write " MEI_HDR_FMT "\n",
+ MEI_HDR_PRM(&mei_hdr));
+
+
+ if (mei_write_message(dev, &mei_hdr, buf->data)) {
+ rets = -EIO;
+ goto err;
+ }
+
+ cl->writing_state = MEI_WRITING;
+ cb->buf_idx = mei_hdr.length;
+
+ rets = buf->size;
+out:
+ if (mei_hdr.msg_complete) {
+ if (mei_cl_flow_ctrl_reduce(cl)) {
+ rets = -ENODEV;
+ goto err;
+ }
+ list_add_tail(&cb->list, &dev->write_waiting_list.list);
+ } else {
+ list_add_tail(&cb->list, &dev->write_list.list);
+ }
+
+
+ if (blocking && cl->writing_state != MEI_WRITE_COMPLETE) {
+
+ mutex_unlock(&dev->device_lock);
+ if (wait_event_interruptible(cl->tx_wait,
+ cl->writing_state == MEI_WRITE_COMPLETE)) {
+ if (signal_pending(current))
+ rets = -EINTR;
+ else
+ rets = -ERESTARTSYS;
+ }
+ mutex_lock(&dev->device_lock);
+ }
+err:
+ return rets;
+}
+
+
+
+/**
* mei_cl_all_disconnect - disconnect forcefully all connected clients
*
* @dev - mei device