HID: intel-ish: enable raw interface to HID devices on ISH
authorHyungwoo Yang <hyungwoo.yang@intel.com>
Mon, 4 Mar 2019 20:48:54 +0000 (12:48 -0800)
committerJiri Kosina <jkosina@suse.cz>
Mon, 18 Mar 2019 13:46:20 +0000 (14:46 +0100)
Raw interface is often used to update firmwares in HID devices.
We are enabling the interface to support in-field firmware update
for the HID devices attached to ISH.

Signed-off-by: Hyungwoo Yang <hyungwoo.yang@intel.com>
Acked-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
drivers/hid/intel-ish-hid/ishtp-hid-client.c
drivers/hid/intel-ish-hid/ishtp-hid.c
drivers/hid/intel-ish-hid/ishtp-hid.h

index 30fe0c5e6fade934c882d0d049010d696c2b62f3..58773a3b5150c04425da0e895dc6c33cc51076f2 100644 (file)
@@ -69,13 +69,15 @@ static void process_recv(struct ishtp_cl *hid_ishtp_cl, void *recv_buf,
        unsigned char *payload;
        struct device_info *dev_info;
        int i, j;
-       size_t  payload_len, total_len, cur_pos;
+       size_t  payload_len, total_len, cur_pos, raw_len;
        int report_type;
        struct report_list *reports_list;
        char *reports;
        size_t report_len;
        struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data;
        int curr_hid_dev = client_data->cur_hid_dev;
+       struct ishtp_hid_data *hid_data = NULL;
+       struct hid_device *hid = NULL;
 
        payload = recv_buf + sizeof(struct hostif_msg_hdr);
        total_len = data_len;
@@ -219,18 +221,31 @@ do_get_report:
                        /* Get index of device that matches this id */
                        for (i = 0; i < client_data->num_hid_devices; ++i) {
                                if (recv_msg->hdr.device_id ==
-                                       client_data->hid_devices[i].dev_id)
-                                       if (client_data->hid_sensor_hubs[i]) {
-                                               hid_input_report(
-                                               client_data->hid_sensor_hubs[
-                                                                       i],
-                                               report_type, payload,
-                                               payload_len, 0);
-                                               ishtp_hid_wakeup(
-                                               client_data->hid_sensor_hubs[
-                                                       i]);
+                                         client_data->hid_devices[i].dev_id) {
+                                       hid = client_data->hid_sensor_hubs[i];
+                                       if (!hid)
                                                break;
+
+                                       hid_data = hid->driver_data;
+                                       if (hid_data->raw_get_req) {
+                                               raw_len =
+                                                 (hid_data->raw_buf_size <
+                                                               payload_len) ?
+                                                 hid_data->raw_buf_size :
+                                                 payload_len;
+
+                                               memcpy(hid_data->raw_buf,
+                                                      payload, raw_len);
+                                       } else {
+                                               hid_input_report
+                                                       (hid, report_type,
+                                                        payload, payload_len,
+                                                        0);
                                        }
+
+                                       ishtp_hid_wakeup(hid);
+                                       break;
+                               }
                        }
                        break;
 
index bc4c536f3c0d7d0c26e3cba6418558b5628547a6..5c7e127b0483b4b1b1766ef7cda1e424e5c90928 100644 (file)
@@ -59,10 +59,46 @@ static void ishtp_hid_close(struct hid_device *hid)
 {
 }
 
-static int ishtp_raw_request(struct hid_device *hdev, unsigned char reportnum,
-       __u8 *buf, size_t len, unsigned char rtype, int reqtype)
+static int ishtp_raw_request(struct hid_device *hid, unsigned char reportnum,
+                            __u8 *buf, size_t len, unsigned char rtype,
+                            int reqtype)
 {
-       return 0;
+       struct ishtp_hid_data *hid_data =  hid->driver_data;
+       char *ishtp_buf = NULL;
+       size_t ishtp_buf_len;
+       unsigned int header_size = sizeof(struct hostif_msg);
+
+       if (rtype == HID_OUTPUT_REPORT)
+               return -EINVAL;
+
+       hid_data->request_done = false;
+       switch (reqtype) {
+       case HID_REQ_GET_REPORT:
+               hid_data->raw_buf = buf;
+               hid_data->raw_buf_size = len;
+               hid_data->raw_get_req = true;
+
+               hid_ishtp_get_report(hid, reportnum, rtype);
+               break;
+       case HID_REQ_SET_REPORT:
+               /*
+                * Spare 7 bytes for 64b accesses through
+                * get/put_unaligned_le64()
+                */
+               ishtp_buf_len = len + header_size;
+               ishtp_buf = kzalloc(ishtp_buf_len + 7, GFP_KERNEL);
+               if (!ishtp_buf)
+                       return -ENOMEM;
+
+               memcpy(ishtp_buf + header_size, buf, len);
+               hid_ishtp_set_feature(hid, ishtp_buf, ishtp_buf_len, reportnum);
+               kfree(ishtp_buf);
+               break;
+       }
+
+       hid_hw_wait(hid);
+
+       return len;
 }
 
 /**
@@ -87,6 +123,7 @@ static void ishtp_hid_request(struct hid_device *hid, struct hid_report *rep,
        hid_data->request_done = false;
        switch (reqtype) {
        case HID_REQ_GET_REPORT:
+               hid_data->raw_get_req = false;
                hid_ishtp_get_report(hid, rep->id, rep->type);
                break;
        case HID_REQ_SET_REPORT:
index 1cd07a441cd4026c22dd1634eaeb92c26fb6b639..40663639e43bf5feaf2e2531af62b3f33c889bfd 100644 (file)
@@ -159,6 +159,9 @@ struct ishtp_cl_data {
  * @client_data:       Link to the client instance
  * @hid_wait:          Completion waitq
  *
+ * @raw_get_req:       Flag indicating raw get request ongoing
+ * @raw_buf:           raw request buffer filled on receiving get report
+ * @raw_buf_size:      raw request buffer size
  * Used to tie hid hid->driver data to driver client instance
  */
 struct ishtp_hid_data {
@@ -166,6 +169,11 @@ struct ishtp_hid_data {
        bool request_done;
        struct ishtp_cl_data *client_data;
        wait_queue_head_t hid_wait;
+
+       /* raw request */
+       bool raw_get_req;
+       u8 *raw_buf;
+       size_t raw_buf_size;
 };
 
 /* Interface functions between HID LL driver and ISH TP client */