On Mon, 2019-03-04 at 12:48 -0800, Hyungwoo Yang wrote: > 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@xxxxxxxxx> Acked-by: Srinivas Pandruvada <srinivas.pandruvada@xxxxxxxxxxxxxxx> But this is a new feature, so it can only go to v5.2+ kernel. Thanks, Srinivas > --- > drivers/hid/intel-ish-hid/ishtp-hid-client.c | 37 +++++++++++++++++- > ------ > drivers/hid/intel-ish-hid/ishtp-hid.c | 43 > ++++++++++++++++++++++++++-- > drivers/hid/intel-ish-hid/ishtp-hid.h | 8 ++++++ > 3 files changed, 74 insertions(+), 14 deletions(-) > > diff --git a/drivers/hid/intel-ish-hid/ishtp-hid-client.c > b/drivers/hid/intel-ish-hid/ishtp-hid-client.c > index 30fe0c5..58773a3 100644 > --- a/drivers/hid/intel-ish-hid/ishtp-hid-client.c > +++ b/drivers/hid/intel-ish-hid/ishtp-hid-client.c > @@ -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 @@ static void process_recv(struct ishtp_cl > *hid_ishtp_cl, void *recv_buf, > /* 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; > > diff --git a/drivers/hid/intel-ish-hid/ishtp-hid.c > b/drivers/hid/intel-ish-hid/ishtp-hid.c > index bc4c536..5c7e127 100644 > --- a/drivers/hid/intel-ish-hid/ishtp-hid.c > +++ b/drivers/hid/intel-ish-hid/ishtp-hid.c > @@ -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: > diff --git a/drivers/hid/intel-ish-hid/ishtp-hid.h > b/drivers/hid/intel-ish-hid/ishtp-hid.h > index 1cd07a4..40663639 100644 > --- a/drivers/hid/intel-ish-hid/ishtp-hid.h > +++ b/drivers/hid/intel-ish-hid/ishtp-hid.h > @@ -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 */