12025cf9eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
20b28cb4bSSrinivas Pandruvada /*
30b28cb4bSSrinivas Pandruvada * ISHTP client driver for HID (ISH)
40b28cb4bSSrinivas Pandruvada *
50b28cb4bSSrinivas Pandruvada * Copyright (c) 2014-2016, Intel Corporation.
60b28cb4bSSrinivas Pandruvada */
70b28cb4bSSrinivas Pandruvada
80b28cb4bSSrinivas Pandruvada #include <linux/module.h>
90b28cb4bSSrinivas Pandruvada #include <linux/hid.h>
107ab21842SSrinivas Pandruvada #include <linux/intel-ish-client-if.h>
110b28cb4bSSrinivas Pandruvada #include <linux/sched.h>
120b28cb4bSSrinivas Pandruvada #include "ishtp-hid.h"
130b28cb4bSSrinivas Pandruvada
14a2e7aa05SLee Jones /* ISH Transport protocol (ISHTP in short) GUID */
15bf9167a8SArnd Bergmann static const struct ishtp_device_id hid_ishtp_id_table[] = {
16bf9167a8SArnd Bergmann { .guid = GUID_INIT(0x33AECD58, 0xB679, 0x4E54,
17bf9167a8SArnd Bergmann 0x9B, 0xD9, 0xA0, 0x4D, 0x34, 0xF0, 0xC2, 0x26), },
18bf9167a8SArnd Bergmann { }
19bf9167a8SArnd Bergmann };
20bf9167a8SArnd Bergmann MODULE_DEVICE_TABLE(ishtp, hid_ishtp_id_table);
21a2e7aa05SLee Jones
220b28cb4bSSrinivas Pandruvada /* Rx ring buffer pool size */
230b28cb4bSSrinivas Pandruvada #define HID_CL_RX_RING_SIZE 32
240b28cb4bSSrinivas Pandruvada #define HID_CL_TX_RING_SIZE 16
250b28cb4bSSrinivas Pandruvada
267ab21842SSrinivas Pandruvada #define cl_data_to_dev(client_data) ishtp_device(client_data->cl_device)
277ab21842SSrinivas Pandruvada
280b28cb4bSSrinivas Pandruvada /**
29fb42b1daSLee Jones * report_bad_packet() - Report bad packets
300b28cb4bSSrinivas Pandruvada * @hid_ishtp_cl: Client instance to get stats
310b28cb4bSSrinivas Pandruvada * @recv_buf: Raw received host interface message
320b28cb4bSSrinivas Pandruvada * @cur_pos: Current position index in payload
330b28cb4bSSrinivas Pandruvada * @payload_len: Length of payload expected
340b28cb4bSSrinivas Pandruvada *
350b28cb4bSSrinivas Pandruvada * Dumps error in case bad packet is received
360b28cb4bSSrinivas Pandruvada */
report_bad_packet(struct ishtp_cl * hid_ishtp_cl,void * recv_buf,size_t cur_pos,size_t payload_len)370b28cb4bSSrinivas Pandruvada static void report_bad_packet(struct ishtp_cl *hid_ishtp_cl, void *recv_buf,
380b28cb4bSSrinivas Pandruvada size_t cur_pos, size_t payload_len)
390b28cb4bSSrinivas Pandruvada {
400b28cb4bSSrinivas Pandruvada struct hostif_msg *recv_msg = recv_buf;
4129b06d12SSrinivas Pandruvada struct ishtp_cl_data *client_data = ishtp_get_client_data(hid_ishtp_cl);
420b28cb4bSSrinivas Pandruvada
437ab21842SSrinivas Pandruvada dev_err(cl_data_to_dev(client_data), "[hid-ish]: BAD packet %02X\n"
440b28cb4bSSrinivas Pandruvada "total_bad=%u cur_pos=%u\n"
450b28cb4bSSrinivas Pandruvada "[%02X %02X %02X %02X]\n"
460b28cb4bSSrinivas Pandruvada "payload_len=%u\n"
470b28cb4bSSrinivas Pandruvada "multi_packet_cnt=%u\n"
480b28cb4bSSrinivas Pandruvada "is_response=%02X\n",
490b28cb4bSSrinivas Pandruvada recv_msg->hdr.command, client_data->bad_recv_cnt,
500b28cb4bSSrinivas Pandruvada (unsigned int)cur_pos,
510b28cb4bSSrinivas Pandruvada ((unsigned char *)recv_msg)[0], ((unsigned char *)recv_msg)[1],
520b28cb4bSSrinivas Pandruvada ((unsigned char *)recv_msg)[2], ((unsigned char *)recv_msg)[3],
530b28cb4bSSrinivas Pandruvada (unsigned int)payload_len, client_data->multi_packet_cnt,
540b28cb4bSSrinivas Pandruvada recv_msg->hdr.command & ~CMD_MASK);
550b28cb4bSSrinivas Pandruvada }
560b28cb4bSSrinivas Pandruvada
570b28cb4bSSrinivas Pandruvada /**
580b28cb4bSSrinivas Pandruvada * process_recv() - Received and parse incoming packet
590b28cb4bSSrinivas Pandruvada * @hid_ishtp_cl: Client instance to get stats
600b28cb4bSSrinivas Pandruvada * @recv_buf: Raw received host interface message
610b28cb4bSSrinivas Pandruvada * @data_len: length of the message
620b28cb4bSSrinivas Pandruvada *
630b28cb4bSSrinivas Pandruvada * Parse the incoming packet. If it is a response packet then it will update
640b28cb4bSSrinivas Pandruvada * per instance flags and wake up the caller waiting to for the response.
650b28cb4bSSrinivas Pandruvada */
process_recv(struct ishtp_cl * hid_ishtp_cl,void * recv_buf,size_t data_len)660b28cb4bSSrinivas Pandruvada static void process_recv(struct ishtp_cl *hid_ishtp_cl, void *recv_buf,
670b28cb4bSSrinivas Pandruvada size_t data_len)
680b28cb4bSSrinivas Pandruvada {
690b28cb4bSSrinivas Pandruvada struct hostif_msg *recv_msg;
700b28cb4bSSrinivas Pandruvada unsigned char *payload;
710b28cb4bSSrinivas Pandruvada struct device_info *dev_info;
720b28cb4bSSrinivas Pandruvada int i, j;
73e19595fcSHyungwoo Yang size_t payload_len, total_len, cur_pos, raw_len;
740b28cb4bSSrinivas Pandruvada int report_type;
750b28cb4bSSrinivas Pandruvada struct report_list *reports_list;
760b28cb4bSSrinivas Pandruvada char *reports;
770b28cb4bSSrinivas Pandruvada size_t report_len;
7829b06d12SSrinivas Pandruvada struct ishtp_cl_data *client_data = ishtp_get_client_data(hid_ishtp_cl);
790b28cb4bSSrinivas Pandruvada int curr_hid_dev = client_data->cur_hid_dev;
80e19595fcSHyungwoo Yang struct ishtp_hid_data *hid_data = NULL;
81e19595fcSHyungwoo Yang struct hid_device *hid = NULL;
820b28cb4bSSrinivas Pandruvada
8337ba3c35SHans de Goede payload = recv_buf + sizeof(struct hostif_msg_hdr);
8437ba3c35SHans de Goede total_len = data_len;
8537ba3c35SHans de Goede cur_pos = 0;
8637ba3c35SHans de Goede
8737ba3c35SHans de Goede do {
8837ba3c35SHans de Goede if (cur_pos + sizeof(struct hostif_msg) > total_len) {
897ab21842SSrinivas Pandruvada dev_err(cl_data_to_dev(client_data),
900b28cb4bSSrinivas Pandruvada "[hid-ish]: error, received %u which is less than data header %u\n",
910b28cb4bSSrinivas Pandruvada (unsigned int)data_len,
920b28cb4bSSrinivas Pandruvada (unsigned int)sizeof(struct hostif_msg_hdr));
930b28cb4bSSrinivas Pandruvada ++client_data->bad_recv_cnt;
9429b06d12SSrinivas Pandruvada ish_hw_reset(ishtp_get_ishtp_device(hid_ishtp_cl));
9537ba3c35SHans de Goede break;
960b28cb4bSSrinivas Pandruvada }
970b28cb4bSSrinivas Pandruvada
980b28cb4bSSrinivas Pandruvada recv_msg = (struct hostif_msg *)(recv_buf + cur_pos);
990b28cb4bSSrinivas Pandruvada payload_len = recv_msg->hdr.size;
1000b28cb4bSSrinivas Pandruvada
1010b28cb4bSSrinivas Pandruvada /* Sanity checks */
1020b28cb4bSSrinivas Pandruvada if (cur_pos + payload_len + sizeof(struct hostif_msg) >
1030b28cb4bSSrinivas Pandruvada total_len) {
1040b28cb4bSSrinivas Pandruvada ++client_data->bad_recv_cnt;
1050b28cb4bSSrinivas Pandruvada report_bad_packet(hid_ishtp_cl, recv_msg, cur_pos,
1060b28cb4bSSrinivas Pandruvada payload_len);
10729b06d12SSrinivas Pandruvada ish_hw_reset(ishtp_get_ishtp_device(hid_ishtp_cl));
1080b28cb4bSSrinivas Pandruvada break;
1090b28cb4bSSrinivas Pandruvada }
1100b28cb4bSSrinivas Pandruvada
1110b28cb4bSSrinivas Pandruvada hid_ishtp_trace(client_data, "%s %d\n",
1120b28cb4bSSrinivas Pandruvada __func__, recv_msg->hdr.command & CMD_MASK);
1130b28cb4bSSrinivas Pandruvada
1140b28cb4bSSrinivas Pandruvada switch (recv_msg->hdr.command & CMD_MASK) {
1150b28cb4bSSrinivas Pandruvada case HOSTIF_DM_ENUM_DEVICES:
1160b28cb4bSSrinivas Pandruvada if ((!(recv_msg->hdr.command & ~CMD_MASK) ||
1170b28cb4bSSrinivas Pandruvada client_data->init_done)) {
1180b28cb4bSSrinivas Pandruvada ++client_data->bad_recv_cnt;
1190b28cb4bSSrinivas Pandruvada report_bad_packet(hid_ishtp_cl, recv_msg,
1200b28cb4bSSrinivas Pandruvada cur_pos,
1210b28cb4bSSrinivas Pandruvada payload_len);
12229b06d12SSrinivas Pandruvada ish_hw_reset(ishtp_get_ishtp_device(hid_ishtp_cl));
1230b28cb4bSSrinivas Pandruvada break;
1240b28cb4bSSrinivas Pandruvada }
1250b28cb4bSSrinivas Pandruvada client_data->hid_dev_count = (unsigned int)*payload;
1260b28cb4bSSrinivas Pandruvada if (!client_data->hid_devices)
127a86854d0SKees Cook client_data->hid_devices = devm_kcalloc(
1287ab21842SSrinivas Pandruvada cl_data_to_dev(client_data),
129a86854d0SKees Cook client_data->hid_dev_count,
1300b28cb4bSSrinivas Pandruvada sizeof(struct device_info),
1310b28cb4bSSrinivas Pandruvada GFP_KERNEL);
1320b28cb4bSSrinivas Pandruvada if (!client_data->hid_devices) {
1337ab21842SSrinivas Pandruvada dev_err(cl_data_to_dev(client_data),
1340b28cb4bSSrinivas Pandruvada "Mem alloc failed for hid device info\n");
1350b28cb4bSSrinivas Pandruvada wake_up_interruptible(&client_data->init_wait);
1360b28cb4bSSrinivas Pandruvada break;
1370b28cb4bSSrinivas Pandruvada }
1380b28cb4bSSrinivas Pandruvada for (i = 0; i < client_data->hid_dev_count; ++i) {
1390b28cb4bSSrinivas Pandruvada if (1 + sizeof(struct device_info) * i >=
1400b28cb4bSSrinivas Pandruvada payload_len) {
1417ab21842SSrinivas Pandruvada dev_err(cl_data_to_dev(client_data),
142318fc2a8SArnd Bergmann "[hid-ish]: [ENUM_DEVICES]: content size %zu is bigger than payload_len %zu\n",
1430b28cb4bSSrinivas Pandruvada 1 + sizeof(struct device_info)
144318fc2a8SArnd Bergmann * i, payload_len);
1450b28cb4bSSrinivas Pandruvada }
1460b28cb4bSSrinivas Pandruvada
1470b28cb4bSSrinivas Pandruvada if (1 + sizeof(struct device_info) * i >=
1480b28cb4bSSrinivas Pandruvada data_len)
1490b28cb4bSSrinivas Pandruvada break;
1500b28cb4bSSrinivas Pandruvada
1510b28cb4bSSrinivas Pandruvada dev_info = (struct device_info *)(payload + 1 +
1520b28cb4bSSrinivas Pandruvada sizeof(struct device_info) * i);
1530b28cb4bSSrinivas Pandruvada if (client_data->hid_devices)
1540b28cb4bSSrinivas Pandruvada memcpy(client_data->hid_devices + i,
1550b28cb4bSSrinivas Pandruvada dev_info,
1560b28cb4bSSrinivas Pandruvada sizeof(struct device_info));
1570b28cb4bSSrinivas Pandruvada }
1580b28cb4bSSrinivas Pandruvada
1590b28cb4bSSrinivas Pandruvada client_data->enum_devices_done = true;
1600b28cb4bSSrinivas Pandruvada wake_up_interruptible(&client_data->init_wait);
1610b28cb4bSSrinivas Pandruvada
1620b28cb4bSSrinivas Pandruvada break;
1630b28cb4bSSrinivas Pandruvada
1640b28cb4bSSrinivas Pandruvada case HOSTIF_GET_HID_DESCRIPTOR:
1650b28cb4bSSrinivas Pandruvada if ((!(recv_msg->hdr.command & ~CMD_MASK) ||
1660b28cb4bSSrinivas Pandruvada client_data->init_done)) {
1670b28cb4bSSrinivas Pandruvada ++client_data->bad_recv_cnt;
1680b28cb4bSSrinivas Pandruvada report_bad_packet(hid_ishtp_cl, recv_msg,
1690b28cb4bSSrinivas Pandruvada cur_pos,
1700b28cb4bSSrinivas Pandruvada payload_len);
17129b06d12SSrinivas Pandruvada ish_hw_reset(ishtp_get_ishtp_device(hid_ishtp_cl));
1720b28cb4bSSrinivas Pandruvada break;
1730b28cb4bSSrinivas Pandruvada }
1740b28cb4bSSrinivas Pandruvada if (!client_data->hid_descr[curr_hid_dev])
1750b28cb4bSSrinivas Pandruvada client_data->hid_descr[curr_hid_dev] =
1767ab21842SSrinivas Pandruvada devm_kmalloc(cl_data_to_dev(client_data),
1770b28cb4bSSrinivas Pandruvada payload_len, GFP_KERNEL);
1780b28cb4bSSrinivas Pandruvada if (client_data->hid_descr[curr_hid_dev]) {
1790b28cb4bSSrinivas Pandruvada memcpy(client_data->hid_descr[curr_hid_dev],
1800b28cb4bSSrinivas Pandruvada payload, payload_len);
1810b28cb4bSSrinivas Pandruvada client_data->hid_descr_size[curr_hid_dev] =
1820b28cb4bSSrinivas Pandruvada payload_len;
1830b28cb4bSSrinivas Pandruvada client_data->hid_descr_done = true;
1840b28cb4bSSrinivas Pandruvada }
1850b28cb4bSSrinivas Pandruvada wake_up_interruptible(&client_data->init_wait);
1860b28cb4bSSrinivas Pandruvada
1870b28cb4bSSrinivas Pandruvada break;
1880b28cb4bSSrinivas Pandruvada
1890b28cb4bSSrinivas Pandruvada case HOSTIF_GET_REPORT_DESCRIPTOR:
1900b28cb4bSSrinivas Pandruvada if ((!(recv_msg->hdr.command & ~CMD_MASK) ||
1910b28cb4bSSrinivas Pandruvada client_data->init_done)) {
1920b28cb4bSSrinivas Pandruvada ++client_data->bad_recv_cnt;
1930b28cb4bSSrinivas Pandruvada report_bad_packet(hid_ishtp_cl, recv_msg,
1940b28cb4bSSrinivas Pandruvada cur_pos,
1950b28cb4bSSrinivas Pandruvada payload_len);
19629b06d12SSrinivas Pandruvada ish_hw_reset(ishtp_get_ishtp_device(hid_ishtp_cl));
1970b28cb4bSSrinivas Pandruvada break;
1980b28cb4bSSrinivas Pandruvada }
1990b28cb4bSSrinivas Pandruvada if (!client_data->report_descr[curr_hid_dev])
2000b28cb4bSSrinivas Pandruvada client_data->report_descr[curr_hid_dev] =
2017ab21842SSrinivas Pandruvada devm_kmalloc(cl_data_to_dev(client_data),
2020b28cb4bSSrinivas Pandruvada payload_len, GFP_KERNEL);
2030b28cb4bSSrinivas Pandruvada if (client_data->report_descr[curr_hid_dev]) {
2040b28cb4bSSrinivas Pandruvada memcpy(client_data->report_descr[curr_hid_dev],
2050b28cb4bSSrinivas Pandruvada payload,
2060b28cb4bSSrinivas Pandruvada payload_len);
2070b28cb4bSSrinivas Pandruvada client_data->report_descr_size[curr_hid_dev] =
2080b28cb4bSSrinivas Pandruvada payload_len;
2090b28cb4bSSrinivas Pandruvada client_data->report_descr_done = true;
2100b28cb4bSSrinivas Pandruvada }
2110b28cb4bSSrinivas Pandruvada wake_up_interruptible(&client_data->init_wait);
2120b28cb4bSSrinivas Pandruvada
2130b28cb4bSSrinivas Pandruvada break;
2140b28cb4bSSrinivas Pandruvada
2150b28cb4bSSrinivas Pandruvada case HOSTIF_GET_FEATURE_REPORT:
2160b28cb4bSSrinivas Pandruvada report_type = HID_FEATURE_REPORT;
2170b28cb4bSSrinivas Pandruvada goto do_get_report;
2180b28cb4bSSrinivas Pandruvada
2190b28cb4bSSrinivas Pandruvada case HOSTIF_GET_INPUT_REPORT:
2200b28cb4bSSrinivas Pandruvada report_type = HID_INPUT_REPORT;
2210b28cb4bSSrinivas Pandruvada do_get_report:
2220b28cb4bSSrinivas Pandruvada /* Get index of device that matches this id */
2230b28cb4bSSrinivas Pandruvada for (i = 0; i < client_data->num_hid_devices; ++i) {
2240b28cb4bSSrinivas Pandruvada if (recv_msg->hdr.device_id ==
225e19595fcSHyungwoo Yang client_data->hid_devices[i].dev_id) {
226e19595fcSHyungwoo Yang hid = client_data->hid_sensor_hubs[i];
227e19595fcSHyungwoo Yang if (!hid)
228e19595fcSHyungwoo Yang break;
229e19595fcSHyungwoo Yang
230e19595fcSHyungwoo Yang hid_data = hid->driver_data;
231e19595fcSHyungwoo Yang if (hid_data->raw_get_req) {
232e19595fcSHyungwoo Yang raw_len =
233e19595fcSHyungwoo Yang (hid_data->raw_buf_size <
234e19595fcSHyungwoo Yang payload_len) ?
235e19595fcSHyungwoo Yang hid_data->raw_buf_size :
236e19595fcSHyungwoo Yang payload_len;
237e19595fcSHyungwoo Yang
238e19595fcSHyungwoo Yang memcpy(hid_data->raw_buf,
239e19595fcSHyungwoo Yang payload, raw_len);
240e19595fcSHyungwoo Yang } else {
241e19595fcSHyungwoo Yang hid_input_report
242e19595fcSHyungwoo Yang (hid, report_type,
243e19595fcSHyungwoo Yang payload, payload_len,
244e19595fcSHyungwoo Yang 0);
245e19595fcSHyungwoo Yang }
246e19595fcSHyungwoo Yang
247e19595fcSHyungwoo Yang ishtp_hid_wakeup(hid);
2480b28cb4bSSrinivas Pandruvada break;
2490b28cb4bSSrinivas Pandruvada }
2500b28cb4bSSrinivas Pandruvada }
2510b28cb4bSSrinivas Pandruvada break;
2520b28cb4bSSrinivas Pandruvada
2530b28cb4bSSrinivas Pandruvada case HOSTIF_SET_FEATURE_REPORT:
2540b28cb4bSSrinivas Pandruvada /* Get index of device that matches this id */
2550b28cb4bSSrinivas Pandruvada for (i = 0; i < client_data->num_hid_devices; ++i) {
2560b28cb4bSSrinivas Pandruvada if (recv_msg->hdr.device_id ==
2570b28cb4bSSrinivas Pandruvada client_data->hid_devices[i].dev_id)
2580b28cb4bSSrinivas Pandruvada if (client_data->hid_sensor_hubs[i]) {
2590b28cb4bSSrinivas Pandruvada ishtp_hid_wakeup(
2600b28cb4bSSrinivas Pandruvada client_data->hid_sensor_hubs[
2610b28cb4bSSrinivas Pandruvada i]);
2620b28cb4bSSrinivas Pandruvada break;
2630b28cb4bSSrinivas Pandruvada }
2640b28cb4bSSrinivas Pandruvada }
2650b28cb4bSSrinivas Pandruvada break;
2660b28cb4bSSrinivas Pandruvada
2670b28cb4bSSrinivas Pandruvada case HOSTIF_PUBLISH_INPUT_REPORT:
2680b28cb4bSSrinivas Pandruvada report_type = HID_INPUT_REPORT;
2690b28cb4bSSrinivas Pandruvada for (i = 0; i < client_data->num_hid_devices; ++i)
2700b28cb4bSSrinivas Pandruvada if (recv_msg->hdr.device_id ==
2710b28cb4bSSrinivas Pandruvada client_data->hid_devices[i].dev_id)
2720b28cb4bSSrinivas Pandruvada if (client_data->hid_sensor_hubs[i])
2730b28cb4bSSrinivas Pandruvada hid_input_report(
2740b28cb4bSSrinivas Pandruvada client_data->hid_sensor_hubs[
2750b28cb4bSSrinivas Pandruvada i],
2760b28cb4bSSrinivas Pandruvada report_type, payload,
2770b28cb4bSSrinivas Pandruvada payload_len, 0);
2780b28cb4bSSrinivas Pandruvada break;
2790b28cb4bSSrinivas Pandruvada
2800b28cb4bSSrinivas Pandruvada case HOSTIF_PUBLISH_INPUT_REPORT_LIST:
2810b28cb4bSSrinivas Pandruvada report_type = HID_INPUT_REPORT;
2820b28cb4bSSrinivas Pandruvada reports_list = (struct report_list *)payload;
2830b28cb4bSSrinivas Pandruvada reports = (char *)reports_list->reports;
2840b28cb4bSSrinivas Pandruvada
2850b28cb4bSSrinivas Pandruvada for (j = 0; j < reports_list->num_of_reports; j++) {
2860b28cb4bSSrinivas Pandruvada recv_msg = (struct hostif_msg *)(reports +
2870b28cb4bSSrinivas Pandruvada sizeof(uint16_t));
2880b28cb4bSSrinivas Pandruvada report_len = *(uint16_t *)reports;
2890b28cb4bSSrinivas Pandruvada payload = reports + sizeof(uint16_t) +
2900b28cb4bSSrinivas Pandruvada sizeof(struct hostif_msg_hdr);
2910b28cb4bSSrinivas Pandruvada payload_len = report_len -
2920b28cb4bSSrinivas Pandruvada sizeof(struct hostif_msg_hdr);
2930b28cb4bSSrinivas Pandruvada
2940b28cb4bSSrinivas Pandruvada for (i = 0; i < client_data->num_hid_devices;
2950b28cb4bSSrinivas Pandruvada ++i)
2960b28cb4bSSrinivas Pandruvada if (recv_msg->hdr.device_id ==
2970b28cb4bSSrinivas Pandruvada client_data->hid_devices[i].dev_id &&
2980b28cb4bSSrinivas Pandruvada client_data->hid_sensor_hubs[i]) {
2990b28cb4bSSrinivas Pandruvada hid_input_report(
3000b28cb4bSSrinivas Pandruvada client_data->hid_sensor_hubs[
3010b28cb4bSSrinivas Pandruvada i],
3020b28cb4bSSrinivas Pandruvada report_type,
3030b28cb4bSSrinivas Pandruvada payload, payload_len,
3040b28cb4bSSrinivas Pandruvada 0);
3050b28cb4bSSrinivas Pandruvada }
3060b28cb4bSSrinivas Pandruvada
3070b28cb4bSSrinivas Pandruvada reports += sizeof(uint16_t) + report_len;
3080b28cb4bSSrinivas Pandruvada }
3090b28cb4bSSrinivas Pandruvada break;
3100b28cb4bSSrinivas Pandruvada default:
3110b28cb4bSSrinivas Pandruvada ++client_data->bad_recv_cnt;
3120b28cb4bSSrinivas Pandruvada report_bad_packet(hid_ishtp_cl, recv_msg, cur_pos,
3130b28cb4bSSrinivas Pandruvada payload_len);
31429b06d12SSrinivas Pandruvada ish_hw_reset(ishtp_get_ishtp_device(hid_ishtp_cl));
3150b28cb4bSSrinivas Pandruvada break;
3160b28cb4bSSrinivas Pandruvada
3170b28cb4bSSrinivas Pandruvada }
3180b28cb4bSSrinivas Pandruvada
3190b28cb4bSSrinivas Pandruvada if (!cur_pos && cur_pos + payload_len +
3200b28cb4bSSrinivas Pandruvada sizeof(struct hostif_msg) < total_len)
3210b28cb4bSSrinivas Pandruvada ++client_data->multi_packet_cnt;
3220b28cb4bSSrinivas Pandruvada
3230b28cb4bSSrinivas Pandruvada cur_pos += payload_len + sizeof(struct hostif_msg);
3240b28cb4bSSrinivas Pandruvada payload += payload_len + sizeof(struct hostif_msg);
3250b28cb4bSSrinivas Pandruvada
3260b28cb4bSSrinivas Pandruvada } while (cur_pos < total_len);
3270b28cb4bSSrinivas Pandruvada }
3280b28cb4bSSrinivas Pandruvada
3290b28cb4bSSrinivas Pandruvada /**
3300b28cb4bSSrinivas Pandruvada * ish_cl_event_cb() - bus driver callback for incoming message/packet
331*92443a9fSJiang Jian * @device: Pointer to the ishtp client device for which this message
3320b28cb4bSSrinivas Pandruvada * is targeted
3330b28cb4bSSrinivas Pandruvada *
3340b28cb4bSSrinivas Pandruvada * Remove the packet from the list and process the message by calling
3350b28cb4bSSrinivas Pandruvada * process_recv
3360b28cb4bSSrinivas Pandruvada */
ish_cl_event_cb(struct ishtp_cl_device * device)3370b28cb4bSSrinivas Pandruvada static void ish_cl_event_cb(struct ishtp_cl_device *device)
3380b28cb4bSSrinivas Pandruvada {
339d174c666SEven Xu struct ishtp_cl *hid_ishtp_cl = ishtp_get_drvdata(device);
3400b28cb4bSSrinivas Pandruvada struct ishtp_cl_rb *rb_in_proc;
3410b28cb4bSSrinivas Pandruvada size_t r_length;
3420b28cb4bSSrinivas Pandruvada
3430b28cb4bSSrinivas Pandruvada if (!hid_ishtp_cl)
3440b28cb4bSSrinivas Pandruvada return;
3450b28cb4bSSrinivas Pandruvada
346816e7ed1SEven Xu while ((rb_in_proc = ishtp_cl_rx_get_rb(hid_ishtp_cl)) != NULL) {
3470b28cb4bSSrinivas Pandruvada if (!rb_in_proc->buffer.data)
3480b28cb4bSSrinivas Pandruvada return;
3490b28cb4bSSrinivas Pandruvada
3500b28cb4bSSrinivas Pandruvada r_length = rb_in_proc->buf_idx;
3510b28cb4bSSrinivas Pandruvada
3520b28cb4bSSrinivas Pandruvada /* decide what to do with received data */
3530b28cb4bSSrinivas Pandruvada process_recv(hid_ishtp_cl, rb_in_proc->buffer.data, r_length);
3540b28cb4bSSrinivas Pandruvada
3550b28cb4bSSrinivas Pandruvada ishtp_cl_io_rb_recycle(rb_in_proc);
3560b28cb4bSSrinivas Pandruvada }
3570b28cb4bSSrinivas Pandruvada }
3580b28cb4bSSrinivas Pandruvada
3590b28cb4bSSrinivas Pandruvada /**
3600b28cb4bSSrinivas Pandruvada * hid_ishtp_set_feature() - send request to ISH FW to set a feature request
3610b28cb4bSSrinivas Pandruvada * @hid: hid device instance for this request
3620b28cb4bSSrinivas Pandruvada * @buf: feature buffer
3630b28cb4bSSrinivas Pandruvada * @len: Length of feature buffer
3640b28cb4bSSrinivas Pandruvada * @report_id: Report id for the feature set request
3650b28cb4bSSrinivas Pandruvada *
3660b28cb4bSSrinivas Pandruvada * This is called from hid core .request() callback. This function doesn't wait
3670b28cb4bSSrinivas Pandruvada * for response.
3680b28cb4bSSrinivas Pandruvada */
hid_ishtp_set_feature(struct hid_device * hid,char * buf,unsigned int len,int report_id)3690b28cb4bSSrinivas Pandruvada void hid_ishtp_set_feature(struct hid_device *hid, char *buf, unsigned int len,
3700b28cb4bSSrinivas Pandruvada int report_id)
3710b28cb4bSSrinivas Pandruvada {
3720b28cb4bSSrinivas Pandruvada struct ishtp_hid_data *hid_data = hid->driver_data;
3730b28cb4bSSrinivas Pandruvada struct ishtp_cl_data *client_data = hid_data->client_data;
3740b28cb4bSSrinivas Pandruvada struct hostif_msg *msg = (struct hostif_msg *)buf;
3750b28cb4bSSrinivas Pandruvada int rv;
3760b28cb4bSSrinivas Pandruvada int i;
3770b28cb4bSSrinivas Pandruvada
3780b28cb4bSSrinivas Pandruvada hid_ishtp_trace(client_data, "%s hid %p\n", __func__, hid);
3790b28cb4bSSrinivas Pandruvada
3800b28cb4bSSrinivas Pandruvada rv = ishtp_hid_link_ready_wait(client_data);
3810b28cb4bSSrinivas Pandruvada if (rv) {
3820b28cb4bSSrinivas Pandruvada hid_ishtp_trace(client_data, "%s hid %p link not ready\n",
3830b28cb4bSSrinivas Pandruvada __func__, hid);
3840b28cb4bSSrinivas Pandruvada return;
3850b28cb4bSSrinivas Pandruvada }
3860b28cb4bSSrinivas Pandruvada
3870b28cb4bSSrinivas Pandruvada memset(msg, 0, sizeof(struct hostif_msg));
3880b28cb4bSSrinivas Pandruvada msg->hdr.command = HOSTIF_SET_FEATURE_REPORT;
3890b28cb4bSSrinivas Pandruvada for (i = 0; i < client_data->num_hid_devices; ++i) {
3900b28cb4bSSrinivas Pandruvada if (hid == client_data->hid_sensor_hubs[i]) {
3910b28cb4bSSrinivas Pandruvada msg->hdr.device_id =
3920b28cb4bSSrinivas Pandruvada client_data->hid_devices[i].dev_id;
3930b28cb4bSSrinivas Pandruvada break;
3940b28cb4bSSrinivas Pandruvada }
3950b28cb4bSSrinivas Pandruvada }
3960b28cb4bSSrinivas Pandruvada
3970b28cb4bSSrinivas Pandruvada if (i == client_data->num_hid_devices)
3980b28cb4bSSrinivas Pandruvada return;
3990b28cb4bSSrinivas Pandruvada
4000b28cb4bSSrinivas Pandruvada rv = ishtp_cl_send(client_data->hid_ishtp_cl, buf, len);
4010b28cb4bSSrinivas Pandruvada if (rv)
4020b28cb4bSSrinivas Pandruvada hid_ishtp_trace(client_data, "%s hid %p send failed\n",
4030b28cb4bSSrinivas Pandruvada __func__, hid);
4040b28cb4bSSrinivas Pandruvada }
4050b28cb4bSSrinivas Pandruvada
4060b28cb4bSSrinivas Pandruvada /**
4070b28cb4bSSrinivas Pandruvada * hid_ishtp_get_report() - request to get feature/input report
4080b28cb4bSSrinivas Pandruvada * @hid: hid device instance for this request
4090b28cb4bSSrinivas Pandruvada * @report_id: Report id for the get request
4100b28cb4bSSrinivas Pandruvada * @report_type: Report type for the this request
4110b28cb4bSSrinivas Pandruvada *
4120b28cb4bSSrinivas Pandruvada * This is called from hid core .request() callback. This function will send
4130b28cb4bSSrinivas Pandruvada * request to FW and return without waiting for response.
4140b28cb4bSSrinivas Pandruvada */
hid_ishtp_get_report(struct hid_device * hid,int report_id,int report_type)4150b28cb4bSSrinivas Pandruvada void hid_ishtp_get_report(struct hid_device *hid, int report_id,
4160b28cb4bSSrinivas Pandruvada int report_type)
4170b28cb4bSSrinivas Pandruvada {
4180b28cb4bSSrinivas Pandruvada struct ishtp_hid_data *hid_data = hid->driver_data;
4190b28cb4bSSrinivas Pandruvada struct ishtp_cl_data *client_data = hid_data->client_data;
420749ab300SHans de Goede struct hostif_msg_to_sensor msg = {};
4210b28cb4bSSrinivas Pandruvada int rv;
4220b28cb4bSSrinivas Pandruvada int i;
4230b28cb4bSSrinivas Pandruvada
4240b28cb4bSSrinivas Pandruvada hid_ishtp_trace(client_data, "%s hid %p\n", __func__, hid);
4250b28cb4bSSrinivas Pandruvada rv = ishtp_hid_link_ready_wait(client_data);
4260b28cb4bSSrinivas Pandruvada if (rv) {
4270b28cb4bSSrinivas Pandruvada hid_ishtp_trace(client_data, "%s hid %p link not ready\n",
4280b28cb4bSSrinivas Pandruvada __func__, hid);
4290b28cb4bSSrinivas Pandruvada return;
4300b28cb4bSSrinivas Pandruvada }
4310b28cb4bSSrinivas Pandruvada
432749ab300SHans de Goede msg.hdr.command = (report_type == HID_FEATURE_REPORT) ?
4330b28cb4bSSrinivas Pandruvada HOSTIF_GET_FEATURE_REPORT : HOSTIF_GET_INPUT_REPORT;
4340b28cb4bSSrinivas Pandruvada for (i = 0; i < client_data->num_hid_devices; ++i) {
4350b28cb4bSSrinivas Pandruvada if (hid == client_data->hid_sensor_hubs[i]) {
436749ab300SHans de Goede msg.hdr.device_id =
4370b28cb4bSSrinivas Pandruvada client_data->hid_devices[i].dev_id;
4380b28cb4bSSrinivas Pandruvada break;
4390b28cb4bSSrinivas Pandruvada }
4400b28cb4bSSrinivas Pandruvada }
4410b28cb4bSSrinivas Pandruvada
4420b28cb4bSSrinivas Pandruvada if (i == client_data->num_hid_devices)
4430b28cb4bSSrinivas Pandruvada return;
4440b28cb4bSSrinivas Pandruvada
445749ab300SHans de Goede msg.report_id = report_id;
446749ab300SHans de Goede rv = ishtp_cl_send(client_data->hid_ishtp_cl, (uint8_t *)&msg,
447749ab300SHans de Goede sizeof(msg));
4480b28cb4bSSrinivas Pandruvada if (rv)
4490b28cb4bSSrinivas Pandruvada hid_ishtp_trace(client_data, "%s hid %p send failed\n",
4500b28cb4bSSrinivas Pandruvada __func__, hid);
4510b28cb4bSSrinivas Pandruvada }
4520b28cb4bSSrinivas Pandruvada
4530b28cb4bSSrinivas Pandruvada /**
4540b28cb4bSSrinivas Pandruvada * ishtp_hid_link_ready_wait() - Wait for link ready
4550b28cb4bSSrinivas Pandruvada * @client_data: client data instance
4560b28cb4bSSrinivas Pandruvada *
4570b28cb4bSSrinivas Pandruvada * If the transport link started suspend process, then wait, till either
4580b28cb4bSSrinivas Pandruvada * resumed or timeout
4590b28cb4bSSrinivas Pandruvada *
4600b28cb4bSSrinivas Pandruvada * Return: 0 on success, non zero on error
4610b28cb4bSSrinivas Pandruvada */
ishtp_hid_link_ready_wait(struct ishtp_cl_data * client_data)4620b28cb4bSSrinivas Pandruvada int ishtp_hid_link_ready_wait(struct ishtp_cl_data *client_data)
4630b28cb4bSSrinivas Pandruvada {
4640b28cb4bSSrinivas Pandruvada int rc;
4650b28cb4bSSrinivas Pandruvada
4660b28cb4bSSrinivas Pandruvada if (client_data->suspended) {
4670b28cb4bSSrinivas Pandruvada hid_ishtp_trace(client_data, "wait for link ready\n");
4680b28cb4bSSrinivas Pandruvada rc = wait_event_interruptible_timeout(
4690b28cb4bSSrinivas Pandruvada client_data->ishtp_resume_wait,
4700b28cb4bSSrinivas Pandruvada !client_data->suspended,
4710b28cb4bSSrinivas Pandruvada 5 * HZ);
4720b28cb4bSSrinivas Pandruvada
4730b28cb4bSSrinivas Pandruvada if (rc == 0) {
4740b28cb4bSSrinivas Pandruvada hid_ishtp_trace(client_data, "link not ready\n");
4750b28cb4bSSrinivas Pandruvada return -EIO;
4760b28cb4bSSrinivas Pandruvada }
4770b28cb4bSSrinivas Pandruvada hid_ishtp_trace(client_data, "link ready\n");
4780b28cb4bSSrinivas Pandruvada }
4790b28cb4bSSrinivas Pandruvada
4800b28cb4bSSrinivas Pandruvada return 0;
4810b28cb4bSSrinivas Pandruvada }
4820b28cb4bSSrinivas Pandruvada
4830b28cb4bSSrinivas Pandruvada /**
4840b28cb4bSSrinivas Pandruvada * ishtp_enum_enum_devices() - Enumerate hid devices
4850b28cb4bSSrinivas Pandruvada * @hid_ishtp_cl: client instance
4860b28cb4bSSrinivas Pandruvada *
4870b28cb4bSSrinivas Pandruvada * Helper function to send request to firmware to enumerate HID devices
4880b28cb4bSSrinivas Pandruvada *
4890b28cb4bSSrinivas Pandruvada * Return: 0 on success, non zero on error
4900b28cb4bSSrinivas Pandruvada */
ishtp_enum_enum_devices(struct ishtp_cl * hid_ishtp_cl)4910b28cb4bSSrinivas Pandruvada static int ishtp_enum_enum_devices(struct ishtp_cl *hid_ishtp_cl)
4920b28cb4bSSrinivas Pandruvada {
4930b28cb4bSSrinivas Pandruvada struct hostif_msg msg;
49429b06d12SSrinivas Pandruvada struct ishtp_cl_data *client_data = ishtp_get_client_data(hid_ishtp_cl);
4950b28cb4bSSrinivas Pandruvada int retry_count;
4960b28cb4bSSrinivas Pandruvada int rv;
4970b28cb4bSSrinivas Pandruvada
4980b28cb4bSSrinivas Pandruvada /* Send HOSTIF_DM_ENUM_DEVICES */
4990b28cb4bSSrinivas Pandruvada memset(&msg, 0, sizeof(struct hostif_msg));
5000b28cb4bSSrinivas Pandruvada msg.hdr.command = HOSTIF_DM_ENUM_DEVICES;
5010b28cb4bSSrinivas Pandruvada rv = ishtp_cl_send(hid_ishtp_cl, (unsigned char *)&msg,
5020b28cb4bSSrinivas Pandruvada sizeof(struct hostif_msg));
5030b28cb4bSSrinivas Pandruvada if (rv)
5040b28cb4bSSrinivas Pandruvada return rv;
5050b28cb4bSSrinivas Pandruvada
5060b28cb4bSSrinivas Pandruvada retry_count = 0;
5070b28cb4bSSrinivas Pandruvada while (!client_data->enum_devices_done &&
5080b28cb4bSSrinivas Pandruvada retry_count < 10) {
5090b28cb4bSSrinivas Pandruvada wait_event_interruptible_timeout(client_data->init_wait,
5100b28cb4bSSrinivas Pandruvada client_data->enum_devices_done,
5110b28cb4bSSrinivas Pandruvada 3 * HZ);
5120b28cb4bSSrinivas Pandruvada ++retry_count;
5130b28cb4bSSrinivas Pandruvada if (!client_data->enum_devices_done)
5140b28cb4bSSrinivas Pandruvada /* Send HOSTIF_DM_ENUM_DEVICES */
5150b28cb4bSSrinivas Pandruvada rv = ishtp_cl_send(hid_ishtp_cl,
5160b28cb4bSSrinivas Pandruvada (unsigned char *) &msg,
5170b28cb4bSSrinivas Pandruvada sizeof(struct hostif_msg));
5180b28cb4bSSrinivas Pandruvada }
5190b28cb4bSSrinivas Pandruvada if (!client_data->enum_devices_done) {
5207ab21842SSrinivas Pandruvada dev_err(cl_data_to_dev(client_data),
5210b28cb4bSSrinivas Pandruvada "[hid-ish]: timed out waiting for enum_devices\n");
5220b28cb4bSSrinivas Pandruvada return -ETIMEDOUT;
5230b28cb4bSSrinivas Pandruvada }
5240b28cb4bSSrinivas Pandruvada if (!client_data->hid_devices) {
5257ab21842SSrinivas Pandruvada dev_err(cl_data_to_dev(client_data),
5260b28cb4bSSrinivas Pandruvada "[hid-ish]: failed to allocate HID dev structures\n");
5270b28cb4bSSrinivas Pandruvada return -ENOMEM;
5280b28cb4bSSrinivas Pandruvada }
5290b28cb4bSSrinivas Pandruvada
5300b28cb4bSSrinivas Pandruvada client_data->num_hid_devices = client_data->hid_dev_count;
53129b06d12SSrinivas Pandruvada dev_info(ishtp_device(client_data->cl_device),
5320b28cb4bSSrinivas Pandruvada "[hid-ish]: enum_devices_done OK, num_hid_devices=%d\n",
5330b28cb4bSSrinivas Pandruvada client_data->num_hid_devices);
5340b28cb4bSSrinivas Pandruvada
5350b28cb4bSSrinivas Pandruvada return 0;
5360b28cb4bSSrinivas Pandruvada }
5370b28cb4bSSrinivas Pandruvada
5380b28cb4bSSrinivas Pandruvada /**
5390b28cb4bSSrinivas Pandruvada * ishtp_get_hid_descriptor() - Get hid descriptor
5400b28cb4bSSrinivas Pandruvada * @hid_ishtp_cl: client instance
5410b28cb4bSSrinivas Pandruvada * @index: Index into the hid_descr array
5420b28cb4bSSrinivas Pandruvada *
5430b28cb4bSSrinivas Pandruvada * Helper function to send request to firmware get HID descriptor of a device
5440b28cb4bSSrinivas Pandruvada *
5450b28cb4bSSrinivas Pandruvada * Return: 0 on success, non zero on error
5460b28cb4bSSrinivas Pandruvada */
ishtp_get_hid_descriptor(struct ishtp_cl * hid_ishtp_cl,int index)5470b28cb4bSSrinivas Pandruvada static int ishtp_get_hid_descriptor(struct ishtp_cl *hid_ishtp_cl, int index)
5480b28cb4bSSrinivas Pandruvada {
5490b28cb4bSSrinivas Pandruvada struct hostif_msg msg;
55029b06d12SSrinivas Pandruvada struct ishtp_cl_data *client_data = ishtp_get_client_data(hid_ishtp_cl);
5510b28cb4bSSrinivas Pandruvada int rv;
5520b28cb4bSSrinivas Pandruvada
5530b28cb4bSSrinivas Pandruvada /* Get HID descriptor */
5540b28cb4bSSrinivas Pandruvada client_data->hid_descr_done = false;
5550b28cb4bSSrinivas Pandruvada memset(&msg, 0, sizeof(struct hostif_msg));
5560b28cb4bSSrinivas Pandruvada msg.hdr.command = HOSTIF_GET_HID_DESCRIPTOR;
5570b28cb4bSSrinivas Pandruvada msg.hdr.device_id = client_data->hid_devices[index].dev_id;
5580b28cb4bSSrinivas Pandruvada rv = ishtp_cl_send(hid_ishtp_cl, (unsigned char *) &msg,
5590b28cb4bSSrinivas Pandruvada sizeof(struct hostif_msg));
5600b28cb4bSSrinivas Pandruvada if (rv)
5610b28cb4bSSrinivas Pandruvada return rv;
5620b28cb4bSSrinivas Pandruvada
5630b28cb4bSSrinivas Pandruvada if (!client_data->hid_descr_done) {
5640b28cb4bSSrinivas Pandruvada wait_event_interruptible_timeout(client_data->init_wait,
5650b28cb4bSSrinivas Pandruvada client_data->hid_descr_done,
5660b28cb4bSSrinivas Pandruvada 3 * HZ);
5670b28cb4bSSrinivas Pandruvada if (!client_data->hid_descr_done) {
5687ab21842SSrinivas Pandruvada dev_err(cl_data_to_dev(client_data),
5690b28cb4bSSrinivas Pandruvada "[hid-ish]: timed out for hid_descr_done\n");
5700b28cb4bSSrinivas Pandruvada return -EIO;
5710b28cb4bSSrinivas Pandruvada }
5720b28cb4bSSrinivas Pandruvada
5730b28cb4bSSrinivas Pandruvada if (!client_data->hid_descr[index]) {
5747ab21842SSrinivas Pandruvada dev_err(cl_data_to_dev(client_data),
5750b28cb4bSSrinivas Pandruvada "[hid-ish]: allocation HID desc fail\n");
5760b28cb4bSSrinivas Pandruvada return -ENOMEM;
5770b28cb4bSSrinivas Pandruvada }
5780b28cb4bSSrinivas Pandruvada }
5790b28cb4bSSrinivas Pandruvada
5800b28cb4bSSrinivas Pandruvada return 0;
5810b28cb4bSSrinivas Pandruvada }
5820b28cb4bSSrinivas Pandruvada
5830b28cb4bSSrinivas Pandruvada /**
5840b28cb4bSSrinivas Pandruvada * ishtp_get_report_descriptor() - Get report descriptor
5850b28cb4bSSrinivas Pandruvada * @hid_ishtp_cl: client instance
5860b28cb4bSSrinivas Pandruvada * @index: Index into the hid_descr array
5870b28cb4bSSrinivas Pandruvada *
5880b28cb4bSSrinivas Pandruvada * Helper function to send request to firmware get HID report descriptor of
5890b28cb4bSSrinivas Pandruvada * a device
5900b28cb4bSSrinivas Pandruvada *
5910b28cb4bSSrinivas Pandruvada * Return: 0 on success, non zero on error
5920b28cb4bSSrinivas Pandruvada */
ishtp_get_report_descriptor(struct ishtp_cl * hid_ishtp_cl,int index)5930b28cb4bSSrinivas Pandruvada static int ishtp_get_report_descriptor(struct ishtp_cl *hid_ishtp_cl,
5940b28cb4bSSrinivas Pandruvada int index)
5950b28cb4bSSrinivas Pandruvada {
5960b28cb4bSSrinivas Pandruvada struct hostif_msg msg;
59729b06d12SSrinivas Pandruvada struct ishtp_cl_data *client_data = ishtp_get_client_data(hid_ishtp_cl);
5980b28cb4bSSrinivas Pandruvada int rv;
5990b28cb4bSSrinivas Pandruvada
6000b28cb4bSSrinivas Pandruvada /* Get report descriptor */
6010b28cb4bSSrinivas Pandruvada client_data->report_descr_done = false;
6020b28cb4bSSrinivas Pandruvada memset(&msg, 0, sizeof(struct hostif_msg));
6030b28cb4bSSrinivas Pandruvada msg.hdr.command = HOSTIF_GET_REPORT_DESCRIPTOR;
6040b28cb4bSSrinivas Pandruvada msg.hdr.device_id = client_data->hid_devices[index].dev_id;
6050b28cb4bSSrinivas Pandruvada rv = ishtp_cl_send(hid_ishtp_cl, (unsigned char *) &msg,
6060b28cb4bSSrinivas Pandruvada sizeof(struct hostif_msg));
6070b28cb4bSSrinivas Pandruvada if (rv)
6080b28cb4bSSrinivas Pandruvada return rv;
6090b28cb4bSSrinivas Pandruvada
6100b28cb4bSSrinivas Pandruvada if (!client_data->report_descr_done)
6110b28cb4bSSrinivas Pandruvada wait_event_interruptible_timeout(client_data->init_wait,
6120b28cb4bSSrinivas Pandruvada client_data->report_descr_done,
6130b28cb4bSSrinivas Pandruvada 3 * HZ);
6140b28cb4bSSrinivas Pandruvada if (!client_data->report_descr_done) {
6157ab21842SSrinivas Pandruvada dev_err(cl_data_to_dev(client_data),
6160b28cb4bSSrinivas Pandruvada "[hid-ish]: timed out for report descr\n");
6170b28cb4bSSrinivas Pandruvada return -EIO;
6180b28cb4bSSrinivas Pandruvada }
6190b28cb4bSSrinivas Pandruvada if (!client_data->report_descr[index]) {
6207ab21842SSrinivas Pandruvada dev_err(cl_data_to_dev(client_data),
6210b28cb4bSSrinivas Pandruvada "[hid-ish]: failed to alloc report descr\n");
6220b28cb4bSSrinivas Pandruvada return -ENOMEM;
6230b28cb4bSSrinivas Pandruvada }
6240b28cb4bSSrinivas Pandruvada
6250b28cb4bSSrinivas Pandruvada return 0;
6260b28cb4bSSrinivas Pandruvada }
6270b28cb4bSSrinivas Pandruvada
6280b28cb4bSSrinivas Pandruvada /**
6290b28cb4bSSrinivas Pandruvada * hid_ishtp_cl_init() - Init function for ISHTP client
6300b28cb4bSSrinivas Pandruvada * @hid_ishtp_cl: ISHTP client instance
6310b28cb4bSSrinivas Pandruvada * @reset: true if called for init after reset
6320b28cb4bSSrinivas Pandruvada *
6330b28cb4bSSrinivas Pandruvada * This function complete the initializtion of the client. The summary of
6340b28cb4bSSrinivas Pandruvada * processing:
6350b28cb4bSSrinivas Pandruvada * - Send request to enumerate the hid clients
6360b28cb4bSSrinivas Pandruvada * Get the HID descriptor for each enumearated device
6370b28cb4bSSrinivas Pandruvada * Get report description of each device
6380b28cb4bSSrinivas Pandruvada * Register each device wik hid core by calling ishtp_hid_probe
6390b28cb4bSSrinivas Pandruvada *
6400b28cb4bSSrinivas Pandruvada * Return: 0 on success, non zero on error
6410b28cb4bSSrinivas Pandruvada */
hid_ishtp_cl_init(struct ishtp_cl * hid_ishtp_cl,int reset)6420b28cb4bSSrinivas Pandruvada static int hid_ishtp_cl_init(struct ishtp_cl *hid_ishtp_cl, int reset)
6430b28cb4bSSrinivas Pandruvada {
6440b28cb4bSSrinivas Pandruvada struct ishtp_device *dev;
64529b06d12SSrinivas Pandruvada struct ishtp_cl_data *client_data = ishtp_get_client_data(hid_ishtp_cl);
646f26de33fSEven Xu struct ishtp_fw_client *fw_client;
6470b28cb4bSSrinivas Pandruvada int i;
6480b28cb4bSSrinivas Pandruvada int rv;
6490b28cb4bSSrinivas Pandruvada
6507ab21842SSrinivas Pandruvada dev_dbg(cl_data_to_dev(client_data), "%s\n", __func__);
6510b28cb4bSSrinivas Pandruvada hid_ishtp_trace(client_data, "%s reset flag: %d\n", __func__, reset);
6520b28cb4bSSrinivas Pandruvada
653c2012ec0SSrinivas Pandruvada rv = ishtp_cl_link(hid_ishtp_cl);
6540b28cb4bSSrinivas Pandruvada if (rv) {
6557ab21842SSrinivas Pandruvada dev_err(cl_data_to_dev(client_data),
6560b28cb4bSSrinivas Pandruvada "ishtp_cl_link failed\n");
6570b28cb4bSSrinivas Pandruvada return -ENOMEM;
6580b28cb4bSSrinivas Pandruvada }
6590b28cb4bSSrinivas Pandruvada
6600b28cb4bSSrinivas Pandruvada client_data->init_done = 0;
6610b28cb4bSSrinivas Pandruvada
66229b06d12SSrinivas Pandruvada dev = ishtp_get_ishtp_device(hid_ishtp_cl);
6630b28cb4bSSrinivas Pandruvada
6640b28cb4bSSrinivas Pandruvada /* Connect to FW client */
66529b06d12SSrinivas Pandruvada ishtp_set_tx_ring_size(hid_ishtp_cl, HID_CL_TX_RING_SIZE);
66629b06d12SSrinivas Pandruvada ishtp_set_rx_ring_size(hid_ishtp_cl, HID_CL_RX_RING_SIZE);
6670b28cb4bSSrinivas Pandruvada
668bf9167a8SArnd Bergmann fw_client = ishtp_fw_cl_get_client(dev, &hid_ishtp_id_table[0].guid);
669f26de33fSEven Xu if (!fw_client) {
6707ab21842SSrinivas Pandruvada dev_err(cl_data_to_dev(client_data),
6710b28cb4bSSrinivas Pandruvada "ish client uuid not found\n");
672f26de33fSEven Xu return -ENOENT;
6730b28cb4bSSrinivas Pandruvada }
67429b06d12SSrinivas Pandruvada ishtp_cl_set_fw_client_id(hid_ishtp_cl,
67529b06d12SSrinivas Pandruvada ishtp_get_fw_client_id(fw_client));
67629b06d12SSrinivas Pandruvada ishtp_set_connection_state(hid_ishtp_cl, ISHTP_CL_CONNECTING);
6770b28cb4bSSrinivas Pandruvada
6780b28cb4bSSrinivas Pandruvada rv = ishtp_cl_connect(hid_ishtp_cl);
6790b28cb4bSSrinivas Pandruvada if (rv) {
6807ab21842SSrinivas Pandruvada dev_err(cl_data_to_dev(client_data),
6810b28cb4bSSrinivas Pandruvada "client connect fail\n");
6820b28cb4bSSrinivas Pandruvada goto err_cl_unlink;
6830b28cb4bSSrinivas Pandruvada }
6840b28cb4bSSrinivas Pandruvada
6850b28cb4bSSrinivas Pandruvada hid_ishtp_trace(client_data, "%s client connected\n", __func__);
6860b28cb4bSSrinivas Pandruvada
6870b28cb4bSSrinivas Pandruvada /* Register read callback */
68829b06d12SSrinivas Pandruvada ishtp_register_event_cb(client_data->cl_device, ish_cl_event_cb);
6890b28cb4bSSrinivas Pandruvada
6900b28cb4bSSrinivas Pandruvada rv = ishtp_enum_enum_devices(hid_ishtp_cl);
6910b28cb4bSSrinivas Pandruvada if (rv)
6920b28cb4bSSrinivas Pandruvada goto err_cl_disconnect;
6930b28cb4bSSrinivas Pandruvada
6940b28cb4bSSrinivas Pandruvada hid_ishtp_trace(client_data, "%s enumerated device count %d\n",
6950b28cb4bSSrinivas Pandruvada __func__, client_data->num_hid_devices);
6960b28cb4bSSrinivas Pandruvada
6970b28cb4bSSrinivas Pandruvada for (i = 0; i < client_data->num_hid_devices; ++i) {
6980b28cb4bSSrinivas Pandruvada client_data->cur_hid_dev = i;
6990b28cb4bSSrinivas Pandruvada
7000b28cb4bSSrinivas Pandruvada rv = ishtp_get_hid_descriptor(hid_ishtp_cl, i);
7010b28cb4bSSrinivas Pandruvada if (rv)
7020b28cb4bSSrinivas Pandruvada goto err_cl_disconnect;
7030b28cb4bSSrinivas Pandruvada
7040b28cb4bSSrinivas Pandruvada rv = ishtp_get_report_descriptor(hid_ishtp_cl, i);
7050b28cb4bSSrinivas Pandruvada if (rv)
7060b28cb4bSSrinivas Pandruvada goto err_cl_disconnect;
7070b28cb4bSSrinivas Pandruvada
7080b28cb4bSSrinivas Pandruvada if (!reset) {
7090b28cb4bSSrinivas Pandruvada rv = ishtp_hid_probe(i, client_data);
7100b28cb4bSSrinivas Pandruvada if (rv) {
7117ab21842SSrinivas Pandruvada dev_err(cl_data_to_dev(client_data),
7120b28cb4bSSrinivas Pandruvada "[hid-ish]: HID probe for #%u failed: %d\n",
7130b28cb4bSSrinivas Pandruvada i, rv);
7140b28cb4bSSrinivas Pandruvada goto err_cl_disconnect;
7150b28cb4bSSrinivas Pandruvada }
7160b28cb4bSSrinivas Pandruvada }
7170b28cb4bSSrinivas Pandruvada } /* for() on all hid devices */
7180b28cb4bSSrinivas Pandruvada
7190b28cb4bSSrinivas Pandruvada client_data->init_done = 1;
7200b28cb4bSSrinivas Pandruvada client_data->suspended = false;
7210b28cb4bSSrinivas Pandruvada wake_up_interruptible(&client_data->ishtp_resume_wait);
7220b28cb4bSSrinivas Pandruvada hid_ishtp_trace(client_data, "%s successful init\n", __func__);
7230b28cb4bSSrinivas Pandruvada return 0;
7240b28cb4bSSrinivas Pandruvada
7250b28cb4bSSrinivas Pandruvada err_cl_disconnect:
72629b06d12SSrinivas Pandruvada ishtp_set_connection_state(hid_ishtp_cl, ISHTP_CL_DISCONNECTING);
7270b28cb4bSSrinivas Pandruvada ishtp_cl_disconnect(hid_ishtp_cl);
7280b28cb4bSSrinivas Pandruvada err_cl_unlink:
7290b28cb4bSSrinivas Pandruvada ishtp_cl_unlink(hid_ishtp_cl);
7300b28cb4bSSrinivas Pandruvada return rv;
7310b28cb4bSSrinivas Pandruvada }
7320b28cb4bSSrinivas Pandruvada
7330b28cb4bSSrinivas Pandruvada /**
7340b28cb4bSSrinivas Pandruvada * hid_ishtp_cl_deinit() - Deinit function for ISHTP client
7350b28cb4bSSrinivas Pandruvada * @hid_ishtp_cl: ISHTP client instance
7360b28cb4bSSrinivas Pandruvada *
7370b28cb4bSSrinivas Pandruvada * Unlink and free hid client
7380b28cb4bSSrinivas Pandruvada */
hid_ishtp_cl_deinit(struct ishtp_cl * hid_ishtp_cl)7390b28cb4bSSrinivas Pandruvada static void hid_ishtp_cl_deinit(struct ishtp_cl *hid_ishtp_cl)
7400b28cb4bSSrinivas Pandruvada {
7410b28cb4bSSrinivas Pandruvada ishtp_cl_unlink(hid_ishtp_cl);
7420b28cb4bSSrinivas Pandruvada ishtp_cl_flush_queues(hid_ishtp_cl);
7430b28cb4bSSrinivas Pandruvada
7440b28cb4bSSrinivas Pandruvada /* disband and free all Tx and Rx client-level rings */
7450b28cb4bSSrinivas Pandruvada ishtp_cl_free(hid_ishtp_cl);
7460b28cb4bSSrinivas Pandruvada }
7470b28cb4bSSrinivas Pandruvada
hid_ishtp_cl_reset_handler(struct work_struct * work)7480b28cb4bSSrinivas Pandruvada static void hid_ishtp_cl_reset_handler(struct work_struct *work)
7490b28cb4bSSrinivas Pandruvada {
7500b28cb4bSSrinivas Pandruvada struct ishtp_cl_data *client_data;
7510b28cb4bSSrinivas Pandruvada struct ishtp_cl *hid_ishtp_cl;
7520b28cb4bSSrinivas Pandruvada struct ishtp_cl_device *cl_device;
7530b28cb4bSSrinivas Pandruvada int retry;
7540b28cb4bSSrinivas Pandruvada int rv;
7550b28cb4bSSrinivas Pandruvada
7560b28cb4bSSrinivas Pandruvada client_data = container_of(work, struct ishtp_cl_data, work);
7570b28cb4bSSrinivas Pandruvada
7580b28cb4bSSrinivas Pandruvada hid_ishtp_cl = client_data->hid_ishtp_cl;
7590b28cb4bSSrinivas Pandruvada cl_device = client_data->cl_device;
7600b28cb4bSSrinivas Pandruvada
7610b28cb4bSSrinivas Pandruvada hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__,
7620b28cb4bSSrinivas Pandruvada hid_ishtp_cl);
76329b06d12SSrinivas Pandruvada dev_dbg(ishtp_device(client_data->cl_device), "%s\n", __func__);
7640b28cb4bSSrinivas Pandruvada
7650b28cb4bSSrinivas Pandruvada hid_ishtp_cl_deinit(hid_ishtp_cl);
7660b28cb4bSSrinivas Pandruvada
7677ab21842SSrinivas Pandruvada hid_ishtp_cl = ishtp_cl_allocate(cl_device);
7680b28cb4bSSrinivas Pandruvada if (!hid_ishtp_cl)
7690b28cb4bSSrinivas Pandruvada return;
7700b28cb4bSSrinivas Pandruvada
771d174c666SEven Xu ishtp_set_drvdata(cl_device, hid_ishtp_cl);
77229b06d12SSrinivas Pandruvada ishtp_set_client_data(hid_ishtp_cl, client_data);
7730b28cb4bSSrinivas Pandruvada client_data->hid_ishtp_cl = hid_ishtp_cl;
7740b28cb4bSSrinivas Pandruvada
7750b28cb4bSSrinivas Pandruvada client_data->num_hid_devices = 0;
7760b28cb4bSSrinivas Pandruvada
7770b28cb4bSSrinivas Pandruvada for (retry = 0; retry < 3; ++retry) {
7780b28cb4bSSrinivas Pandruvada rv = hid_ishtp_cl_init(hid_ishtp_cl, 1);
7790b28cb4bSSrinivas Pandruvada if (!rv)
7800b28cb4bSSrinivas Pandruvada break;
7817ab21842SSrinivas Pandruvada dev_err(cl_data_to_dev(client_data), "Retry reset init\n");
7820b28cb4bSSrinivas Pandruvada }
7830b28cb4bSSrinivas Pandruvada if (rv) {
7847ab21842SSrinivas Pandruvada dev_err(cl_data_to_dev(client_data), "Reset Failed\n");
7850b28cb4bSSrinivas Pandruvada hid_ishtp_trace(client_data, "%s Failed hid_ishtp_cl %p\n",
7860b28cb4bSSrinivas Pandruvada __func__, hid_ishtp_cl);
7870b28cb4bSSrinivas Pandruvada }
7880b28cb4bSSrinivas Pandruvada }
7890b28cb4bSSrinivas Pandruvada
hid_ishtp_cl_resume_handler(struct work_struct * work)790e48bf29cSYe Xiang static void hid_ishtp_cl_resume_handler(struct work_struct *work)
791e48bf29cSYe Xiang {
792e48bf29cSYe Xiang struct ishtp_cl_data *client_data = container_of(work, struct ishtp_cl_data, resume_work);
793e48bf29cSYe Xiang struct ishtp_cl *hid_ishtp_cl = client_data->hid_ishtp_cl;
794e48bf29cSYe Xiang
795e48bf29cSYe Xiang if (ishtp_wait_resume(ishtp_get_ishtp_device(hid_ishtp_cl))) {
796e48bf29cSYe Xiang client_data->suspended = false;
797e48bf29cSYe Xiang wake_up_interruptible(&client_data->ishtp_resume_wait);
798e48bf29cSYe Xiang }
799e48bf29cSYe Xiang }
800e48bf29cSYe Xiang
801c57179c7SLee Jones ishtp_print_log ishtp_hid_print_trace;
8027ab21842SSrinivas Pandruvada
8030b28cb4bSSrinivas Pandruvada /**
8040b28cb4bSSrinivas Pandruvada * hid_ishtp_cl_probe() - ISHTP client driver probe
8050b28cb4bSSrinivas Pandruvada * @cl_device: ISHTP client device instance
8060b28cb4bSSrinivas Pandruvada *
8070b28cb4bSSrinivas Pandruvada * This function gets called on device create on ISHTP bus
8080b28cb4bSSrinivas Pandruvada *
8090b28cb4bSSrinivas Pandruvada * Return: 0 on success, non zero on error
8100b28cb4bSSrinivas Pandruvada */
hid_ishtp_cl_probe(struct ishtp_cl_device * cl_device)8110b28cb4bSSrinivas Pandruvada static int hid_ishtp_cl_probe(struct ishtp_cl_device *cl_device)
8120b28cb4bSSrinivas Pandruvada {
8130b28cb4bSSrinivas Pandruvada struct ishtp_cl *hid_ishtp_cl;
8140b28cb4bSSrinivas Pandruvada struct ishtp_cl_data *client_data;
8150b28cb4bSSrinivas Pandruvada int rv;
8160b28cb4bSSrinivas Pandruvada
8170b28cb4bSSrinivas Pandruvada if (!cl_device)
8180b28cb4bSSrinivas Pandruvada return -ENODEV;
8190b28cb4bSSrinivas Pandruvada
8207ab21842SSrinivas Pandruvada client_data = devm_kzalloc(ishtp_device(cl_device),
8217ab21842SSrinivas Pandruvada sizeof(*client_data),
8220b28cb4bSSrinivas Pandruvada GFP_KERNEL);
8230b28cb4bSSrinivas Pandruvada if (!client_data)
8240b28cb4bSSrinivas Pandruvada return -ENOMEM;
8250b28cb4bSSrinivas Pandruvada
8267ab21842SSrinivas Pandruvada hid_ishtp_cl = ishtp_cl_allocate(cl_device);
8270b28cb4bSSrinivas Pandruvada if (!hid_ishtp_cl)
8280b28cb4bSSrinivas Pandruvada return -ENOMEM;
8290b28cb4bSSrinivas Pandruvada
830d174c666SEven Xu ishtp_set_drvdata(cl_device, hid_ishtp_cl);
83129b06d12SSrinivas Pandruvada ishtp_set_client_data(hid_ishtp_cl, client_data);
8320b28cb4bSSrinivas Pandruvada client_data->hid_ishtp_cl = hid_ishtp_cl;
8330b28cb4bSSrinivas Pandruvada client_data->cl_device = cl_device;
8340b28cb4bSSrinivas Pandruvada
8350b28cb4bSSrinivas Pandruvada init_waitqueue_head(&client_data->init_wait);
8360b28cb4bSSrinivas Pandruvada init_waitqueue_head(&client_data->ishtp_resume_wait);
8370b28cb4bSSrinivas Pandruvada
8380b28cb4bSSrinivas Pandruvada INIT_WORK(&client_data->work, hid_ishtp_cl_reset_handler);
839e48bf29cSYe Xiang INIT_WORK(&client_data->resume_work, hid_ishtp_cl_resume_handler);
840e48bf29cSYe Xiang
8410b28cb4bSSrinivas Pandruvada
842c57179c7SLee Jones ishtp_hid_print_trace = ishtp_trace_callback(cl_device);
8437ab21842SSrinivas Pandruvada
8440b28cb4bSSrinivas Pandruvada rv = hid_ishtp_cl_init(hid_ishtp_cl, 0);
8450b28cb4bSSrinivas Pandruvada if (rv) {
8460b28cb4bSSrinivas Pandruvada ishtp_cl_free(hid_ishtp_cl);
8470b28cb4bSSrinivas Pandruvada return rv;
8480b28cb4bSSrinivas Pandruvada }
8490b28cb4bSSrinivas Pandruvada ishtp_get_device(cl_device);
8500b28cb4bSSrinivas Pandruvada
8510b28cb4bSSrinivas Pandruvada return 0;
8520b28cb4bSSrinivas Pandruvada }
8530b28cb4bSSrinivas Pandruvada
8540b28cb4bSSrinivas Pandruvada /**
8550b28cb4bSSrinivas Pandruvada * hid_ishtp_cl_remove() - ISHTP client driver remove
8560b28cb4bSSrinivas Pandruvada * @cl_device: ISHTP client device instance
8570b28cb4bSSrinivas Pandruvada *
8580b28cb4bSSrinivas Pandruvada * This function gets called on device remove on ISHTP bus
8590b28cb4bSSrinivas Pandruvada *
8600b28cb4bSSrinivas Pandruvada * Return: 0
8610b28cb4bSSrinivas Pandruvada */
hid_ishtp_cl_remove(struct ishtp_cl_device * cl_device)862e71da1fdSUwe Kleine-König static void hid_ishtp_cl_remove(struct ishtp_cl_device *cl_device)
8630b28cb4bSSrinivas Pandruvada {
864d174c666SEven Xu struct ishtp_cl *hid_ishtp_cl = ishtp_get_drvdata(cl_device);
86529b06d12SSrinivas Pandruvada struct ishtp_cl_data *client_data = ishtp_get_client_data(hid_ishtp_cl);
8660b28cb4bSSrinivas Pandruvada
8670b28cb4bSSrinivas Pandruvada hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__,
8680b28cb4bSSrinivas Pandruvada hid_ishtp_cl);
8690b28cb4bSSrinivas Pandruvada
8707ab21842SSrinivas Pandruvada dev_dbg(ishtp_device(cl_device), "%s\n", __func__);
87129b06d12SSrinivas Pandruvada ishtp_set_connection_state(hid_ishtp_cl, ISHTP_CL_DISCONNECTING);
8720b28cb4bSSrinivas Pandruvada ishtp_cl_disconnect(hid_ishtp_cl);
8730b28cb4bSSrinivas Pandruvada ishtp_put_device(cl_device);
8740b28cb4bSSrinivas Pandruvada ishtp_hid_remove(client_data);
8750b28cb4bSSrinivas Pandruvada hid_ishtp_cl_deinit(hid_ishtp_cl);
8760b28cb4bSSrinivas Pandruvada
8770b28cb4bSSrinivas Pandruvada hid_ishtp_cl = NULL;
8780b28cb4bSSrinivas Pandruvada
8790b28cb4bSSrinivas Pandruvada client_data->num_hid_devices = 0;
8800b28cb4bSSrinivas Pandruvada }
8810b28cb4bSSrinivas Pandruvada
8820b28cb4bSSrinivas Pandruvada /**
8830b28cb4bSSrinivas Pandruvada * hid_ishtp_cl_reset() - ISHTP client driver reset
8840b28cb4bSSrinivas Pandruvada * @cl_device: ISHTP client device instance
8850b28cb4bSSrinivas Pandruvada *
8860b28cb4bSSrinivas Pandruvada * This function gets called on device reset on ISHTP bus
8870b28cb4bSSrinivas Pandruvada *
8880b28cb4bSSrinivas Pandruvada * Return: 0
8890b28cb4bSSrinivas Pandruvada */
hid_ishtp_cl_reset(struct ishtp_cl_device * cl_device)8900b28cb4bSSrinivas Pandruvada static int hid_ishtp_cl_reset(struct ishtp_cl_device *cl_device)
8910b28cb4bSSrinivas Pandruvada {
892d174c666SEven Xu struct ishtp_cl *hid_ishtp_cl = ishtp_get_drvdata(cl_device);
89329b06d12SSrinivas Pandruvada struct ishtp_cl_data *client_data = ishtp_get_client_data(hid_ishtp_cl);
8940b28cb4bSSrinivas Pandruvada
8950b28cb4bSSrinivas Pandruvada hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__,
8960b28cb4bSSrinivas Pandruvada hid_ishtp_cl);
8970b28cb4bSSrinivas Pandruvada
8980b28cb4bSSrinivas Pandruvada schedule_work(&client_data->work);
8990b28cb4bSSrinivas Pandruvada
9000b28cb4bSSrinivas Pandruvada return 0;
9010b28cb4bSSrinivas Pandruvada }
9020b28cb4bSSrinivas Pandruvada
9030b28cb4bSSrinivas Pandruvada /**
9040b28cb4bSSrinivas Pandruvada * hid_ishtp_cl_suspend() - ISHTP client driver suspend
9050b28cb4bSSrinivas Pandruvada * @device: device instance
9060b28cb4bSSrinivas Pandruvada *
9070b28cb4bSSrinivas Pandruvada * This function gets called on system suspend
9080b28cb4bSSrinivas Pandruvada *
9090b28cb4bSSrinivas Pandruvada * Return: 0
9100b28cb4bSSrinivas Pandruvada */
hid_ishtp_cl_suspend(struct device * device)9110b28cb4bSSrinivas Pandruvada static int hid_ishtp_cl_suspend(struct device *device)
9120b28cb4bSSrinivas Pandruvada {
913b12bbdc5SHyungwoo Yang struct ishtp_cl_device *cl_device = ishtp_dev_to_cl_device(device);
914d174c666SEven Xu struct ishtp_cl *hid_ishtp_cl = ishtp_get_drvdata(cl_device);
91529b06d12SSrinivas Pandruvada struct ishtp_cl_data *client_data = ishtp_get_client_data(hid_ishtp_cl);
9160b28cb4bSSrinivas Pandruvada
9170b28cb4bSSrinivas Pandruvada hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__,
9180b28cb4bSSrinivas Pandruvada hid_ishtp_cl);
9190b28cb4bSSrinivas Pandruvada client_data->suspended = true;
9200b28cb4bSSrinivas Pandruvada
9210b28cb4bSSrinivas Pandruvada return 0;
9220b28cb4bSSrinivas Pandruvada }
9230b28cb4bSSrinivas Pandruvada
9240b28cb4bSSrinivas Pandruvada /**
9250b28cb4bSSrinivas Pandruvada * hid_ishtp_cl_resume() - ISHTP client driver resume
9260b28cb4bSSrinivas Pandruvada * @device: device instance
9270b28cb4bSSrinivas Pandruvada *
9280b28cb4bSSrinivas Pandruvada * This function gets called on system resume
9290b28cb4bSSrinivas Pandruvada *
9300b28cb4bSSrinivas Pandruvada * Return: 0
9310b28cb4bSSrinivas Pandruvada */
hid_ishtp_cl_resume(struct device * device)9320b28cb4bSSrinivas Pandruvada static int hid_ishtp_cl_resume(struct device *device)
9330b28cb4bSSrinivas Pandruvada {
934b12bbdc5SHyungwoo Yang struct ishtp_cl_device *cl_device = ishtp_dev_to_cl_device(device);
935d174c666SEven Xu struct ishtp_cl *hid_ishtp_cl = ishtp_get_drvdata(cl_device);
93629b06d12SSrinivas Pandruvada struct ishtp_cl_data *client_data = ishtp_get_client_data(hid_ishtp_cl);
9370b28cb4bSSrinivas Pandruvada
9380b28cb4bSSrinivas Pandruvada hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__,
9390b28cb4bSSrinivas Pandruvada hid_ishtp_cl);
940e48bf29cSYe Xiang schedule_work(&client_data->resume_work);
9410b28cb4bSSrinivas Pandruvada return 0;
9420b28cb4bSSrinivas Pandruvada }
9430b28cb4bSSrinivas Pandruvada
9440b28cb4bSSrinivas Pandruvada static const struct dev_pm_ops hid_ishtp_pm_ops = {
9450b28cb4bSSrinivas Pandruvada .suspend = hid_ishtp_cl_suspend,
9460b28cb4bSSrinivas Pandruvada .resume = hid_ishtp_cl_resume,
9470b28cb4bSSrinivas Pandruvada };
9480b28cb4bSSrinivas Pandruvada
9490b28cb4bSSrinivas Pandruvada static struct ishtp_cl_driver hid_ishtp_cl_driver = {
9500b28cb4bSSrinivas Pandruvada .name = "ish-hid",
951bf9167a8SArnd Bergmann .id = hid_ishtp_id_table,
9520b28cb4bSSrinivas Pandruvada .probe = hid_ishtp_cl_probe,
9530b28cb4bSSrinivas Pandruvada .remove = hid_ishtp_cl_remove,
9540b28cb4bSSrinivas Pandruvada .reset = hid_ishtp_cl_reset,
9550b28cb4bSSrinivas Pandruvada .driver.pm = &hid_ishtp_pm_ops,
9560b28cb4bSSrinivas Pandruvada };
9570b28cb4bSSrinivas Pandruvada
ish_hid_init(void)9580b28cb4bSSrinivas Pandruvada static int __init ish_hid_init(void)
9590b28cb4bSSrinivas Pandruvada {
9600b28cb4bSSrinivas Pandruvada int rv;
9610b28cb4bSSrinivas Pandruvada
9620b28cb4bSSrinivas Pandruvada /* Register ISHTP client device driver with ISHTP Bus */
963e00a864fSSrinivas Pandruvada rv = ishtp_cl_driver_register(&hid_ishtp_cl_driver, THIS_MODULE);
9640b28cb4bSSrinivas Pandruvada
9650b28cb4bSSrinivas Pandruvada return rv;
9660b28cb4bSSrinivas Pandruvada
9670b28cb4bSSrinivas Pandruvada }
9680b28cb4bSSrinivas Pandruvada
ish_hid_exit(void)9690b28cb4bSSrinivas Pandruvada static void __exit ish_hid_exit(void)
9700b28cb4bSSrinivas Pandruvada {
9710b28cb4bSSrinivas Pandruvada ishtp_cl_driver_unregister(&hid_ishtp_cl_driver);
9720b28cb4bSSrinivas Pandruvada }
9730b28cb4bSSrinivas Pandruvada
9740b28cb4bSSrinivas Pandruvada late_initcall(ish_hid_init);
9750b28cb4bSSrinivas Pandruvada module_exit(ish_hid_exit);
9760b28cb4bSSrinivas Pandruvada
9770b28cb4bSSrinivas Pandruvada MODULE_DESCRIPTION("ISH ISHTP HID client driver");
9780b28cb4bSSrinivas Pandruvada /* Primary author */
9790b28cb4bSSrinivas Pandruvada MODULE_AUTHOR("Daniel Drubin <daniel.drubin@intel.com>");
9800b28cb4bSSrinivas Pandruvada /*
9810b28cb4bSSrinivas Pandruvada * Several modification for multi instance support
9820b28cb4bSSrinivas Pandruvada * suspend/resume and clean up
9830b28cb4bSSrinivas Pandruvada */
9840b28cb4bSSrinivas Pandruvada MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
9850b28cb4bSSrinivas Pandruvada
9860b28cb4bSSrinivas Pandruvada MODULE_LICENSE("GPL");
987