10b28cb4bSSrinivas Pandruvada /* 20b28cb4bSSrinivas Pandruvada * ISHTP client driver for HID (ISH) 30b28cb4bSSrinivas Pandruvada * 40b28cb4bSSrinivas Pandruvada * Copyright (c) 2014-2016, Intel Corporation. 50b28cb4bSSrinivas Pandruvada * 60b28cb4bSSrinivas Pandruvada * This program is free software; you can redistribute it and/or modify it 70b28cb4bSSrinivas Pandruvada * under the terms and conditions of the GNU General Public License, 80b28cb4bSSrinivas Pandruvada * version 2, as published by the Free Software Foundation. 90b28cb4bSSrinivas Pandruvada * 100b28cb4bSSrinivas Pandruvada * This program is distributed in the hope it will be useful, but WITHOUT 110b28cb4bSSrinivas Pandruvada * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 120b28cb4bSSrinivas Pandruvada * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 130b28cb4bSSrinivas Pandruvada * more details. 140b28cb4bSSrinivas Pandruvada */ 150b28cb4bSSrinivas Pandruvada 160b28cb4bSSrinivas Pandruvada #include <linux/module.h> 170b28cb4bSSrinivas Pandruvada #include <linux/hid.h> 180b28cb4bSSrinivas Pandruvada #include <linux/sched.h> 190b28cb4bSSrinivas Pandruvada #include "ishtp/ishtp-dev.h" 200b28cb4bSSrinivas Pandruvada #include "ishtp/client.h" 210b28cb4bSSrinivas Pandruvada #include "ishtp-hid.h" 220b28cb4bSSrinivas Pandruvada 230b28cb4bSSrinivas Pandruvada /* Rx ring buffer pool size */ 240b28cb4bSSrinivas Pandruvada #define HID_CL_RX_RING_SIZE 32 250b28cb4bSSrinivas Pandruvada #define HID_CL_TX_RING_SIZE 16 260b28cb4bSSrinivas Pandruvada 270b28cb4bSSrinivas Pandruvada /** 280b28cb4bSSrinivas Pandruvada * report_bad_packets() - Report bad packets 290b28cb4bSSrinivas Pandruvada * @hid_ishtp_cl: Client instance to get stats 300b28cb4bSSrinivas Pandruvada * @recv_buf: Raw received host interface message 310b28cb4bSSrinivas Pandruvada * @cur_pos: Current position index in payload 320b28cb4bSSrinivas Pandruvada * @payload_len: Length of payload expected 330b28cb4bSSrinivas Pandruvada * 340b28cb4bSSrinivas Pandruvada * Dumps error in case bad packet is received 350b28cb4bSSrinivas Pandruvada */ 360b28cb4bSSrinivas Pandruvada static void report_bad_packet(struct ishtp_cl *hid_ishtp_cl, void *recv_buf, 370b28cb4bSSrinivas Pandruvada size_t cur_pos, size_t payload_len) 380b28cb4bSSrinivas Pandruvada { 390b28cb4bSSrinivas Pandruvada struct hostif_msg *recv_msg = recv_buf; 400b28cb4bSSrinivas Pandruvada struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data; 410b28cb4bSSrinivas Pandruvada 420b28cb4bSSrinivas Pandruvada dev_err(&client_data->cl_device->dev, "[hid-ish]: BAD packet %02X\n" 430b28cb4bSSrinivas Pandruvada "total_bad=%u cur_pos=%u\n" 440b28cb4bSSrinivas Pandruvada "[%02X %02X %02X %02X]\n" 450b28cb4bSSrinivas Pandruvada "payload_len=%u\n" 460b28cb4bSSrinivas Pandruvada "multi_packet_cnt=%u\n" 470b28cb4bSSrinivas Pandruvada "is_response=%02X\n", 480b28cb4bSSrinivas Pandruvada recv_msg->hdr.command, client_data->bad_recv_cnt, 490b28cb4bSSrinivas Pandruvada (unsigned int)cur_pos, 500b28cb4bSSrinivas Pandruvada ((unsigned char *)recv_msg)[0], ((unsigned char *)recv_msg)[1], 510b28cb4bSSrinivas Pandruvada ((unsigned char *)recv_msg)[2], ((unsigned char *)recv_msg)[3], 520b28cb4bSSrinivas Pandruvada (unsigned int)payload_len, client_data->multi_packet_cnt, 530b28cb4bSSrinivas Pandruvada recv_msg->hdr.command & ~CMD_MASK); 540b28cb4bSSrinivas Pandruvada } 550b28cb4bSSrinivas Pandruvada 560b28cb4bSSrinivas Pandruvada /** 570b28cb4bSSrinivas Pandruvada * process_recv() - Received and parse incoming packet 580b28cb4bSSrinivas Pandruvada * @hid_ishtp_cl: Client instance to get stats 590b28cb4bSSrinivas Pandruvada * @recv_buf: Raw received host interface message 600b28cb4bSSrinivas Pandruvada * @data_len: length of the message 610b28cb4bSSrinivas Pandruvada * 620b28cb4bSSrinivas Pandruvada * Parse the incoming packet. If it is a response packet then it will update 630b28cb4bSSrinivas Pandruvada * per instance flags and wake up the caller waiting to for the response. 640b28cb4bSSrinivas Pandruvada */ 650b28cb4bSSrinivas Pandruvada static void process_recv(struct ishtp_cl *hid_ishtp_cl, void *recv_buf, 660b28cb4bSSrinivas Pandruvada size_t data_len) 670b28cb4bSSrinivas Pandruvada { 680b28cb4bSSrinivas Pandruvada struct hostif_msg *recv_msg; 690b28cb4bSSrinivas Pandruvada unsigned char *payload; 700b28cb4bSSrinivas Pandruvada struct device_info *dev_info; 710b28cb4bSSrinivas Pandruvada int i, j; 720b28cb4bSSrinivas Pandruvada size_t payload_len, total_len, cur_pos; 730b28cb4bSSrinivas Pandruvada int report_type; 740b28cb4bSSrinivas Pandruvada struct report_list *reports_list; 750b28cb4bSSrinivas Pandruvada char *reports; 760b28cb4bSSrinivas Pandruvada size_t report_len; 770b28cb4bSSrinivas Pandruvada struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data; 780b28cb4bSSrinivas Pandruvada int curr_hid_dev = client_data->cur_hid_dev; 790b28cb4bSSrinivas Pandruvada 800b28cb4bSSrinivas Pandruvada if (data_len < sizeof(struct hostif_msg_hdr)) { 810b28cb4bSSrinivas Pandruvada dev_err(&client_data->cl_device->dev, 820b28cb4bSSrinivas Pandruvada "[hid-ish]: error, received %u which is less than data header %u\n", 830b28cb4bSSrinivas Pandruvada (unsigned int)data_len, 840b28cb4bSSrinivas Pandruvada (unsigned int)sizeof(struct hostif_msg_hdr)); 850b28cb4bSSrinivas Pandruvada ++client_data->bad_recv_cnt; 860b28cb4bSSrinivas Pandruvada ish_hw_reset(hid_ishtp_cl->dev); 870b28cb4bSSrinivas Pandruvada return; 880b28cb4bSSrinivas Pandruvada } 890b28cb4bSSrinivas Pandruvada 900b28cb4bSSrinivas Pandruvada payload = recv_buf + sizeof(struct hostif_msg_hdr); 910b28cb4bSSrinivas Pandruvada total_len = data_len; 920b28cb4bSSrinivas Pandruvada cur_pos = 0; 930b28cb4bSSrinivas Pandruvada 940b28cb4bSSrinivas Pandruvada do { 950b28cb4bSSrinivas Pandruvada recv_msg = (struct hostif_msg *)(recv_buf + cur_pos); 960b28cb4bSSrinivas Pandruvada payload_len = recv_msg->hdr.size; 970b28cb4bSSrinivas Pandruvada 980b28cb4bSSrinivas Pandruvada /* Sanity checks */ 990b28cb4bSSrinivas Pandruvada if (cur_pos + payload_len + sizeof(struct hostif_msg) > 1000b28cb4bSSrinivas Pandruvada total_len) { 1010b28cb4bSSrinivas Pandruvada ++client_data->bad_recv_cnt; 1020b28cb4bSSrinivas Pandruvada report_bad_packet(hid_ishtp_cl, recv_msg, cur_pos, 1030b28cb4bSSrinivas Pandruvada payload_len); 1040b28cb4bSSrinivas Pandruvada ish_hw_reset(hid_ishtp_cl->dev); 1050b28cb4bSSrinivas Pandruvada break; 1060b28cb4bSSrinivas Pandruvada } 1070b28cb4bSSrinivas Pandruvada 1080b28cb4bSSrinivas Pandruvada hid_ishtp_trace(client_data, "%s %d\n", 1090b28cb4bSSrinivas Pandruvada __func__, recv_msg->hdr.command & CMD_MASK); 1100b28cb4bSSrinivas Pandruvada 1110b28cb4bSSrinivas Pandruvada switch (recv_msg->hdr.command & CMD_MASK) { 1120b28cb4bSSrinivas Pandruvada case HOSTIF_DM_ENUM_DEVICES: 1130b28cb4bSSrinivas Pandruvada if ((!(recv_msg->hdr.command & ~CMD_MASK) || 1140b28cb4bSSrinivas Pandruvada client_data->init_done)) { 1150b28cb4bSSrinivas Pandruvada ++client_data->bad_recv_cnt; 1160b28cb4bSSrinivas Pandruvada report_bad_packet(hid_ishtp_cl, recv_msg, 1170b28cb4bSSrinivas Pandruvada cur_pos, 1180b28cb4bSSrinivas Pandruvada payload_len); 1190b28cb4bSSrinivas Pandruvada ish_hw_reset(hid_ishtp_cl->dev); 1200b28cb4bSSrinivas Pandruvada break; 1210b28cb4bSSrinivas Pandruvada } 1220b28cb4bSSrinivas Pandruvada client_data->hid_dev_count = (unsigned int)*payload; 1230b28cb4bSSrinivas Pandruvada if (!client_data->hid_devices) 1240b28cb4bSSrinivas Pandruvada client_data->hid_devices = devm_kzalloc( 1250b28cb4bSSrinivas Pandruvada &client_data->cl_device->dev, 1260b28cb4bSSrinivas Pandruvada client_data->hid_dev_count * 1270b28cb4bSSrinivas Pandruvada sizeof(struct device_info), 1280b28cb4bSSrinivas Pandruvada GFP_KERNEL); 1290b28cb4bSSrinivas Pandruvada if (!client_data->hid_devices) { 1300b28cb4bSSrinivas Pandruvada dev_err(&client_data->cl_device->dev, 1310b28cb4bSSrinivas Pandruvada "Mem alloc failed for hid device info\n"); 1320b28cb4bSSrinivas Pandruvada wake_up_interruptible(&client_data->init_wait); 1330b28cb4bSSrinivas Pandruvada break; 1340b28cb4bSSrinivas Pandruvada } 1350b28cb4bSSrinivas Pandruvada for (i = 0; i < client_data->hid_dev_count; ++i) { 1360b28cb4bSSrinivas Pandruvada if (1 + sizeof(struct device_info) * i >= 1370b28cb4bSSrinivas Pandruvada payload_len) { 1380b28cb4bSSrinivas Pandruvada dev_err(&client_data->cl_device->dev, 139318fc2a8SArnd Bergmann "[hid-ish]: [ENUM_DEVICES]: content size %zu is bigger than payload_len %zu\n", 1400b28cb4bSSrinivas Pandruvada 1 + sizeof(struct device_info) 141318fc2a8SArnd Bergmann * i, payload_len); 1420b28cb4bSSrinivas Pandruvada } 1430b28cb4bSSrinivas Pandruvada 1440b28cb4bSSrinivas Pandruvada if (1 + sizeof(struct device_info) * i >= 1450b28cb4bSSrinivas Pandruvada data_len) 1460b28cb4bSSrinivas Pandruvada break; 1470b28cb4bSSrinivas Pandruvada 1480b28cb4bSSrinivas Pandruvada dev_info = (struct device_info *)(payload + 1 + 1490b28cb4bSSrinivas Pandruvada sizeof(struct device_info) * i); 1500b28cb4bSSrinivas Pandruvada if (client_data->hid_devices) 1510b28cb4bSSrinivas Pandruvada memcpy(client_data->hid_devices + i, 1520b28cb4bSSrinivas Pandruvada dev_info, 1530b28cb4bSSrinivas Pandruvada sizeof(struct device_info)); 1540b28cb4bSSrinivas Pandruvada } 1550b28cb4bSSrinivas Pandruvada 1560b28cb4bSSrinivas Pandruvada client_data->enum_devices_done = true; 1570b28cb4bSSrinivas Pandruvada wake_up_interruptible(&client_data->init_wait); 1580b28cb4bSSrinivas Pandruvada 1590b28cb4bSSrinivas Pandruvada break; 1600b28cb4bSSrinivas Pandruvada 1610b28cb4bSSrinivas Pandruvada case HOSTIF_GET_HID_DESCRIPTOR: 1620b28cb4bSSrinivas Pandruvada if ((!(recv_msg->hdr.command & ~CMD_MASK) || 1630b28cb4bSSrinivas Pandruvada client_data->init_done)) { 1640b28cb4bSSrinivas Pandruvada ++client_data->bad_recv_cnt; 1650b28cb4bSSrinivas Pandruvada report_bad_packet(hid_ishtp_cl, recv_msg, 1660b28cb4bSSrinivas Pandruvada cur_pos, 1670b28cb4bSSrinivas Pandruvada payload_len); 1680b28cb4bSSrinivas Pandruvada ish_hw_reset(hid_ishtp_cl->dev); 1690b28cb4bSSrinivas Pandruvada break; 1700b28cb4bSSrinivas Pandruvada } 1710b28cb4bSSrinivas Pandruvada if (!client_data->hid_descr[curr_hid_dev]) 1720b28cb4bSSrinivas Pandruvada client_data->hid_descr[curr_hid_dev] = 1730b28cb4bSSrinivas Pandruvada devm_kmalloc(&client_data->cl_device->dev, 1740b28cb4bSSrinivas Pandruvada payload_len, GFP_KERNEL); 1750b28cb4bSSrinivas Pandruvada if (client_data->hid_descr[curr_hid_dev]) { 1760b28cb4bSSrinivas Pandruvada memcpy(client_data->hid_descr[curr_hid_dev], 1770b28cb4bSSrinivas Pandruvada payload, payload_len); 1780b28cb4bSSrinivas Pandruvada client_data->hid_descr_size[curr_hid_dev] = 1790b28cb4bSSrinivas Pandruvada payload_len; 1800b28cb4bSSrinivas Pandruvada client_data->hid_descr_done = true; 1810b28cb4bSSrinivas Pandruvada } 1820b28cb4bSSrinivas Pandruvada wake_up_interruptible(&client_data->init_wait); 1830b28cb4bSSrinivas Pandruvada 1840b28cb4bSSrinivas Pandruvada break; 1850b28cb4bSSrinivas Pandruvada 1860b28cb4bSSrinivas Pandruvada case HOSTIF_GET_REPORT_DESCRIPTOR: 1870b28cb4bSSrinivas Pandruvada if ((!(recv_msg->hdr.command & ~CMD_MASK) || 1880b28cb4bSSrinivas Pandruvada client_data->init_done)) { 1890b28cb4bSSrinivas Pandruvada ++client_data->bad_recv_cnt; 1900b28cb4bSSrinivas Pandruvada report_bad_packet(hid_ishtp_cl, recv_msg, 1910b28cb4bSSrinivas Pandruvada cur_pos, 1920b28cb4bSSrinivas Pandruvada payload_len); 1930b28cb4bSSrinivas Pandruvada ish_hw_reset(hid_ishtp_cl->dev); 1940b28cb4bSSrinivas Pandruvada break; 1950b28cb4bSSrinivas Pandruvada } 1960b28cb4bSSrinivas Pandruvada if (!client_data->report_descr[curr_hid_dev]) 1970b28cb4bSSrinivas Pandruvada client_data->report_descr[curr_hid_dev] = 1980b28cb4bSSrinivas Pandruvada devm_kmalloc(&client_data->cl_device->dev, 1990b28cb4bSSrinivas Pandruvada payload_len, GFP_KERNEL); 2000b28cb4bSSrinivas Pandruvada if (client_data->report_descr[curr_hid_dev]) { 2010b28cb4bSSrinivas Pandruvada memcpy(client_data->report_descr[curr_hid_dev], 2020b28cb4bSSrinivas Pandruvada payload, 2030b28cb4bSSrinivas Pandruvada payload_len); 2040b28cb4bSSrinivas Pandruvada client_data->report_descr_size[curr_hid_dev] = 2050b28cb4bSSrinivas Pandruvada payload_len; 2060b28cb4bSSrinivas Pandruvada client_data->report_descr_done = true; 2070b28cb4bSSrinivas Pandruvada } 2080b28cb4bSSrinivas Pandruvada wake_up_interruptible(&client_data->init_wait); 2090b28cb4bSSrinivas Pandruvada 2100b28cb4bSSrinivas Pandruvada break; 2110b28cb4bSSrinivas Pandruvada 2120b28cb4bSSrinivas Pandruvada case HOSTIF_GET_FEATURE_REPORT: 2130b28cb4bSSrinivas Pandruvada report_type = HID_FEATURE_REPORT; 2140b28cb4bSSrinivas Pandruvada goto do_get_report; 2150b28cb4bSSrinivas Pandruvada 2160b28cb4bSSrinivas Pandruvada case HOSTIF_GET_INPUT_REPORT: 2170b28cb4bSSrinivas Pandruvada report_type = HID_INPUT_REPORT; 2180b28cb4bSSrinivas Pandruvada do_get_report: 2190b28cb4bSSrinivas Pandruvada /* Get index of device that matches this id */ 2200b28cb4bSSrinivas Pandruvada for (i = 0; i < client_data->num_hid_devices; ++i) { 2210b28cb4bSSrinivas Pandruvada if (recv_msg->hdr.device_id == 2220b28cb4bSSrinivas Pandruvada client_data->hid_devices[i].dev_id) 2230b28cb4bSSrinivas Pandruvada if (client_data->hid_sensor_hubs[i]) { 2240b28cb4bSSrinivas Pandruvada hid_input_report( 2250b28cb4bSSrinivas Pandruvada client_data->hid_sensor_hubs[ 2260b28cb4bSSrinivas Pandruvada i], 2270b28cb4bSSrinivas Pandruvada report_type, payload, 2280b28cb4bSSrinivas Pandruvada payload_len, 0); 2290b28cb4bSSrinivas Pandruvada ishtp_hid_wakeup( 2300b28cb4bSSrinivas Pandruvada client_data->hid_sensor_hubs[ 2310b28cb4bSSrinivas Pandruvada i]); 2320b28cb4bSSrinivas Pandruvada break; 2330b28cb4bSSrinivas Pandruvada } 2340b28cb4bSSrinivas Pandruvada } 2350b28cb4bSSrinivas Pandruvada break; 2360b28cb4bSSrinivas Pandruvada 2370b28cb4bSSrinivas Pandruvada case HOSTIF_SET_FEATURE_REPORT: 2380b28cb4bSSrinivas Pandruvada /* Get index of device that matches this id */ 2390b28cb4bSSrinivas Pandruvada for (i = 0; i < client_data->num_hid_devices; ++i) { 2400b28cb4bSSrinivas Pandruvada if (recv_msg->hdr.device_id == 2410b28cb4bSSrinivas Pandruvada client_data->hid_devices[i].dev_id) 2420b28cb4bSSrinivas Pandruvada if (client_data->hid_sensor_hubs[i]) { 2430b28cb4bSSrinivas Pandruvada ishtp_hid_wakeup( 2440b28cb4bSSrinivas Pandruvada client_data->hid_sensor_hubs[ 2450b28cb4bSSrinivas Pandruvada i]); 2460b28cb4bSSrinivas Pandruvada break; 2470b28cb4bSSrinivas Pandruvada } 2480b28cb4bSSrinivas Pandruvada } 2490b28cb4bSSrinivas Pandruvada break; 2500b28cb4bSSrinivas Pandruvada 2510b28cb4bSSrinivas Pandruvada case HOSTIF_PUBLISH_INPUT_REPORT: 2520b28cb4bSSrinivas Pandruvada report_type = HID_INPUT_REPORT; 2530b28cb4bSSrinivas Pandruvada for (i = 0; i < client_data->num_hid_devices; ++i) 2540b28cb4bSSrinivas Pandruvada if (recv_msg->hdr.device_id == 2550b28cb4bSSrinivas Pandruvada client_data->hid_devices[i].dev_id) 2560b28cb4bSSrinivas Pandruvada if (client_data->hid_sensor_hubs[i]) 2570b28cb4bSSrinivas Pandruvada hid_input_report( 2580b28cb4bSSrinivas Pandruvada client_data->hid_sensor_hubs[ 2590b28cb4bSSrinivas Pandruvada i], 2600b28cb4bSSrinivas Pandruvada report_type, payload, 2610b28cb4bSSrinivas Pandruvada payload_len, 0); 2620b28cb4bSSrinivas Pandruvada break; 2630b28cb4bSSrinivas Pandruvada 2640b28cb4bSSrinivas Pandruvada case HOSTIF_PUBLISH_INPUT_REPORT_LIST: 2650b28cb4bSSrinivas Pandruvada report_type = HID_INPUT_REPORT; 2660b28cb4bSSrinivas Pandruvada reports_list = (struct report_list *)payload; 2670b28cb4bSSrinivas Pandruvada reports = (char *)reports_list->reports; 2680b28cb4bSSrinivas Pandruvada 2690b28cb4bSSrinivas Pandruvada for (j = 0; j < reports_list->num_of_reports; j++) { 2700b28cb4bSSrinivas Pandruvada recv_msg = (struct hostif_msg *)(reports + 2710b28cb4bSSrinivas Pandruvada sizeof(uint16_t)); 2720b28cb4bSSrinivas Pandruvada report_len = *(uint16_t *)reports; 2730b28cb4bSSrinivas Pandruvada payload = reports + sizeof(uint16_t) + 2740b28cb4bSSrinivas Pandruvada sizeof(struct hostif_msg_hdr); 2750b28cb4bSSrinivas Pandruvada payload_len = report_len - 2760b28cb4bSSrinivas Pandruvada sizeof(struct hostif_msg_hdr); 2770b28cb4bSSrinivas Pandruvada 2780b28cb4bSSrinivas Pandruvada for (i = 0; i < client_data->num_hid_devices; 2790b28cb4bSSrinivas Pandruvada ++i) 2800b28cb4bSSrinivas Pandruvada if (recv_msg->hdr.device_id == 2810b28cb4bSSrinivas Pandruvada client_data->hid_devices[i].dev_id && 2820b28cb4bSSrinivas Pandruvada client_data->hid_sensor_hubs[i]) { 2830b28cb4bSSrinivas Pandruvada hid_input_report( 2840b28cb4bSSrinivas Pandruvada client_data->hid_sensor_hubs[ 2850b28cb4bSSrinivas Pandruvada i], 2860b28cb4bSSrinivas Pandruvada report_type, 2870b28cb4bSSrinivas Pandruvada payload, payload_len, 2880b28cb4bSSrinivas Pandruvada 0); 2890b28cb4bSSrinivas Pandruvada } 2900b28cb4bSSrinivas Pandruvada 2910b28cb4bSSrinivas Pandruvada reports += sizeof(uint16_t) + report_len; 2920b28cb4bSSrinivas Pandruvada } 2930b28cb4bSSrinivas Pandruvada break; 2940b28cb4bSSrinivas Pandruvada default: 2950b28cb4bSSrinivas Pandruvada ++client_data->bad_recv_cnt; 2960b28cb4bSSrinivas Pandruvada report_bad_packet(hid_ishtp_cl, recv_msg, cur_pos, 2970b28cb4bSSrinivas Pandruvada payload_len); 2980b28cb4bSSrinivas Pandruvada ish_hw_reset(hid_ishtp_cl->dev); 2990b28cb4bSSrinivas Pandruvada break; 3000b28cb4bSSrinivas Pandruvada 3010b28cb4bSSrinivas Pandruvada } 3020b28cb4bSSrinivas Pandruvada 3030b28cb4bSSrinivas Pandruvada if (!cur_pos && cur_pos + payload_len + 3040b28cb4bSSrinivas Pandruvada sizeof(struct hostif_msg) < total_len) 3050b28cb4bSSrinivas Pandruvada ++client_data->multi_packet_cnt; 3060b28cb4bSSrinivas Pandruvada 3070b28cb4bSSrinivas Pandruvada cur_pos += payload_len + sizeof(struct hostif_msg); 3080b28cb4bSSrinivas Pandruvada payload += payload_len + sizeof(struct hostif_msg); 3090b28cb4bSSrinivas Pandruvada 3100b28cb4bSSrinivas Pandruvada } while (cur_pos < total_len); 3110b28cb4bSSrinivas Pandruvada } 3120b28cb4bSSrinivas Pandruvada 3130b28cb4bSSrinivas Pandruvada /** 3140b28cb4bSSrinivas Pandruvada * ish_cl_event_cb() - bus driver callback for incoming message/packet 3150b28cb4bSSrinivas Pandruvada * @device: Pointer to the the ishtp client device for which this message 3160b28cb4bSSrinivas Pandruvada * is targeted 3170b28cb4bSSrinivas Pandruvada * 3180b28cb4bSSrinivas Pandruvada * Remove the packet from the list and process the message by calling 3190b28cb4bSSrinivas Pandruvada * process_recv 3200b28cb4bSSrinivas Pandruvada */ 3210b28cb4bSSrinivas Pandruvada static void ish_cl_event_cb(struct ishtp_cl_device *device) 3220b28cb4bSSrinivas Pandruvada { 3230b28cb4bSSrinivas Pandruvada struct ishtp_cl *hid_ishtp_cl = device->driver_data; 3240b28cb4bSSrinivas Pandruvada struct ishtp_cl_rb *rb_in_proc; 3250b28cb4bSSrinivas Pandruvada size_t r_length; 3260b28cb4bSSrinivas Pandruvada unsigned long flags; 3270b28cb4bSSrinivas Pandruvada 3280b28cb4bSSrinivas Pandruvada if (!hid_ishtp_cl) 3290b28cb4bSSrinivas Pandruvada return; 3300b28cb4bSSrinivas Pandruvada 3310b28cb4bSSrinivas Pandruvada spin_lock_irqsave(&hid_ishtp_cl->in_process_spinlock, flags); 3320b28cb4bSSrinivas Pandruvada while (!list_empty(&hid_ishtp_cl->in_process_list.list)) { 3330b28cb4bSSrinivas Pandruvada rb_in_proc = list_entry( 3340b28cb4bSSrinivas Pandruvada hid_ishtp_cl->in_process_list.list.next, 3350b28cb4bSSrinivas Pandruvada struct ishtp_cl_rb, list); 3360b28cb4bSSrinivas Pandruvada list_del_init(&rb_in_proc->list); 3370b28cb4bSSrinivas Pandruvada spin_unlock_irqrestore(&hid_ishtp_cl->in_process_spinlock, 3380b28cb4bSSrinivas Pandruvada flags); 3390b28cb4bSSrinivas Pandruvada 3400b28cb4bSSrinivas Pandruvada if (!rb_in_proc->buffer.data) 3410b28cb4bSSrinivas Pandruvada return; 3420b28cb4bSSrinivas Pandruvada 3430b28cb4bSSrinivas Pandruvada r_length = rb_in_proc->buf_idx; 3440b28cb4bSSrinivas Pandruvada 3450b28cb4bSSrinivas Pandruvada /* decide what to do with received data */ 3460b28cb4bSSrinivas Pandruvada process_recv(hid_ishtp_cl, rb_in_proc->buffer.data, r_length); 3470b28cb4bSSrinivas Pandruvada 3480b28cb4bSSrinivas Pandruvada ishtp_cl_io_rb_recycle(rb_in_proc); 3490b28cb4bSSrinivas Pandruvada spin_lock_irqsave(&hid_ishtp_cl->in_process_spinlock, flags); 3500b28cb4bSSrinivas Pandruvada } 3510b28cb4bSSrinivas Pandruvada spin_unlock_irqrestore(&hid_ishtp_cl->in_process_spinlock, flags); 3520b28cb4bSSrinivas Pandruvada } 3530b28cb4bSSrinivas Pandruvada 3540b28cb4bSSrinivas Pandruvada /** 3550b28cb4bSSrinivas Pandruvada * hid_ishtp_set_feature() - send request to ISH FW to set a feature request 3560b28cb4bSSrinivas Pandruvada * @hid: hid device instance for this request 3570b28cb4bSSrinivas Pandruvada * @buf: feature buffer 3580b28cb4bSSrinivas Pandruvada * @len: Length of feature buffer 3590b28cb4bSSrinivas Pandruvada * @report_id: Report id for the feature set request 3600b28cb4bSSrinivas Pandruvada * 3610b28cb4bSSrinivas Pandruvada * This is called from hid core .request() callback. This function doesn't wait 3620b28cb4bSSrinivas Pandruvada * for response. 3630b28cb4bSSrinivas Pandruvada */ 3640b28cb4bSSrinivas Pandruvada void hid_ishtp_set_feature(struct hid_device *hid, char *buf, unsigned int len, 3650b28cb4bSSrinivas Pandruvada int report_id) 3660b28cb4bSSrinivas Pandruvada { 3670b28cb4bSSrinivas Pandruvada struct ishtp_hid_data *hid_data = hid->driver_data; 3680b28cb4bSSrinivas Pandruvada struct ishtp_cl_data *client_data = hid_data->client_data; 3690b28cb4bSSrinivas Pandruvada struct hostif_msg *msg = (struct hostif_msg *)buf; 3700b28cb4bSSrinivas Pandruvada int rv; 3710b28cb4bSSrinivas Pandruvada int i; 3720b28cb4bSSrinivas Pandruvada 3730b28cb4bSSrinivas Pandruvada hid_ishtp_trace(client_data, "%s hid %p\n", __func__, hid); 3740b28cb4bSSrinivas Pandruvada 3750b28cb4bSSrinivas Pandruvada rv = ishtp_hid_link_ready_wait(client_data); 3760b28cb4bSSrinivas Pandruvada if (rv) { 3770b28cb4bSSrinivas Pandruvada hid_ishtp_trace(client_data, "%s hid %p link not ready\n", 3780b28cb4bSSrinivas Pandruvada __func__, hid); 3790b28cb4bSSrinivas Pandruvada return; 3800b28cb4bSSrinivas Pandruvada } 3810b28cb4bSSrinivas Pandruvada 3820b28cb4bSSrinivas Pandruvada memset(msg, 0, sizeof(struct hostif_msg)); 3830b28cb4bSSrinivas Pandruvada msg->hdr.command = HOSTIF_SET_FEATURE_REPORT; 3840b28cb4bSSrinivas Pandruvada for (i = 0; i < client_data->num_hid_devices; ++i) { 3850b28cb4bSSrinivas Pandruvada if (hid == client_data->hid_sensor_hubs[i]) { 3860b28cb4bSSrinivas Pandruvada msg->hdr.device_id = 3870b28cb4bSSrinivas Pandruvada client_data->hid_devices[i].dev_id; 3880b28cb4bSSrinivas Pandruvada break; 3890b28cb4bSSrinivas Pandruvada } 3900b28cb4bSSrinivas Pandruvada } 3910b28cb4bSSrinivas Pandruvada 3920b28cb4bSSrinivas Pandruvada if (i == client_data->num_hid_devices) 3930b28cb4bSSrinivas Pandruvada return; 3940b28cb4bSSrinivas Pandruvada 3950b28cb4bSSrinivas Pandruvada rv = ishtp_cl_send(client_data->hid_ishtp_cl, buf, len); 3960b28cb4bSSrinivas Pandruvada if (rv) 3970b28cb4bSSrinivas Pandruvada hid_ishtp_trace(client_data, "%s hid %p send failed\n", 3980b28cb4bSSrinivas Pandruvada __func__, hid); 3990b28cb4bSSrinivas Pandruvada } 4000b28cb4bSSrinivas Pandruvada 4010b28cb4bSSrinivas Pandruvada /** 4020b28cb4bSSrinivas Pandruvada * hid_ishtp_get_report() - request to get feature/input report 4030b28cb4bSSrinivas Pandruvada * @hid: hid device instance for this request 4040b28cb4bSSrinivas Pandruvada * @report_id: Report id for the get request 4050b28cb4bSSrinivas Pandruvada * @report_type: Report type for the this request 4060b28cb4bSSrinivas Pandruvada * 4070b28cb4bSSrinivas Pandruvada * This is called from hid core .request() callback. This function will send 4080b28cb4bSSrinivas Pandruvada * request to FW and return without waiting for response. 4090b28cb4bSSrinivas Pandruvada */ 4100b28cb4bSSrinivas Pandruvada void hid_ishtp_get_report(struct hid_device *hid, int report_id, 4110b28cb4bSSrinivas Pandruvada int report_type) 4120b28cb4bSSrinivas Pandruvada { 4130b28cb4bSSrinivas Pandruvada struct ishtp_hid_data *hid_data = hid->driver_data; 4140b28cb4bSSrinivas Pandruvada struct ishtp_cl_data *client_data = hid_data->client_data; 4150b28cb4bSSrinivas Pandruvada static unsigned char buf[10]; 4160b28cb4bSSrinivas Pandruvada unsigned int len; 4170b28cb4bSSrinivas Pandruvada struct hostif_msg_to_sensor *msg = (struct hostif_msg_to_sensor *)buf; 4180b28cb4bSSrinivas Pandruvada int rv; 4190b28cb4bSSrinivas Pandruvada int i; 4200b28cb4bSSrinivas Pandruvada 4210b28cb4bSSrinivas Pandruvada hid_ishtp_trace(client_data, "%s hid %p\n", __func__, hid); 4220b28cb4bSSrinivas Pandruvada rv = ishtp_hid_link_ready_wait(client_data); 4230b28cb4bSSrinivas Pandruvada if (rv) { 4240b28cb4bSSrinivas Pandruvada hid_ishtp_trace(client_data, "%s hid %p link not ready\n", 4250b28cb4bSSrinivas Pandruvada __func__, hid); 4260b28cb4bSSrinivas Pandruvada return; 4270b28cb4bSSrinivas Pandruvada } 4280b28cb4bSSrinivas Pandruvada 4290b28cb4bSSrinivas Pandruvada len = sizeof(struct hostif_msg_to_sensor); 4300b28cb4bSSrinivas Pandruvada 4310b28cb4bSSrinivas Pandruvada memset(msg, 0, sizeof(struct hostif_msg_to_sensor)); 4320b28cb4bSSrinivas Pandruvada 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]) { 4360b28cb4bSSrinivas Pandruvada 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 4450b28cb4bSSrinivas Pandruvada msg->report_id = report_id; 4460b28cb4bSSrinivas Pandruvada rv = ishtp_cl_send(client_data->hid_ishtp_cl, buf, len); 4470b28cb4bSSrinivas Pandruvada if (rv) 4480b28cb4bSSrinivas Pandruvada hid_ishtp_trace(client_data, "%s hid %p send failed\n", 4490b28cb4bSSrinivas Pandruvada __func__, hid); 4500b28cb4bSSrinivas Pandruvada } 4510b28cb4bSSrinivas Pandruvada 4520b28cb4bSSrinivas Pandruvada /** 4530b28cb4bSSrinivas Pandruvada * ishtp_hid_link_ready_wait() - Wait for link ready 4540b28cb4bSSrinivas Pandruvada * @client_data: client data instance 4550b28cb4bSSrinivas Pandruvada * 4560b28cb4bSSrinivas Pandruvada * If the transport link started suspend process, then wait, till either 4570b28cb4bSSrinivas Pandruvada * resumed or timeout 4580b28cb4bSSrinivas Pandruvada * 4590b28cb4bSSrinivas Pandruvada * Return: 0 on success, non zero on error 4600b28cb4bSSrinivas Pandruvada */ 4610b28cb4bSSrinivas Pandruvada int ishtp_hid_link_ready_wait(struct ishtp_cl_data *client_data) 4620b28cb4bSSrinivas Pandruvada { 4630b28cb4bSSrinivas Pandruvada int rc; 4640b28cb4bSSrinivas Pandruvada 4650b28cb4bSSrinivas Pandruvada if (client_data->suspended) { 4660b28cb4bSSrinivas Pandruvada hid_ishtp_trace(client_data, "wait for link ready\n"); 4670b28cb4bSSrinivas Pandruvada rc = wait_event_interruptible_timeout( 4680b28cb4bSSrinivas Pandruvada client_data->ishtp_resume_wait, 4690b28cb4bSSrinivas Pandruvada !client_data->suspended, 4700b28cb4bSSrinivas Pandruvada 5 * HZ); 4710b28cb4bSSrinivas Pandruvada 4720b28cb4bSSrinivas Pandruvada if (rc == 0) { 4730b28cb4bSSrinivas Pandruvada hid_ishtp_trace(client_data, "link not ready\n"); 4740b28cb4bSSrinivas Pandruvada return -EIO; 4750b28cb4bSSrinivas Pandruvada } 4760b28cb4bSSrinivas Pandruvada hid_ishtp_trace(client_data, "link ready\n"); 4770b28cb4bSSrinivas Pandruvada } 4780b28cb4bSSrinivas Pandruvada 4790b28cb4bSSrinivas Pandruvada return 0; 4800b28cb4bSSrinivas Pandruvada } 4810b28cb4bSSrinivas Pandruvada 4820b28cb4bSSrinivas Pandruvada /** 4830b28cb4bSSrinivas Pandruvada * ishtp_enum_enum_devices() - Enumerate hid devices 4840b28cb4bSSrinivas Pandruvada * @hid_ishtp_cl: client instance 4850b28cb4bSSrinivas Pandruvada * 4860b28cb4bSSrinivas Pandruvada * Helper function to send request to firmware to enumerate HID devices 4870b28cb4bSSrinivas Pandruvada * 4880b28cb4bSSrinivas Pandruvada * Return: 0 on success, non zero on error 4890b28cb4bSSrinivas Pandruvada */ 4900b28cb4bSSrinivas Pandruvada static int ishtp_enum_enum_devices(struct ishtp_cl *hid_ishtp_cl) 4910b28cb4bSSrinivas Pandruvada { 4920b28cb4bSSrinivas Pandruvada struct hostif_msg msg; 4930b28cb4bSSrinivas Pandruvada struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data; 4940b28cb4bSSrinivas Pandruvada int retry_count; 4950b28cb4bSSrinivas Pandruvada int rv; 4960b28cb4bSSrinivas Pandruvada 4970b28cb4bSSrinivas Pandruvada /* Send HOSTIF_DM_ENUM_DEVICES */ 4980b28cb4bSSrinivas Pandruvada memset(&msg, 0, sizeof(struct hostif_msg)); 4990b28cb4bSSrinivas Pandruvada msg.hdr.command = HOSTIF_DM_ENUM_DEVICES; 5000b28cb4bSSrinivas Pandruvada rv = ishtp_cl_send(hid_ishtp_cl, (unsigned char *)&msg, 5010b28cb4bSSrinivas Pandruvada sizeof(struct hostif_msg)); 5020b28cb4bSSrinivas Pandruvada if (rv) 5030b28cb4bSSrinivas Pandruvada return rv; 5040b28cb4bSSrinivas Pandruvada 5050b28cb4bSSrinivas Pandruvada retry_count = 0; 5060b28cb4bSSrinivas Pandruvada while (!client_data->enum_devices_done && 5070b28cb4bSSrinivas Pandruvada retry_count < 10) { 5080b28cb4bSSrinivas Pandruvada wait_event_interruptible_timeout(client_data->init_wait, 5090b28cb4bSSrinivas Pandruvada client_data->enum_devices_done, 5100b28cb4bSSrinivas Pandruvada 3 * HZ); 5110b28cb4bSSrinivas Pandruvada ++retry_count; 5120b28cb4bSSrinivas Pandruvada if (!client_data->enum_devices_done) 5130b28cb4bSSrinivas Pandruvada /* Send HOSTIF_DM_ENUM_DEVICES */ 5140b28cb4bSSrinivas Pandruvada rv = ishtp_cl_send(hid_ishtp_cl, 5150b28cb4bSSrinivas Pandruvada (unsigned char *) &msg, 5160b28cb4bSSrinivas Pandruvada sizeof(struct hostif_msg)); 5170b28cb4bSSrinivas Pandruvada } 5180b28cb4bSSrinivas Pandruvada if (!client_data->enum_devices_done) { 5190b28cb4bSSrinivas Pandruvada dev_err(&client_data->cl_device->dev, 5200b28cb4bSSrinivas Pandruvada "[hid-ish]: timed out waiting for enum_devices\n"); 5210b28cb4bSSrinivas Pandruvada return -ETIMEDOUT; 5220b28cb4bSSrinivas Pandruvada } 5230b28cb4bSSrinivas Pandruvada if (!client_data->hid_devices) { 5240b28cb4bSSrinivas Pandruvada dev_err(&client_data->cl_device->dev, 5250b28cb4bSSrinivas Pandruvada "[hid-ish]: failed to allocate HID dev structures\n"); 5260b28cb4bSSrinivas Pandruvada return -ENOMEM; 5270b28cb4bSSrinivas Pandruvada } 5280b28cb4bSSrinivas Pandruvada 5290b28cb4bSSrinivas Pandruvada client_data->num_hid_devices = client_data->hid_dev_count; 5300b28cb4bSSrinivas Pandruvada dev_info(&hid_ishtp_cl->device->dev, 5310b28cb4bSSrinivas Pandruvada "[hid-ish]: enum_devices_done OK, num_hid_devices=%d\n", 5320b28cb4bSSrinivas Pandruvada client_data->num_hid_devices); 5330b28cb4bSSrinivas Pandruvada 5340b28cb4bSSrinivas Pandruvada return 0; 5350b28cb4bSSrinivas Pandruvada } 5360b28cb4bSSrinivas Pandruvada 5370b28cb4bSSrinivas Pandruvada /** 5380b28cb4bSSrinivas Pandruvada * ishtp_get_hid_descriptor() - Get hid descriptor 5390b28cb4bSSrinivas Pandruvada * @hid_ishtp_cl: client instance 5400b28cb4bSSrinivas Pandruvada * @index: Index into the hid_descr array 5410b28cb4bSSrinivas Pandruvada * 5420b28cb4bSSrinivas Pandruvada * Helper function to send request to firmware get HID descriptor of a device 5430b28cb4bSSrinivas Pandruvada * 5440b28cb4bSSrinivas Pandruvada * Return: 0 on success, non zero on error 5450b28cb4bSSrinivas Pandruvada */ 5460b28cb4bSSrinivas Pandruvada static int ishtp_get_hid_descriptor(struct ishtp_cl *hid_ishtp_cl, int index) 5470b28cb4bSSrinivas Pandruvada { 5480b28cb4bSSrinivas Pandruvada struct hostif_msg msg; 5490b28cb4bSSrinivas Pandruvada struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data; 5500b28cb4bSSrinivas Pandruvada int rv; 5510b28cb4bSSrinivas Pandruvada 5520b28cb4bSSrinivas Pandruvada /* Get HID descriptor */ 5530b28cb4bSSrinivas Pandruvada client_data->hid_descr_done = false; 5540b28cb4bSSrinivas Pandruvada memset(&msg, 0, sizeof(struct hostif_msg)); 5550b28cb4bSSrinivas Pandruvada msg.hdr.command = HOSTIF_GET_HID_DESCRIPTOR; 5560b28cb4bSSrinivas Pandruvada msg.hdr.device_id = client_data->hid_devices[index].dev_id; 5570b28cb4bSSrinivas Pandruvada rv = ishtp_cl_send(hid_ishtp_cl, (unsigned char *) &msg, 5580b28cb4bSSrinivas Pandruvada sizeof(struct hostif_msg)); 5590b28cb4bSSrinivas Pandruvada if (rv) 5600b28cb4bSSrinivas Pandruvada return rv; 5610b28cb4bSSrinivas Pandruvada 5620b28cb4bSSrinivas Pandruvada if (!client_data->hid_descr_done) { 5630b28cb4bSSrinivas Pandruvada wait_event_interruptible_timeout(client_data->init_wait, 5640b28cb4bSSrinivas Pandruvada client_data->hid_descr_done, 5650b28cb4bSSrinivas Pandruvada 3 * HZ); 5660b28cb4bSSrinivas Pandruvada if (!client_data->hid_descr_done) { 5670b28cb4bSSrinivas Pandruvada dev_err(&client_data->cl_device->dev, 5680b28cb4bSSrinivas Pandruvada "[hid-ish]: timed out for hid_descr_done\n"); 5690b28cb4bSSrinivas Pandruvada return -EIO; 5700b28cb4bSSrinivas Pandruvada } 5710b28cb4bSSrinivas Pandruvada 5720b28cb4bSSrinivas Pandruvada if (!client_data->hid_descr[index]) { 5730b28cb4bSSrinivas Pandruvada dev_err(&client_data->cl_device->dev, 5740b28cb4bSSrinivas Pandruvada "[hid-ish]: allocation HID desc fail\n"); 5750b28cb4bSSrinivas Pandruvada return -ENOMEM; 5760b28cb4bSSrinivas Pandruvada } 5770b28cb4bSSrinivas Pandruvada } 5780b28cb4bSSrinivas Pandruvada 5790b28cb4bSSrinivas Pandruvada return 0; 5800b28cb4bSSrinivas Pandruvada } 5810b28cb4bSSrinivas Pandruvada 5820b28cb4bSSrinivas Pandruvada /** 5830b28cb4bSSrinivas Pandruvada * ishtp_get_report_descriptor() - Get report descriptor 5840b28cb4bSSrinivas Pandruvada * @hid_ishtp_cl: client instance 5850b28cb4bSSrinivas Pandruvada * @index: Index into the hid_descr array 5860b28cb4bSSrinivas Pandruvada * 5870b28cb4bSSrinivas Pandruvada * Helper function to send request to firmware get HID report descriptor of 5880b28cb4bSSrinivas Pandruvada * a device 5890b28cb4bSSrinivas Pandruvada * 5900b28cb4bSSrinivas Pandruvada * Return: 0 on success, non zero on error 5910b28cb4bSSrinivas Pandruvada */ 5920b28cb4bSSrinivas Pandruvada static int ishtp_get_report_descriptor(struct ishtp_cl *hid_ishtp_cl, 5930b28cb4bSSrinivas Pandruvada int index) 5940b28cb4bSSrinivas Pandruvada { 5950b28cb4bSSrinivas Pandruvada struct hostif_msg msg; 5960b28cb4bSSrinivas Pandruvada struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data; 5970b28cb4bSSrinivas Pandruvada int rv; 5980b28cb4bSSrinivas Pandruvada 5990b28cb4bSSrinivas Pandruvada /* Get report descriptor */ 6000b28cb4bSSrinivas Pandruvada client_data->report_descr_done = false; 6010b28cb4bSSrinivas Pandruvada memset(&msg, 0, sizeof(struct hostif_msg)); 6020b28cb4bSSrinivas Pandruvada msg.hdr.command = HOSTIF_GET_REPORT_DESCRIPTOR; 6030b28cb4bSSrinivas Pandruvada msg.hdr.device_id = client_data->hid_devices[index].dev_id; 6040b28cb4bSSrinivas Pandruvada rv = ishtp_cl_send(hid_ishtp_cl, (unsigned char *) &msg, 6050b28cb4bSSrinivas Pandruvada sizeof(struct hostif_msg)); 6060b28cb4bSSrinivas Pandruvada if (rv) 6070b28cb4bSSrinivas Pandruvada return rv; 6080b28cb4bSSrinivas Pandruvada 6090b28cb4bSSrinivas Pandruvada if (!client_data->report_descr_done) 6100b28cb4bSSrinivas Pandruvada wait_event_interruptible_timeout(client_data->init_wait, 6110b28cb4bSSrinivas Pandruvada client_data->report_descr_done, 6120b28cb4bSSrinivas Pandruvada 3 * HZ); 6130b28cb4bSSrinivas Pandruvada if (!client_data->report_descr_done) { 6140b28cb4bSSrinivas Pandruvada dev_err(&client_data->cl_device->dev, 6150b28cb4bSSrinivas Pandruvada "[hid-ish]: timed out for report descr\n"); 6160b28cb4bSSrinivas Pandruvada return -EIO; 6170b28cb4bSSrinivas Pandruvada } 6180b28cb4bSSrinivas Pandruvada if (!client_data->report_descr[index]) { 6190b28cb4bSSrinivas Pandruvada dev_err(&client_data->cl_device->dev, 6200b28cb4bSSrinivas Pandruvada "[hid-ish]: failed to alloc report descr\n"); 6210b28cb4bSSrinivas Pandruvada return -ENOMEM; 6220b28cb4bSSrinivas Pandruvada } 6230b28cb4bSSrinivas Pandruvada 6240b28cb4bSSrinivas Pandruvada return 0; 6250b28cb4bSSrinivas Pandruvada } 6260b28cb4bSSrinivas Pandruvada 6270b28cb4bSSrinivas Pandruvada /** 6280b28cb4bSSrinivas Pandruvada * hid_ishtp_cl_init() - Init function for ISHTP client 6290b28cb4bSSrinivas Pandruvada * @hid_ishtp_cl: ISHTP client instance 6300b28cb4bSSrinivas Pandruvada * @reset: true if called for init after reset 6310b28cb4bSSrinivas Pandruvada * 6320b28cb4bSSrinivas Pandruvada * This function complete the initializtion of the client. The summary of 6330b28cb4bSSrinivas Pandruvada * processing: 6340b28cb4bSSrinivas Pandruvada * - Send request to enumerate the hid clients 6350b28cb4bSSrinivas Pandruvada * Get the HID descriptor for each enumearated device 6360b28cb4bSSrinivas Pandruvada * Get report description of each device 6370b28cb4bSSrinivas Pandruvada * Register each device wik hid core by calling ishtp_hid_probe 6380b28cb4bSSrinivas Pandruvada * 6390b28cb4bSSrinivas Pandruvada * Return: 0 on success, non zero on error 6400b28cb4bSSrinivas Pandruvada */ 6410b28cb4bSSrinivas Pandruvada static int hid_ishtp_cl_init(struct ishtp_cl *hid_ishtp_cl, int reset) 6420b28cb4bSSrinivas Pandruvada { 6430b28cb4bSSrinivas Pandruvada struct ishtp_device *dev; 6440b28cb4bSSrinivas Pandruvada unsigned long flags; 6450b28cb4bSSrinivas Pandruvada struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data; 6460b28cb4bSSrinivas Pandruvada int i; 6470b28cb4bSSrinivas Pandruvada int rv; 6480b28cb4bSSrinivas Pandruvada 6490b28cb4bSSrinivas Pandruvada dev_dbg(&client_data->cl_device->dev, "%s\n", __func__); 6500b28cb4bSSrinivas Pandruvada hid_ishtp_trace(client_data, "%s reset flag: %d\n", __func__, reset); 6510b28cb4bSSrinivas Pandruvada 6520b28cb4bSSrinivas Pandruvada rv = ishtp_cl_link(hid_ishtp_cl, ISHTP_HOST_CLIENT_ID_ANY); 6530b28cb4bSSrinivas Pandruvada if (rv) { 6540b28cb4bSSrinivas Pandruvada dev_err(&client_data->cl_device->dev, 6550b28cb4bSSrinivas Pandruvada "ishtp_cl_link failed\n"); 6560b28cb4bSSrinivas Pandruvada return -ENOMEM; 6570b28cb4bSSrinivas Pandruvada } 6580b28cb4bSSrinivas Pandruvada 6590b28cb4bSSrinivas Pandruvada client_data->init_done = 0; 6600b28cb4bSSrinivas Pandruvada 6610b28cb4bSSrinivas Pandruvada dev = hid_ishtp_cl->dev; 6620b28cb4bSSrinivas Pandruvada 6630b28cb4bSSrinivas Pandruvada /* Connect to FW client */ 6640b28cb4bSSrinivas Pandruvada hid_ishtp_cl->rx_ring_size = HID_CL_RX_RING_SIZE; 6650b28cb4bSSrinivas Pandruvada hid_ishtp_cl->tx_ring_size = HID_CL_TX_RING_SIZE; 6660b28cb4bSSrinivas Pandruvada 6670b28cb4bSSrinivas Pandruvada spin_lock_irqsave(&dev->fw_clients_lock, flags); 6680b28cb4bSSrinivas Pandruvada i = ishtp_fw_cl_by_uuid(dev, &hid_ishtp_guid); 6690b28cb4bSSrinivas Pandruvada if (i < 0) { 6700b28cb4bSSrinivas Pandruvada spin_unlock_irqrestore(&dev->fw_clients_lock, flags); 6710b28cb4bSSrinivas Pandruvada dev_err(&client_data->cl_device->dev, 6720b28cb4bSSrinivas Pandruvada "ish client uuid not found\n"); 6730b28cb4bSSrinivas Pandruvada return i; 6740b28cb4bSSrinivas Pandruvada } 6750b28cb4bSSrinivas Pandruvada hid_ishtp_cl->fw_client_id = dev->fw_clients[i].client_id; 6760b28cb4bSSrinivas Pandruvada spin_unlock_irqrestore(&dev->fw_clients_lock, flags); 6770b28cb4bSSrinivas Pandruvada hid_ishtp_cl->state = ISHTP_CL_CONNECTING; 6780b28cb4bSSrinivas Pandruvada 6790b28cb4bSSrinivas Pandruvada rv = ishtp_cl_connect(hid_ishtp_cl); 6800b28cb4bSSrinivas Pandruvada if (rv) { 6810b28cb4bSSrinivas Pandruvada dev_err(&client_data->cl_device->dev, 6820b28cb4bSSrinivas Pandruvada "client connect fail\n"); 6830b28cb4bSSrinivas Pandruvada goto err_cl_unlink; 6840b28cb4bSSrinivas Pandruvada } 6850b28cb4bSSrinivas Pandruvada 6860b28cb4bSSrinivas Pandruvada hid_ishtp_trace(client_data, "%s client connected\n", __func__); 6870b28cb4bSSrinivas Pandruvada 6880b28cb4bSSrinivas Pandruvada /* Register read callback */ 6890b28cb4bSSrinivas Pandruvada ishtp_register_event_cb(hid_ishtp_cl->device, ish_cl_event_cb); 6900b28cb4bSSrinivas Pandruvada 6910b28cb4bSSrinivas Pandruvada rv = ishtp_enum_enum_devices(hid_ishtp_cl); 6920b28cb4bSSrinivas Pandruvada if (rv) 6930b28cb4bSSrinivas Pandruvada goto err_cl_disconnect; 6940b28cb4bSSrinivas Pandruvada 6950b28cb4bSSrinivas Pandruvada hid_ishtp_trace(client_data, "%s enumerated device count %d\n", 6960b28cb4bSSrinivas Pandruvada __func__, client_data->num_hid_devices); 6970b28cb4bSSrinivas Pandruvada 6980b28cb4bSSrinivas Pandruvada for (i = 0; i < client_data->num_hid_devices; ++i) { 6990b28cb4bSSrinivas Pandruvada client_data->cur_hid_dev = i; 7000b28cb4bSSrinivas Pandruvada 7010b28cb4bSSrinivas Pandruvada rv = ishtp_get_hid_descriptor(hid_ishtp_cl, i); 7020b28cb4bSSrinivas Pandruvada if (rv) 7030b28cb4bSSrinivas Pandruvada goto err_cl_disconnect; 7040b28cb4bSSrinivas Pandruvada 7050b28cb4bSSrinivas Pandruvada rv = ishtp_get_report_descriptor(hid_ishtp_cl, i); 7060b28cb4bSSrinivas Pandruvada if (rv) 7070b28cb4bSSrinivas Pandruvada goto err_cl_disconnect; 7080b28cb4bSSrinivas Pandruvada 7090b28cb4bSSrinivas Pandruvada if (!reset) { 7100b28cb4bSSrinivas Pandruvada rv = ishtp_hid_probe(i, client_data); 7110b28cb4bSSrinivas Pandruvada if (rv) { 7120b28cb4bSSrinivas Pandruvada dev_err(&client_data->cl_device->dev, 7130b28cb4bSSrinivas Pandruvada "[hid-ish]: HID probe for #%u failed: %d\n", 7140b28cb4bSSrinivas Pandruvada i, rv); 7150b28cb4bSSrinivas Pandruvada goto err_cl_disconnect; 7160b28cb4bSSrinivas Pandruvada } 7170b28cb4bSSrinivas Pandruvada } 7180b28cb4bSSrinivas Pandruvada } /* for() on all hid devices */ 7190b28cb4bSSrinivas Pandruvada 7200b28cb4bSSrinivas Pandruvada client_data->init_done = 1; 7210b28cb4bSSrinivas Pandruvada client_data->suspended = false; 7220b28cb4bSSrinivas Pandruvada wake_up_interruptible(&client_data->ishtp_resume_wait); 7230b28cb4bSSrinivas Pandruvada hid_ishtp_trace(client_data, "%s successful init\n", __func__); 7240b28cb4bSSrinivas Pandruvada return 0; 7250b28cb4bSSrinivas Pandruvada 7260b28cb4bSSrinivas Pandruvada err_cl_disconnect: 7270b28cb4bSSrinivas Pandruvada hid_ishtp_cl->state = ISHTP_CL_DISCONNECTING; 7280b28cb4bSSrinivas Pandruvada ishtp_cl_disconnect(hid_ishtp_cl); 7290b28cb4bSSrinivas Pandruvada err_cl_unlink: 7300b28cb4bSSrinivas Pandruvada ishtp_cl_unlink(hid_ishtp_cl); 7310b28cb4bSSrinivas Pandruvada return rv; 7320b28cb4bSSrinivas Pandruvada } 7330b28cb4bSSrinivas Pandruvada 7340b28cb4bSSrinivas Pandruvada /** 7350b28cb4bSSrinivas Pandruvada * hid_ishtp_cl_deinit() - Deinit function for ISHTP client 7360b28cb4bSSrinivas Pandruvada * @hid_ishtp_cl: ISHTP client instance 7370b28cb4bSSrinivas Pandruvada * 7380b28cb4bSSrinivas Pandruvada * Unlink and free hid client 7390b28cb4bSSrinivas Pandruvada */ 7400b28cb4bSSrinivas Pandruvada static void hid_ishtp_cl_deinit(struct ishtp_cl *hid_ishtp_cl) 7410b28cb4bSSrinivas Pandruvada { 7420b28cb4bSSrinivas Pandruvada ishtp_cl_unlink(hid_ishtp_cl); 7430b28cb4bSSrinivas Pandruvada ishtp_cl_flush_queues(hid_ishtp_cl); 7440b28cb4bSSrinivas Pandruvada 7450b28cb4bSSrinivas Pandruvada /* disband and free all Tx and Rx client-level rings */ 7460b28cb4bSSrinivas Pandruvada ishtp_cl_free(hid_ishtp_cl); 7470b28cb4bSSrinivas Pandruvada } 7480b28cb4bSSrinivas Pandruvada 7490b28cb4bSSrinivas Pandruvada static void hid_ishtp_cl_reset_handler(struct work_struct *work) 7500b28cb4bSSrinivas Pandruvada { 7510b28cb4bSSrinivas Pandruvada struct ishtp_cl_data *client_data; 7520b28cb4bSSrinivas Pandruvada struct ishtp_cl *hid_ishtp_cl; 7530b28cb4bSSrinivas Pandruvada struct ishtp_cl_device *cl_device; 7540b28cb4bSSrinivas Pandruvada int retry; 7550b28cb4bSSrinivas Pandruvada int rv; 7560b28cb4bSSrinivas Pandruvada 7570b28cb4bSSrinivas Pandruvada client_data = container_of(work, struct ishtp_cl_data, work); 7580b28cb4bSSrinivas Pandruvada 7590b28cb4bSSrinivas Pandruvada hid_ishtp_cl = client_data->hid_ishtp_cl; 7600b28cb4bSSrinivas Pandruvada cl_device = client_data->cl_device; 7610b28cb4bSSrinivas Pandruvada 7620b28cb4bSSrinivas Pandruvada hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__, 7630b28cb4bSSrinivas Pandruvada hid_ishtp_cl); 7640b28cb4bSSrinivas Pandruvada dev_dbg(&cl_device->dev, "%s\n", __func__); 7650b28cb4bSSrinivas Pandruvada 7660b28cb4bSSrinivas Pandruvada hid_ishtp_cl_deinit(hid_ishtp_cl); 7670b28cb4bSSrinivas Pandruvada 7680b28cb4bSSrinivas Pandruvada hid_ishtp_cl = ishtp_cl_allocate(cl_device->ishtp_dev); 7690b28cb4bSSrinivas Pandruvada if (!hid_ishtp_cl) 7700b28cb4bSSrinivas Pandruvada return; 7710b28cb4bSSrinivas Pandruvada 7720b28cb4bSSrinivas Pandruvada cl_device->driver_data = hid_ishtp_cl; 7730b28cb4bSSrinivas Pandruvada hid_ishtp_cl->client_data = client_data; 7740b28cb4bSSrinivas Pandruvada client_data->hid_ishtp_cl = hid_ishtp_cl; 7750b28cb4bSSrinivas Pandruvada 7760b28cb4bSSrinivas Pandruvada client_data->num_hid_devices = 0; 7770b28cb4bSSrinivas Pandruvada 7780b28cb4bSSrinivas Pandruvada for (retry = 0; retry < 3; ++retry) { 7790b28cb4bSSrinivas Pandruvada rv = hid_ishtp_cl_init(hid_ishtp_cl, 1); 7800b28cb4bSSrinivas Pandruvada if (!rv) 7810b28cb4bSSrinivas Pandruvada break; 7820b28cb4bSSrinivas Pandruvada dev_err(&client_data->cl_device->dev, "Retry reset init\n"); 7830b28cb4bSSrinivas Pandruvada } 7840b28cb4bSSrinivas Pandruvada if (rv) { 7850b28cb4bSSrinivas Pandruvada dev_err(&client_data->cl_device->dev, "Reset Failed\n"); 7860b28cb4bSSrinivas Pandruvada hid_ishtp_trace(client_data, "%s Failed hid_ishtp_cl %p\n", 7870b28cb4bSSrinivas Pandruvada __func__, hid_ishtp_cl); 7880b28cb4bSSrinivas Pandruvada } 7890b28cb4bSSrinivas Pandruvada } 7900b28cb4bSSrinivas Pandruvada 7910b28cb4bSSrinivas Pandruvada /** 7920b28cb4bSSrinivas Pandruvada * hid_ishtp_cl_probe() - ISHTP client driver probe 7930b28cb4bSSrinivas Pandruvada * @cl_device: ISHTP client device instance 7940b28cb4bSSrinivas Pandruvada * 7950b28cb4bSSrinivas Pandruvada * This function gets called on device create on ISHTP bus 7960b28cb4bSSrinivas Pandruvada * 7970b28cb4bSSrinivas Pandruvada * Return: 0 on success, non zero on error 7980b28cb4bSSrinivas Pandruvada */ 7990b28cb4bSSrinivas Pandruvada static int hid_ishtp_cl_probe(struct ishtp_cl_device *cl_device) 8000b28cb4bSSrinivas Pandruvada { 8010b28cb4bSSrinivas Pandruvada struct ishtp_cl *hid_ishtp_cl; 8020b28cb4bSSrinivas Pandruvada struct ishtp_cl_data *client_data; 8030b28cb4bSSrinivas Pandruvada int rv; 8040b28cb4bSSrinivas Pandruvada 8050b28cb4bSSrinivas Pandruvada if (!cl_device) 8060b28cb4bSSrinivas Pandruvada return -ENODEV; 8070b28cb4bSSrinivas Pandruvada 8080b28cb4bSSrinivas Pandruvada if (uuid_le_cmp(hid_ishtp_guid, 8090b28cb4bSSrinivas Pandruvada cl_device->fw_client->props.protocol_name) != 0) 8100b28cb4bSSrinivas Pandruvada return -ENODEV; 8110b28cb4bSSrinivas Pandruvada 8120b28cb4bSSrinivas Pandruvada client_data = devm_kzalloc(&cl_device->dev, sizeof(*client_data), 8130b28cb4bSSrinivas Pandruvada GFP_KERNEL); 8140b28cb4bSSrinivas Pandruvada if (!client_data) 8150b28cb4bSSrinivas Pandruvada return -ENOMEM; 8160b28cb4bSSrinivas Pandruvada 8170b28cb4bSSrinivas Pandruvada hid_ishtp_cl = ishtp_cl_allocate(cl_device->ishtp_dev); 8180b28cb4bSSrinivas Pandruvada if (!hid_ishtp_cl) 8190b28cb4bSSrinivas Pandruvada return -ENOMEM; 8200b28cb4bSSrinivas Pandruvada 8210b28cb4bSSrinivas Pandruvada cl_device->driver_data = hid_ishtp_cl; 8220b28cb4bSSrinivas Pandruvada hid_ishtp_cl->client_data = client_data; 8230b28cb4bSSrinivas Pandruvada client_data->hid_ishtp_cl = hid_ishtp_cl; 8240b28cb4bSSrinivas Pandruvada client_data->cl_device = cl_device; 8250b28cb4bSSrinivas Pandruvada 8260b28cb4bSSrinivas Pandruvada init_waitqueue_head(&client_data->init_wait); 8270b28cb4bSSrinivas Pandruvada init_waitqueue_head(&client_data->ishtp_resume_wait); 8280b28cb4bSSrinivas Pandruvada 8290b28cb4bSSrinivas Pandruvada INIT_WORK(&client_data->work, hid_ishtp_cl_reset_handler); 8300b28cb4bSSrinivas Pandruvada 8310b28cb4bSSrinivas Pandruvada rv = hid_ishtp_cl_init(hid_ishtp_cl, 0); 8320b28cb4bSSrinivas Pandruvada if (rv) { 8330b28cb4bSSrinivas Pandruvada ishtp_cl_free(hid_ishtp_cl); 8340b28cb4bSSrinivas Pandruvada return rv; 8350b28cb4bSSrinivas Pandruvada } 8360b28cb4bSSrinivas Pandruvada ishtp_get_device(cl_device); 8370b28cb4bSSrinivas Pandruvada 8380b28cb4bSSrinivas Pandruvada return 0; 8390b28cb4bSSrinivas Pandruvada } 8400b28cb4bSSrinivas Pandruvada 8410b28cb4bSSrinivas Pandruvada /** 8420b28cb4bSSrinivas Pandruvada * hid_ishtp_cl_remove() - ISHTP client driver remove 8430b28cb4bSSrinivas Pandruvada * @cl_device: ISHTP client device instance 8440b28cb4bSSrinivas Pandruvada * 8450b28cb4bSSrinivas Pandruvada * This function gets called on device remove on ISHTP bus 8460b28cb4bSSrinivas Pandruvada * 8470b28cb4bSSrinivas Pandruvada * Return: 0 8480b28cb4bSSrinivas Pandruvada */ 8490b28cb4bSSrinivas Pandruvada static int hid_ishtp_cl_remove(struct ishtp_cl_device *cl_device) 8500b28cb4bSSrinivas Pandruvada { 8510b28cb4bSSrinivas Pandruvada struct ishtp_cl *hid_ishtp_cl = cl_device->driver_data; 8520b28cb4bSSrinivas Pandruvada struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data; 8530b28cb4bSSrinivas Pandruvada 8540b28cb4bSSrinivas Pandruvada hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__, 8550b28cb4bSSrinivas Pandruvada hid_ishtp_cl); 8560b28cb4bSSrinivas Pandruvada 8570b28cb4bSSrinivas Pandruvada dev_dbg(&cl_device->dev, "%s\n", __func__); 8580b28cb4bSSrinivas Pandruvada hid_ishtp_cl->state = ISHTP_CL_DISCONNECTING; 8590b28cb4bSSrinivas Pandruvada ishtp_cl_disconnect(hid_ishtp_cl); 8600b28cb4bSSrinivas Pandruvada ishtp_put_device(cl_device); 8610b28cb4bSSrinivas Pandruvada ishtp_hid_remove(client_data); 8620b28cb4bSSrinivas Pandruvada hid_ishtp_cl_deinit(hid_ishtp_cl); 8630b28cb4bSSrinivas Pandruvada 8640b28cb4bSSrinivas Pandruvada hid_ishtp_cl = NULL; 8650b28cb4bSSrinivas Pandruvada 8660b28cb4bSSrinivas Pandruvada client_data->num_hid_devices = 0; 8670b28cb4bSSrinivas Pandruvada 8680b28cb4bSSrinivas Pandruvada return 0; 8690b28cb4bSSrinivas Pandruvada } 8700b28cb4bSSrinivas Pandruvada 8710b28cb4bSSrinivas Pandruvada /** 8720b28cb4bSSrinivas Pandruvada * hid_ishtp_cl_reset() - ISHTP client driver reset 8730b28cb4bSSrinivas Pandruvada * @cl_device: ISHTP client device instance 8740b28cb4bSSrinivas Pandruvada * 8750b28cb4bSSrinivas Pandruvada * This function gets called on device reset on ISHTP bus 8760b28cb4bSSrinivas Pandruvada * 8770b28cb4bSSrinivas Pandruvada * Return: 0 8780b28cb4bSSrinivas Pandruvada */ 8790b28cb4bSSrinivas Pandruvada static int hid_ishtp_cl_reset(struct ishtp_cl_device *cl_device) 8800b28cb4bSSrinivas Pandruvada { 8810b28cb4bSSrinivas Pandruvada struct ishtp_cl *hid_ishtp_cl = cl_device->driver_data; 8820b28cb4bSSrinivas Pandruvada struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data; 8830b28cb4bSSrinivas Pandruvada 8840b28cb4bSSrinivas Pandruvada hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__, 8850b28cb4bSSrinivas Pandruvada hid_ishtp_cl); 8860b28cb4bSSrinivas Pandruvada 8870b28cb4bSSrinivas Pandruvada schedule_work(&client_data->work); 8880b28cb4bSSrinivas Pandruvada 8890b28cb4bSSrinivas Pandruvada return 0; 8900b28cb4bSSrinivas Pandruvada } 8910b28cb4bSSrinivas Pandruvada 8920b28cb4bSSrinivas Pandruvada #define to_ishtp_cl_device(d) container_of(d, struct ishtp_cl_device, dev) 8930b28cb4bSSrinivas Pandruvada 8940b28cb4bSSrinivas Pandruvada /** 8950b28cb4bSSrinivas Pandruvada * hid_ishtp_cl_suspend() - ISHTP client driver suspend 8960b28cb4bSSrinivas Pandruvada * @device: device instance 8970b28cb4bSSrinivas Pandruvada * 8980b28cb4bSSrinivas Pandruvada * This function gets called on system suspend 8990b28cb4bSSrinivas Pandruvada * 9000b28cb4bSSrinivas Pandruvada * Return: 0 9010b28cb4bSSrinivas Pandruvada */ 9020b28cb4bSSrinivas Pandruvada static int hid_ishtp_cl_suspend(struct device *device) 9030b28cb4bSSrinivas Pandruvada { 9040b28cb4bSSrinivas Pandruvada struct ishtp_cl_device *cl_device = to_ishtp_cl_device(device); 9050b28cb4bSSrinivas Pandruvada struct ishtp_cl *hid_ishtp_cl = cl_device->driver_data; 9060b28cb4bSSrinivas Pandruvada struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data; 9070b28cb4bSSrinivas Pandruvada 9080b28cb4bSSrinivas Pandruvada hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__, 9090b28cb4bSSrinivas Pandruvada hid_ishtp_cl); 9100b28cb4bSSrinivas Pandruvada client_data->suspended = true; 9110b28cb4bSSrinivas Pandruvada 9120b28cb4bSSrinivas Pandruvada return 0; 9130b28cb4bSSrinivas Pandruvada } 9140b28cb4bSSrinivas Pandruvada 9150b28cb4bSSrinivas Pandruvada /** 9160b28cb4bSSrinivas Pandruvada * hid_ishtp_cl_resume() - ISHTP client driver resume 9170b28cb4bSSrinivas Pandruvada * @device: device instance 9180b28cb4bSSrinivas Pandruvada * 9190b28cb4bSSrinivas Pandruvada * This function gets called on system resume 9200b28cb4bSSrinivas Pandruvada * 9210b28cb4bSSrinivas Pandruvada * Return: 0 9220b28cb4bSSrinivas Pandruvada */ 9230b28cb4bSSrinivas Pandruvada static int hid_ishtp_cl_resume(struct device *device) 9240b28cb4bSSrinivas Pandruvada { 9250b28cb4bSSrinivas Pandruvada struct ishtp_cl_device *cl_device = to_ishtp_cl_device(device); 9260b28cb4bSSrinivas Pandruvada struct ishtp_cl *hid_ishtp_cl = cl_device->driver_data; 9270b28cb4bSSrinivas Pandruvada struct ishtp_cl_data *client_data = hid_ishtp_cl->client_data; 9280b28cb4bSSrinivas Pandruvada 9290b28cb4bSSrinivas Pandruvada hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__, 9300b28cb4bSSrinivas Pandruvada hid_ishtp_cl); 9310b28cb4bSSrinivas Pandruvada client_data->suspended = false; 9320b28cb4bSSrinivas Pandruvada return 0; 9330b28cb4bSSrinivas Pandruvada } 9340b28cb4bSSrinivas Pandruvada 9350b28cb4bSSrinivas Pandruvada static const struct dev_pm_ops hid_ishtp_pm_ops = { 9360b28cb4bSSrinivas Pandruvada .suspend = hid_ishtp_cl_suspend, 9370b28cb4bSSrinivas Pandruvada .resume = hid_ishtp_cl_resume, 9380b28cb4bSSrinivas Pandruvada }; 9390b28cb4bSSrinivas Pandruvada 9400b28cb4bSSrinivas Pandruvada static struct ishtp_cl_driver hid_ishtp_cl_driver = { 9410b28cb4bSSrinivas Pandruvada .name = "ish-hid", 9420b28cb4bSSrinivas Pandruvada .probe = hid_ishtp_cl_probe, 9430b28cb4bSSrinivas Pandruvada .remove = hid_ishtp_cl_remove, 9440b28cb4bSSrinivas Pandruvada .reset = hid_ishtp_cl_reset, 9450b28cb4bSSrinivas Pandruvada .driver.pm = &hid_ishtp_pm_ops, 9460b28cb4bSSrinivas Pandruvada }; 9470b28cb4bSSrinivas Pandruvada 9480b28cb4bSSrinivas Pandruvada static int __init ish_hid_init(void) 9490b28cb4bSSrinivas Pandruvada { 9500b28cb4bSSrinivas Pandruvada int rv; 9510b28cb4bSSrinivas Pandruvada 9520b28cb4bSSrinivas Pandruvada /* Register ISHTP client device driver with ISHTP Bus */ 9530b28cb4bSSrinivas Pandruvada rv = ishtp_cl_driver_register(&hid_ishtp_cl_driver); 9540b28cb4bSSrinivas Pandruvada 9550b28cb4bSSrinivas Pandruvada return rv; 9560b28cb4bSSrinivas Pandruvada 9570b28cb4bSSrinivas Pandruvada } 9580b28cb4bSSrinivas Pandruvada 9590b28cb4bSSrinivas Pandruvada static void __exit ish_hid_exit(void) 9600b28cb4bSSrinivas Pandruvada { 9610b28cb4bSSrinivas Pandruvada ishtp_cl_driver_unregister(&hid_ishtp_cl_driver); 9620b28cb4bSSrinivas Pandruvada } 9630b28cb4bSSrinivas Pandruvada 9640b28cb4bSSrinivas Pandruvada late_initcall(ish_hid_init); 9650b28cb4bSSrinivas Pandruvada module_exit(ish_hid_exit); 9660b28cb4bSSrinivas Pandruvada 9670b28cb4bSSrinivas Pandruvada MODULE_DESCRIPTION("ISH ISHTP HID client driver"); 9680b28cb4bSSrinivas Pandruvada /* Primary author */ 9690b28cb4bSSrinivas Pandruvada MODULE_AUTHOR("Daniel Drubin <daniel.drubin@intel.com>"); 9700b28cb4bSSrinivas Pandruvada /* 9710b28cb4bSSrinivas Pandruvada * Several modification for multi instance support 9720b28cb4bSSrinivas Pandruvada * suspend/resume and clean up 9730b28cb4bSSrinivas Pandruvada */ 9740b28cb4bSSrinivas Pandruvada MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>"); 9750b28cb4bSSrinivas Pandruvada 9760b28cb4bSSrinivas Pandruvada MODULE_LICENSE("GPL"); 9770b28cb4bSSrinivas Pandruvada MODULE_ALIAS("ishtp:*"); 978