]> Pileus Git - ~andy/linux/blobdiff - drivers/misc/mei/client.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-3.0-nmw
[~andy/linux] / drivers / misc / mei / client.c
index 1569afe935de6b19474136faed2adba2c77e318d..e310ca6ed1a34b2f78e8e02de45cb9cf222614ac 100644 (file)
@@ -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;
 
@@ -676,6 +681,111 @@ err:
        return rets;
 }
 
+/**
+ * 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
  *