Commit e19595fc authored by Hyungwoo Yang's avatar Hyungwoo Yang Committed by Jiri Kosina

HID: intel-ish: enable raw interface to HID devices on ISH

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: default avatarHyungwoo Yang <hyungwoo.yang@intel.com>
Acked-by: default avatarSrinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Signed-off-by: default avatarJiri Kosina <jkosina@suse.cz>
parent c6400e5c
...@@ -69,13 +69,15 @@ static void process_recv(struct ishtp_cl *hid_ishtp_cl, void *recv_buf, ...@@ -69,13 +69,15 @@ static void process_recv(struct ishtp_cl *hid_ishtp_cl, void *recv_buf,
unsigned char *payload; unsigned char *payload;
struct device_info *dev_info; struct device_info *dev_info;
int i, j; int i, j;
size_t payload_len, total_len, cur_pos; size_t payload_len, total_len, cur_pos, raw_len;
int report_type; int report_type;
struct report_list *reports_list; struct report_list *reports_list;
char *reports; char *reports;
size_t report_len; size_t report_len;
struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data; struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data;
int curr_hid_dev = client_data->cur_hid_dev; 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); payload = recv_buf + sizeof(struct hostif_msg_hdr);
total_len = data_len; total_len = data_len;
...@@ -219,18 +221,31 @@ static void process_recv(struct ishtp_cl *hid_ishtp_cl, void *recv_buf, ...@@ -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 */ /* Get index of device that matches this id */
for (i = 0; i < client_data->num_hid_devices; ++i) { for (i = 0; i < client_data->num_hid_devices; ++i) {
if (recv_msg->hdr.device_id == if (recv_msg->hdr.device_id ==
client_data->hid_devices[i].dev_id) client_data->hid_devices[i].dev_id) {
if (client_data->hid_sensor_hubs[i]) { hid = client_data->hid_sensor_hubs[i];
hid_input_report( if (!hid)
client_data->hid_sensor_hubs[
i],
report_type, payload,
payload_len, 0);
ishtp_hid_wakeup(
client_data->hid_sensor_hubs[
i]);
break; 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; break;
......
...@@ -59,10 +59,46 @@ static void ishtp_hid_close(struct hid_device *hid) ...@@ -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, static int ishtp_raw_request(struct hid_device *hid, unsigned char reportnum,
__u8 *buf, size_t len, unsigned char rtype, int reqtype) __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, ...@@ -87,6 +123,7 @@ static void ishtp_hid_request(struct hid_device *hid, struct hid_report *rep,
hid_data->request_done = false; hid_data->request_done = false;
switch (reqtype) { switch (reqtype) {
case HID_REQ_GET_REPORT: case HID_REQ_GET_REPORT:
hid_data->raw_get_req = false;
hid_ishtp_get_report(hid, rep->id, rep->type); hid_ishtp_get_report(hid, rep->id, rep->type);
break; break;
case HID_REQ_SET_REPORT: case HID_REQ_SET_REPORT:
......
...@@ -159,6 +159,9 @@ struct ishtp_cl_data { ...@@ -159,6 +159,9 @@ struct ishtp_cl_data {
* @client_data: Link to the client instance * @client_data: Link to the client instance
* @hid_wait: Completion waitq * @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 * Used to tie hid hid->driver data to driver client instance
*/ */
struct ishtp_hid_data { struct ishtp_hid_data {
...@@ -166,6 +169,11 @@ struct ishtp_hid_data { ...@@ -166,6 +169,11 @@ struct ishtp_hid_data {
bool request_done; bool request_done;
struct ishtp_cl_data *client_data; struct ishtp_cl_data *client_data;
wait_queue_head_t hid_wait; 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 */ /* Interface functions between HID LL driver and ISH TP client */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment