Message ID | 1551732534-4937-1-git-send-email-hyungwoo.yang@intel.com (mailing list archive) |
---|---|
State | Mainlined |
Commit | e19595fcabb5d09071b9ddb302be98715b77b1b9 |
Delegated to: | Jiri Kosina |
Headers | show |
Series | [1/1] HID: intel-ish: enable raw interface to HID devices on ISH | expand |
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@intel.com> Acked-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com> 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 */
On Tue, 5 Mar 2019, Srinivas Pandruvada wrote: > 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@intel.com> > Acked-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com> > > But this is a new feature, so it can only go to v5.2+ kernel. Applied, thanks.
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 */
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> --- 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(-)