1
0
Fork 0

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: Hyungwoo Yang <hyungwoo.yang@intel.com>
Acked-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
hifive-unleashed-5.2
Hyungwoo Yang 2019-03-04 12:48:54 -08:00 committed by Jiri Kosina
parent c6400e5cef
commit e19595fcab
3 changed files with 74 additions and 14 deletions

View 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;

View 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:

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