diff mbox series

[1/1] HID: intel-ish: enable raw interface to HID devices on ISH

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

Commit Message

Hyungwoo Yang March 4, 2019, 8:48 p.m. UTC
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(-)

Comments

srinivas pandruvada March 5, 2019, 6:19 p.m. UTC | #1
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 */
Jiri Kosina March 18, 2019, 1:46 p.m. UTC | #2
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 mbox series

Patch

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 */