Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * ISHTP client driver for HID (ISH)
0004  *
0005  * Copyright (c) 2014-2016, Intel Corporation.
0006  */
0007 
0008 #include <linux/module.h>
0009 #include <linux/hid.h>
0010 #include <linux/intel-ish-client-if.h>
0011 #include <linux/sched.h>
0012 #include "ishtp-hid.h"
0013 
0014 /* ISH Transport protocol (ISHTP in short) GUID */
0015 static const struct ishtp_device_id hid_ishtp_id_table[] = {
0016     { .guid = GUID_INIT(0x33AECD58, 0xB679, 0x4E54,
0017           0x9B, 0xD9, 0xA0, 0x4D, 0x34, 0xF0, 0xC2, 0x26), },
0018     { }
0019 };
0020 MODULE_DEVICE_TABLE(ishtp, hid_ishtp_id_table);
0021 
0022 /* Rx ring buffer pool size */
0023 #define HID_CL_RX_RING_SIZE 32
0024 #define HID_CL_TX_RING_SIZE 16
0025 
0026 #define cl_data_to_dev(client_data) ishtp_device(client_data->cl_device)
0027 
0028 /**
0029  * report_bad_packet() - Report bad packets
0030  * @hid_ishtp_cl:   Client instance to get stats
0031  * @recv_buf:       Raw received host interface message
0032  * @cur_pos:        Current position index in payload
0033  * @payload_len:    Length of payload expected
0034  *
0035  * Dumps error in case bad packet is received
0036  */
0037 static void report_bad_packet(struct ishtp_cl *hid_ishtp_cl, void *recv_buf,
0038                   size_t cur_pos,  size_t payload_len)
0039 {
0040     struct hostif_msg *recv_msg = recv_buf;
0041     struct ishtp_cl_data *client_data = ishtp_get_client_data(hid_ishtp_cl);
0042 
0043     dev_err(cl_data_to_dev(client_data), "[hid-ish]: BAD packet %02X\n"
0044         "total_bad=%u cur_pos=%u\n"
0045         "[%02X %02X %02X %02X]\n"
0046         "payload_len=%u\n"
0047         "multi_packet_cnt=%u\n"
0048         "is_response=%02X\n",
0049         recv_msg->hdr.command, client_data->bad_recv_cnt,
0050         (unsigned int)cur_pos,
0051         ((unsigned char *)recv_msg)[0], ((unsigned char *)recv_msg)[1],
0052         ((unsigned char *)recv_msg)[2], ((unsigned char *)recv_msg)[3],
0053         (unsigned int)payload_len, client_data->multi_packet_cnt,
0054         recv_msg->hdr.command & ~CMD_MASK);
0055 }
0056 
0057 /**
0058  * process_recv() - Received and parse incoming packet
0059  * @hid_ishtp_cl:   Client instance to get stats
0060  * @recv_buf:       Raw received host interface message
0061  * @data_len:       length of the message
0062  *
0063  * Parse the incoming packet. If it is a response packet then it will update
0064  * per instance flags and wake up the caller waiting to for the response.
0065  */
0066 static void process_recv(struct ishtp_cl *hid_ishtp_cl, void *recv_buf,
0067              size_t data_len)
0068 {
0069     struct hostif_msg *recv_msg;
0070     unsigned char *payload;
0071     struct device_info *dev_info;
0072     int i, j;
0073     size_t  payload_len, total_len, cur_pos, raw_len;
0074     int report_type;
0075     struct report_list *reports_list;
0076     char *reports;
0077     size_t report_len;
0078     struct ishtp_cl_data *client_data = ishtp_get_client_data(hid_ishtp_cl);
0079     int curr_hid_dev = client_data->cur_hid_dev;
0080     struct ishtp_hid_data *hid_data = NULL;
0081     struct hid_device *hid = NULL;
0082 
0083     payload = recv_buf + sizeof(struct hostif_msg_hdr);
0084     total_len = data_len;
0085     cur_pos = 0;
0086 
0087     do {
0088         if (cur_pos + sizeof(struct hostif_msg) > total_len) {
0089             dev_err(cl_data_to_dev(client_data),
0090                 "[hid-ish]: error, received %u which is less than data header %u\n",
0091                 (unsigned int)data_len,
0092                 (unsigned int)sizeof(struct hostif_msg_hdr));
0093             ++client_data->bad_recv_cnt;
0094             ish_hw_reset(ishtp_get_ishtp_device(hid_ishtp_cl));
0095             break;
0096         }
0097 
0098         recv_msg = (struct hostif_msg *)(recv_buf + cur_pos);
0099         payload_len = recv_msg->hdr.size;
0100 
0101         /* Sanity checks */
0102         if (cur_pos + payload_len + sizeof(struct hostif_msg) >
0103                 total_len) {
0104             ++client_data->bad_recv_cnt;
0105             report_bad_packet(hid_ishtp_cl, recv_msg, cur_pos,
0106                       payload_len);
0107             ish_hw_reset(ishtp_get_ishtp_device(hid_ishtp_cl));
0108             break;
0109         }
0110 
0111         hid_ishtp_trace(client_data,  "%s %d\n",
0112                 __func__, recv_msg->hdr.command & CMD_MASK);
0113 
0114         switch (recv_msg->hdr.command & CMD_MASK) {
0115         case HOSTIF_DM_ENUM_DEVICES:
0116             if ((!(recv_msg->hdr.command & ~CMD_MASK) ||
0117                     client_data->init_done)) {
0118                 ++client_data->bad_recv_cnt;
0119                 report_bad_packet(hid_ishtp_cl, recv_msg,
0120                           cur_pos,
0121                           payload_len);
0122                 ish_hw_reset(ishtp_get_ishtp_device(hid_ishtp_cl));
0123                 break;
0124             }
0125             client_data->hid_dev_count = (unsigned int)*payload;
0126             if (!client_data->hid_devices)
0127                 client_data->hid_devices = devm_kcalloc(
0128                         cl_data_to_dev(client_data),
0129                         client_data->hid_dev_count,
0130                         sizeof(struct device_info),
0131                         GFP_KERNEL);
0132             if (!client_data->hid_devices) {
0133                 dev_err(cl_data_to_dev(client_data),
0134                 "Mem alloc failed for hid device info\n");
0135                 wake_up_interruptible(&client_data->init_wait);
0136                 break;
0137             }
0138             for (i = 0; i < client_data->hid_dev_count; ++i) {
0139                 if (1 + sizeof(struct device_info) * i >=
0140                         payload_len) {
0141                     dev_err(cl_data_to_dev(client_data),
0142                         "[hid-ish]: [ENUM_DEVICES]: content size %zu is bigger than payload_len %zu\n",
0143                         1 + sizeof(struct device_info)
0144                         * i, payload_len);
0145                 }
0146 
0147                 if (1 + sizeof(struct device_info) * i >=
0148                         data_len)
0149                     break;
0150 
0151                 dev_info = (struct device_info *)(payload + 1 +
0152                     sizeof(struct device_info) * i);
0153                 if (client_data->hid_devices)
0154                     memcpy(client_data->hid_devices + i,
0155                            dev_info,
0156                            sizeof(struct device_info));
0157             }
0158 
0159             client_data->enum_devices_done = true;
0160             wake_up_interruptible(&client_data->init_wait);
0161 
0162             break;
0163 
0164         case HOSTIF_GET_HID_DESCRIPTOR:
0165             if ((!(recv_msg->hdr.command & ~CMD_MASK) ||
0166                     client_data->init_done)) {
0167                 ++client_data->bad_recv_cnt;
0168                 report_bad_packet(hid_ishtp_cl, recv_msg,
0169                           cur_pos,
0170                           payload_len);
0171                 ish_hw_reset(ishtp_get_ishtp_device(hid_ishtp_cl));
0172                 break;
0173             }
0174             if (!client_data->hid_descr[curr_hid_dev])
0175                 client_data->hid_descr[curr_hid_dev] =
0176                 devm_kmalloc(cl_data_to_dev(client_data),
0177                          payload_len, GFP_KERNEL);
0178             if (client_data->hid_descr[curr_hid_dev]) {
0179                 memcpy(client_data->hid_descr[curr_hid_dev],
0180                        payload, payload_len);
0181                 client_data->hid_descr_size[curr_hid_dev] =
0182                     payload_len;
0183                 client_data->hid_descr_done = true;
0184             }
0185             wake_up_interruptible(&client_data->init_wait);
0186 
0187             break;
0188 
0189         case HOSTIF_GET_REPORT_DESCRIPTOR:
0190             if ((!(recv_msg->hdr.command & ~CMD_MASK) ||
0191                     client_data->init_done)) {
0192                 ++client_data->bad_recv_cnt;
0193                 report_bad_packet(hid_ishtp_cl, recv_msg,
0194                           cur_pos,
0195                           payload_len);
0196                 ish_hw_reset(ishtp_get_ishtp_device(hid_ishtp_cl));
0197                 break;
0198             }
0199             if (!client_data->report_descr[curr_hid_dev])
0200                 client_data->report_descr[curr_hid_dev] =
0201                 devm_kmalloc(cl_data_to_dev(client_data),
0202                          payload_len, GFP_KERNEL);
0203             if (client_data->report_descr[curr_hid_dev])  {
0204                 memcpy(client_data->report_descr[curr_hid_dev],
0205                        payload,
0206                        payload_len);
0207                 client_data->report_descr_size[curr_hid_dev] =
0208                     payload_len;
0209                 client_data->report_descr_done = true;
0210             }
0211             wake_up_interruptible(&client_data->init_wait);
0212 
0213             break;
0214 
0215         case HOSTIF_GET_FEATURE_REPORT:
0216             report_type = HID_FEATURE_REPORT;
0217             goto    do_get_report;
0218 
0219         case HOSTIF_GET_INPUT_REPORT:
0220             report_type = HID_INPUT_REPORT;
0221 do_get_report:
0222             /* Get index of device that matches this id */
0223             for (i = 0; i < client_data->num_hid_devices; ++i) {
0224                 if (recv_msg->hdr.device_id ==
0225                       client_data->hid_devices[i].dev_id) {
0226                     hid = client_data->hid_sensor_hubs[i];
0227                     if (!hid)
0228                         break;
0229 
0230                     hid_data = hid->driver_data;
0231                     if (hid_data->raw_get_req) {
0232                         raw_len =
0233                           (hid_data->raw_buf_size <
0234                                 payload_len) ?
0235                           hid_data->raw_buf_size :
0236                           payload_len;
0237 
0238                         memcpy(hid_data->raw_buf,
0239                                payload, raw_len);
0240                     } else {
0241                         hid_input_report
0242                             (hid, report_type,
0243                              payload, payload_len,
0244                              0);
0245                     }
0246 
0247                     ishtp_hid_wakeup(hid);
0248                     break;
0249                 }
0250             }
0251             break;
0252 
0253         case HOSTIF_SET_FEATURE_REPORT:
0254             /* Get index of device that matches this id */
0255             for (i = 0; i < client_data->num_hid_devices; ++i) {
0256                 if (recv_msg->hdr.device_id ==
0257                     client_data->hid_devices[i].dev_id)
0258                     if (client_data->hid_sensor_hubs[i]) {
0259                         ishtp_hid_wakeup(
0260                         client_data->hid_sensor_hubs[
0261                             i]);
0262                         break;
0263                     }
0264             }
0265             break;
0266 
0267         case HOSTIF_PUBLISH_INPUT_REPORT:
0268             report_type = HID_INPUT_REPORT;
0269             for (i = 0; i < client_data->num_hid_devices; ++i)
0270                 if (recv_msg->hdr.device_id ==
0271                     client_data->hid_devices[i].dev_id)
0272                     if (client_data->hid_sensor_hubs[i])
0273                         hid_input_report(
0274                         client_data->hid_sensor_hubs[
0275                                     i],
0276                         report_type, payload,
0277                         payload_len, 0);
0278             break;
0279 
0280         case HOSTIF_PUBLISH_INPUT_REPORT_LIST:
0281             report_type = HID_INPUT_REPORT;
0282             reports_list = (struct report_list *)payload;
0283             reports = (char *)reports_list->reports;
0284 
0285             for (j = 0; j < reports_list->num_of_reports; j++) {
0286                 recv_msg = (struct hostif_msg *)(reports +
0287                     sizeof(uint16_t));
0288                 report_len = *(uint16_t *)reports;
0289                 payload = reports + sizeof(uint16_t) +
0290                     sizeof(struct hostif_msg_hdr);
0291                 payload_len = report_len -
0292                     sizeof(struct hostif_msg_hdr);
0293 
0294                 for (i = 0; i < client_data->num_hid_devices;
0295                      ++i)
0296                     if (recv_msg->hdr.device_id ==
0297                     client_data->hid_devices[i].dev_id &&
0298                     client_data->hid_sensor_hubs[i]) {
0299                         hid_input_report(
0300                         client_data->hid_sensor_hubs[
0301                                     i],
0302                         report_type,
0303                         payload, payload_len,
0304                         0);
0305                     }
0306 
0307                 reports += sizeof(uint16_t) + report_len;
0308             }
0309             break;
0310         default:
0311             ++client_data->bad_recv_cnt;
0312             report_bad_packet(hid_ishtp_cl, recv_msg, cur_pos,
0313                       payload_len);
0314             ish_hw_reset(ishtp_get_ishtp_device(hid_ishtp_cl));
0315             break;
0316 
0317         }
0318 
0319         if (!cur_pos && cur_pos + payload_len +
0320                 sizeof(struct hostif_msg) < total_len)
0321             ++client_data->multi_packet_cnt;
0322 
0323         cur_pos += payload_len + sizeof(struct hostif_msg);
0324         payload += payload_len + sizeof(struct hostif_msg);
0325 
0326     } while (cur_pos < total_len);
0327 }
0328 
0329 /**
0330  * ish_cl_event_cb() - bus driver callback for incoming message/packet
0331  * @device: Pointer to the ishtp client device for which this message
0332  *      is targeted
0333  *
0334  * Remove the packet from the list and process the message by calling
0335  * process_recv
0336  */
0337 static void ish_cl_event_cb(struct ishtp_cl_device *device)
0338 {
0339     struct ishtp_cl *hid_ishtp_cl = ishtp_get_drvdata(device);
0340     struct ishtp_cl_rb *rb_in_proc;
0341     size_t r_length;
0342 
0343     if (!hid_ishtp_cl)
0344         return;
0345 
0346     while ((rb_in_proc = ishtp_cl_rx_get_rb(hid_ishtp_cl)) != NULL) {
0347         if (!rb_in_proc->buffer.data)
0348             return;
0349 
0350         r_length = rb_in_proc->buf_idx;
0351 
0352         /* decide what to do with received data */
0353         process_recv(hid_ishtp_cl, rb_in_proc->buffer.data, r_length);
0354 
0355         ishtp_cl_io_rb_recycle(rb_in_proc);
0356     }
0357 }
0358 
0359 /**
0360  * hid_ishtp_set_feature() - send request to ISH FW to set a feature request
0361  * @hid:    hid device instance for this request
0362  * @buf:    feature buffer
0363  * @len:    Length of feature buffer
0364  * @report_id:  Report id for the feature set request
0365  *
0366  * This is called from hid core .request() callback. This function doesn't wait
0367  * for response.
0368  */
0369 void hid_ishtp_set_feature(struct hid_device *hid, char *buf, unsigned int len,
0370                int report_id)
0371 {
0372     struct ishtp_hid_data *hid_data =  hid->driver_data;
0373     struct ishtp_cl_data *client_data = hid_data->client_data;
0374     struct hostif_msg *msg = (struct hostif_msg *)buf;
0375     int rv;
0376     int i;
0377 
0378     hid_ishtp_trace(client_data,  "%s hid %p\n", __func__, hid);
0379 
0380     rv = ishtp_hid_link_ready_wait(client_data);
0381     if (rv) {
0382         hid_ishtp_trace(client_data,  "%s hid %p link not ready\n",
0383                 __func__, hid);
0384         return;
0385     }
0386 
0387     memset(msg, 0, sizeof(struct hostif_msg));
0388     msg->hdr.command = HOSTIF_SET_FEATURE_REPORT;
0389     for (i = 0; i < client_data->num_hid_devices; ++i) {
0390         if (hid == client_data->hid_sensor_hubs[i]) {
0391             msg->hdr.device_id =
0392                 client_data->hid_devices[i].dev_id;
0393             break;
0394         }
0395     }
0396 
0397     if (i == client_data->num_hid_devices)
0398         return;
0399 
0400     rv = ishtp_cl_send(client_data->hid_ishtp_cl, buf, len);
0401     if (rv)
0402         hid_ishtp_trace(client_data,  "%s hid %p send failed\n",
0403                 __func__, hid);
0404 }
0405 
0406 /**
0407  * hid_ishtp_get_report() - request to get feature/input report
0408  * @hid:    hid device instance for this request
0409  * @report_id:  Report id for the get request
0410  * @report_type:    Report type for the this request
0411  *
0412  * This is called from hid core .request() callback. This function will send
0413  * request to FW and return without waiting for response.
0414  */
0415 void hid_ishtp_get_report(struct hid_device *hid, int report_id,
0416               int report_type)
0417 {
0418     struct ishtp_hid_data *hid_data =  hid->driver_data;
0419     struct ishtp_cl_data *client_data = hid_data->client_data;
0420     struct hostif_msg_to_sensor msg = {};
0421     int rv;
0422     int i;
0423 
0424     hid_ishtp_trace(client_data,  "%s hid %p\n", __func__, hid);
0425     rv = ishtp_hid_link_ready_wait(client_data);
0426     if (rv) {
0427         hid_ishtp_trace(client_data,  "%s hid %p link not ready\n",
0428                 __func__, hid);
0429         return;
0430     }
0431 
0432     msg.hdr.command = (report_type == HID_FEATURE_REPORT) ?
0433         HOSTIF_GET_FEATURE_REPORT : HOSTIF_GET_INPUT_REPORT;
0434     for (i = 0; i < client_data->num_hid_devices; ++i) {
0435         if (hid == client_data->hid_sensor_hubs[i]) {
0436             msg.hdr.device_id =
0437                 client_data->hid_devices[i].dev_id;
0438             break;
0439         }
0440     }
0441 
0442     if (i == client_data->num_hid_devices)
0443         return;
0444 
0445     msg.report_id = report_id;
0446     rv = ishtp_cl_send(client_data->hid_ishtp_cl, (uint8_t *)&msg,
0447                 sizeof(msg));
0448     if (rv)
0449         hid_ishtp_trace(client_data,  "%s hid %p send failed\n",
0450                 __func__, hid);
0451 }
0452 
0453 /**
0454  * ishtp_hid_link_ready_wait() - Wait for link ready
0455  * @client_data:    client data instance
0456  *
0457  * If the transport link started suspend process, then wait, till either
0458  * resumed or timeout
0459  *
0460  * Return: 0 on success, non zero on error
0461  */
0462 int ishtp_hid_link_ready_wait(struct ishtp_cl_data *client_data)
0463 {
0464     int rc;
0465 
0466     if (client_data->suspended) {
0467         hid_ishtp_trace(client_data,  "wait for link ready\n");
0468         rc = wait_event_interruptible_timeout(
0469                     client_data->ishtp_resume_wait,
0470                     !client_data->suspended,
0471                     5 * HZ);
0472 
0473         if (rc == 0) {
0474             hid_ishtp_trace(client_data,  "link not ready\n");
0475             return -EIO;
0476         }
0477         hid_ishtp_trace(client_data,  "link ready\n");
0478     }
0479 
0480     return 0;
0481 }
0482 
0483 /**
0484  * ishtp_enum_enum_devices() - Enumerate hid devices
0485  * @hid_ishtp_cl:   client instance
0486  *
0487  * Helper function to send request to firmware to enumerate HID devices
0488  *
0489  * Return: 0 on success, non zero on error
0490  */
0491 static int ishtp_enum_enum_devices(struct ishtp_cl *hid_ishtp_cl)
0492 {
0493     struct hostif_msg msg;
0494     struct ishtp_cl_data *client_data = ishtp_get_client_data(hid_ishtp_cl);
0495     int retry_count;
0496     int rv;
0497 
0498     /* Send HOSTIF_DM_ENUM_DEVICES */
0499     memset(&msg, 0, sizeof(struct hostif_msg));
0500     msg.hdr.command = HOSTIF_DM_ENUM_DEVICES;
0501     rv = ishtp_cl_send(hid_ishtp_cl, (unsigned char *)&msg,
0502                sizeof(struct hostif_msg));
0503     if (rv)
0504         return rv;
0505 
0506     retry_count = 0;
0507     while (!client_data->enum_devices_done &&
0508            retry_count < 10) {
0509         wait_event_interruptible_timeout(client_data->init_wait,
0510                      client_data->enum_devices_done,
0511                      3 * HZ);
0512         ++retry_count;
0513         if (!client_data->enum_devices_done)
0514             /* Send HOSTIF_DM_ENUM_DEVICES */
0515             rv = ishtp_cl_send(hid_ishtp_cl,
0516                        (unsigned char *) &msg,
0517                        sizeof(struct hostif_msg));
0518     }
0519     if (!client_data->enum_devices_done) {
0520         dev_err(cl_data_to_dev(client_data),
0521             "[hid-ish]: timed out waiting for enum_devices\n");
0522         return -ETIMEDOUT;
0523     }
0524     if (!client_data->hid_devices) {
0525         dev_err(cl_data_to_dev(client_data),
0526             "[hid-ish]: failed to allocate HID dev structures\n");
0527         return -ENOMEM;
0528     }
0529 
0530     client_data->num_hid_devices = client_data->hid_dev_count;
0531     dev_info(ishtp_device(client_data->cl_device),
0532         "[hid-ish]: enum_devices_done OK, num_hid_devices=%d\n",
0533         client_data->num_hid_devices);
0534 
0535     return  0;
0536 }
0537 
0538 /**
0539  * ishtp_get_hid_descriptor() - Get hid descriptor
0540  * @hid_ishtp_cl:   client instance
0541  * @index:      Index into the hid_descr array
0542  *
0543  * Helper function to send request to firmware get HID descriptor of a device
0544  *
0545  * Return: 0 on success, non zero on error
0546  */
0547 static int ishtp_get_hid_descriptor(struct ishtp_cl *hid_ishtp_cl, int index)
0548 {
0549     struct hostif_msg msg;
0550     struct ishtp_cl_data *client_data = ishtp_get_client_data(hid_ishtp_cl);
0551     int rv;
0552 
0553     /* Get HID descriptor */
0554     client_data->hid_descr_done = false;
0555     memset(&msg, 0, sizeof(struct hostif_msg));
0556     msg.hdr.command = HOSTIF_GET_HID_DESCRIPTOR;
0557     msg.hdr.device_id = client_data->hid_devices[index].dev_id;
0558     rv = ishtp_cl_send(hid_ishtp_cl, (unsigned char *) &msg,
0559                sizeof(struct hostif_msg));
0560     if (rv)
0561         return rv;
0562 
0563     if (!client_data->hid_descr_done) {
0564         wait_event_interruptible_timeout(client_data->init_wait,
0565                          client_data->hid_descr_done,
0566                          3 * HZ);
0567         if (!client_data->hid_descr_done) {
0568             dev_err(cl_data_to_dev(client_data),
0569                 "[hid-ish]: timed out for hid_descr_done\n");
0570             return -EIO;
0571         }
0572 
0573         if (!client_data->hid_descr[index]) {
0574             dev_err(cl_data_to_dev(client_data),
0575                 "[hid-ish]: allocation HID desc fail\n");
0576             return -ENOMEM;
0577         }
0578     }
0579 
0580     return 0;
0581 }
0582 
0583 /**
0584  * ishtp_get_report_descriptor() - Get report descriptor
0585  * @hid_ishtp_cl:   client instance
0586  * @index:      Index into the hid_descr array
0587  *
0588  * Helper function to send request to firmware get HID report descriptor of
0589  * a device
0590  *
0591  * Return: 0 on success, non zero on error
0592  */
0593 static int ishtp_get_report_descriptor(struct ishtp_cl *hid_ishtp_cl,
0594                        int index)
0595 {
0596     struct hostif_msg msg;
0597     struct ishtp_cl_data *client_data = ishtp_get_client_data(hid_ishtp_cl);
0598     int rv;
0599 
0600     /* Get report descriptor */
0601     client_data->report_descr_done = false;
0602     memset(&msg, 0, sizeof(struct hostif_msg));
0603     msg.hdr.command = HOSTIF_GET_REPORT_DESCRIPTOR;
0604     msg.hdr.device_id = client_data->hid_devices[index].dev_id;
0605     rv = ishtp_cl_send(hid_ishtp_cl, (unsigned char *) &msg,
0606                sizeof(struct hostif_msg));
0607     if (rv)
0608         return rv;
0609 
0610     if (!client_data->report_descr_done)
0611         wait_event_interruptible_timeout(client_data->init_wait,
0612                      client_data->report_descr_done,
0613                      3 * HZ);
0614     if (!client_data->report_descr_done) {
0615         dev_err(cl_data_to_dev(client_data),
0616                 "[hid-ish]: timed out for report descr\n");
0617         return -EIO;
0618     }
0619     if (!client_data->report_descr[index]) {
0620         dev_err(cl_data_to_dev(client_data),
0621             "[hid-ish]: failed to alloc report descr\n");
0622         return -ENOMEM;
0623     }
0624 
0625     return 0;
0626 }
0627 
0628 /**
0629  * hid_ishtp_cl_init() - Init function for ISHTP client
0630  * @hid_ishtp_cl:   ISHTP client instance
0631  * @reset:      true if called for init after reset
0632  *
0633  * This function complete the initializtion of the client. The summary of
0634  * processing:
0635  * - Send request to enumerate the hid clients
0636  *  Get the HID descriptor for each enumearated device
0637  *  Get report description of each device
0638  *  Register each device wik hid core by calling ishtp_hid_probe
0639  *
0640  * Return: 0 on success, non zero on error
0641  */
0642 static int hid_ishtp_cl_init(struct ishtp_cl *hid_ishtp_cl, int reset)
0643 {
0644     struct ishtp_device *dev;
0645     struct ishtp_cl_data *client_data = ishtp_get_client_data(hid_ishtp_cl);
0646     struct ishtp_fw_client *fw_client;
0647     int i;
0648     int rv;
0649 
0650     dev_dbg(cl_data_to_dev(client_data), "%s\n", __func__);
0651     hid_ishtp_trace(client_data,  "%s reset flag: %d\n", __func__, reset);
0652 
0653     rv = ishtp_cl_link(hid_ishtp_cl);
0654     if (rv) {
0655         dev_err(cl_data_to_dev(client_data),
0656             "ishtp_cl_link failed\n");
0657         return  -ENOMEM;
0658     }
0659 
0660     client_data->init_done = 0;
0661 
0662     dev = ishtp_get_ishtp_device(hid_ishtp_cl);
0663 
0664     /* Connect to FW client */
0665     ishtp_set_tx_ring_size(hid_ishtp_cl, HID_CL_TX_RING_SIZE);
0666     ishtp_set_rx_ring_size(hid_ishtp_cl, HID_CL_RX_RING_SIZE);
0667 
0668     fw_client = ishtp_fw_cl_get_client(dev, &hid_ishtp_id_table[0].guid);
0669     if (!fw_client) {
0670         dev_err(cl_data_to_dev(client_data),
0671             "ish client uuid not found\n");
0672         return -ENOENT;
0673     }
0674     ishtp_cl_set_fw_client_id(hid_ishtp_cl,
0675                   ishtp_get_fw_client_id(fw_client));
0676     ishtp_set_connection_state(hid_ishtp_cl, ISHTP_CL_CONNECTING);
0677 
0678     rv = ishtp_cl_connect(hid_ishtp_cl);
0679     if (rv) {
0680         dev_err(cl_data_to_dev(client_data),
0681             "client connect fail\n");
0682         goto err_cl_unlink;
0683     }
0684 
0685     hid_ishtp_trace(client_data,  "%s client connected\n", __func__);
0686 
0687     /* Register read callback */
0688     ishtp_register_event_cb(client_data->cl_device, ish_cl_event_cb);
0689 
0690     rv = ishtp_enum_enum_devices(hid_ishtp_cl);
0691     if (rv)
0692         goto err_cl_disconnect;
0693 
0694     hid_ishtp_trace(client_data,  "%s enumerated device count %d\n",
0695             __func__, client_data->num_hid_devices);
0696 
0697     for (i = 0; i < client_data->num_hid_devices; ++i) {
0698         client_data->cur_hid_dev = i;
0699 
0700         rv = ishtp_get_hid_descriptor(hid_ishtp_cl, i);
0701         if (rv)
0702             goto err_cl_disconnect;
0703 
0704         rv = ishtp_get_report_descriptor(hid_ishtp_cl, i);
0705         if (rv)
0706             goto err_cl_disconnect;
0707 
0708         if (!reset) {
0709             rv = ishtp_hid_probe(i, client_data);
0710             if (rv) {
0711                 dev_err(cl_data_to_dev(client_data),
0712                 "[hid-ish]: HID probe for #%u failed: %d\n",
0713                 i, rv);
0714                 goto err_cl_disconnect;
0715             }
0716         }
0717     } /* for() on all hid devices */
0718 
0719     client_data->init_done = 1;
0720     client_data->suspended = false;
0721     wake_up_interruptible(&client_data->ishtp_resume_wait);
0722     hid_ishtp_trace(client_data,  "%s successful init\n", __func__);
0723     return 0;
0724 
0725 err_cl_disconnect:
0726     ishtp_set_connection_state(hid_ishtp_cl, ISHTP_CL_DISCONNECTING);
0727     ishtp_cl_disconnect(hid_ishtp_cl);
0728 err_cl_unlink:
0729     ishtp_cl_unlink(hid_ishtp_cl);
0730     return rv;
0731 }
0732 
0733 /**
0734  * hid_ishtp_cl_deinit() - Deinit function for ISHTP client
0735  * @hid_ishtp_cl:   ISHTP client instance
0736  *
0737  * Unlink and free hid client
0738  */
0739 static void hid_ishtp_cl_deinit(struct ishtp_cl *hid_ishtp_cl)
0740 {
0741     ishtp_cl_unlink(hid_ishtp_cl);
0742     ishtp_cl_flush_queues(hid_ishtp_cl);
0743 
0744     /* disband and free all Tx and Rx client-level rings */
0745     ishtp_cl_free(hid_ishtp_cl);
0746 }
0747 
0748 static void hid_ishtp_cl_reset_handler(struct work_struct *work)
0749 {
0750     struct ishtp_cl_data *client_data;
0751     struct ishtp_cl *hid_ishtp_cl;
0752     struct ishtp_cl_device *cl_device;
0753     int retry;
0754     int rv;
0755 
0756     client_data = container_of(work, struct ishtp_cl_data, work);
0757 
0758     hid_ishtp_cl = client_data->hid_ishtp_cl;
0759     cl_device = client_data->cl_device;
0760 
0761     hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__,
0762             hid_ishtp_cl);
0763     dev_dbg(ishtp_device(client_data->cl_device), "%s\n", __func__);
0764 
0765     hid_ishtp_cl_deinit(hid_ishtp_cl);
0766 
0767     hid_ishtp_cl = ishtp_cl_allocate(cl_device);
0768     if (!hid_ishtp_cl)
0769         return;
0770 
0771     ishtp_set_drvdata(cl_device, hid_ishtp_cl);
0772     ishtp_set_client_data(hid_ishtp_cl, client_data);
0773     client_data->hid_ishtp_cl = hid_ishtp_cl;
0774 
0775     client_data->num_hid_devices = 0;
0776 
0777     for (retry = 0; retry < 3; ++retry) {
0778         rv = hid_ishtp_cl_init(hid_ishtp_cl, 1);
0779         if (!rv)
0780             break;
0781         dev_err(cl_data_to_dev(client_data), "Retry reset init\n");
0782     }
0783     if (rv) {
0784         dev_err(cl_data_to_dev(client_data), "Reset Failed\n");
0785         hid_ishtp_trace(client_data, "%s Failed hid_ishtp_cl %p\n",
0786                 __func__, hid_ishtp_cl);
0787     }
0788 }
0789 
0790 static void hid_ishtp_cl_resume_handler(struct work_struct *work)
0791 {
0792     struct ishtp_cl_data *client_data = container_of(work, struct ishtp_cl_data, resume_work);
0793     struct ishtp_cl *hid_ishtp_cl = client_data->hid_ishtp_cl;
0794 
0795     if (ishtp_wait_resume(ishtp_get_ishtp_device(hid_ishtp_cl))) {
0796         client_data->suspended = false;
0797         wake_up_interruptible(&client_data->ishtp_resume_wait);
0798     }
0799 }
0800 
0801 ishtp_print_log ishtp_hid_print_trace;
0802 
0803 /**
0804  * hid_ishtp_cl_probe() - ISHTP client driver probe
0805  * @cl_device:      ISHTP client device instance
0806  *
0807  * This function gets called on device create on ISHTP bus
0808  *
0809  * Return: 0 on success, non zero on error
0810  */
0811 static int hid_ishtp_cl_probe(struct ishtp_cl_device *cl_device)
0812 {
0813     struct ishtp_cl *hid_ishtp_cl;
0814     struct ishtp_cl_data *client_data;
0815     int rv;
0816 
0817     if (!cl_device)
0818         return  -ENODEV;
0819 
0820     client_data = devm_kzalloc(ishtp_device(cl_device),
0821                    sizeof(*client_data),
0822                    GFP_KERNEL);
0823     if (!client_data)
0824         return -ENOMEM;
0825 
0826     hid_ishtp_cl = ishtp_cl_allocate(cl_device);
0827     if (!hid_ishtp_cl)
0828         return -ENOMEM;
0829 
0830     ishtp_set_drvdata(cl_device, hid_ishtp_cl);
0831     ishtp_set_client_data(hid_ishtp_cl, client_data);
0832     client_data->hid_ishtp_cl = hid_ishtp_cl;
0833     client_data->cl_device = cl_device;
0834 
0835     init_waitqueue_head(&client_data->init_wait);
0836     init_waitqueue_head(&client_data->ishtp_resume_wait);
0837 
0838     INIT_WORK(&client_data->work, hid_ishtp_cl_reset_handler);
0839     INIT_WORK(&client_data->resume_work, hid_ishtp_cl_resume_handler);
0840 
0841 
0842     ishtp_hid_print_trace = ishtp_trace_callback(cl_device);
0843 
0844     rv = hid_ishtp_cl_init(hid_ishtp_cl, 0);
0845     if (rv) {
0846         ishtp_cl_free(hid_ishtp_cl);
0847         return rv;
0848     }
0849     ishtp_get_device(cl_device);
0850 
0851     return 0;
0852 }
0853 
0854 /**
0855  * hid_ishtp_cl_remove() - ISHTP client driver remove
0856  * @cl_device:      ISHTP client device instance
0857  *
0858  * This function gets called on device remove on ISHTP bus
0859  *
0860  * Return: 0
0861  */
0862 static void hid_ishtp_cl_remove(struct ishtp_cl_device *cl_device)
0863 {
0864     struct ishtp_cl *hid_ishtp_cl = ishtp_get_drvdata(cl_device);
0865     struct ishtp_cl_data *client_data = ishtp_get_client_data(hid_ishtp_cl);
0866 
0867     hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__,
0868             hid_ishtp_cl);
0869 
0870     dev_dbg(ishtp_device(cl_device), "%s\n", __func__);
0871     ishtp_set_connection_state(hid_ishtp_cl, ISHTP_CL_DISCONNECTING);
0872     ishtp_cl_disconnect(hid_ishtp_cl);
0873     ishtp_put_device(cl_device);
0874     ishtp_hid_remove(client_data);
0875     hid_ishtp_cl_deinit(hid_ishtp_cl);
0876 
0877     hid_ishtp_cl = NULL;
0878 
0879     client_data->num_hid_devices = 0;
0880 }
0881 
0882 /**
0883  * hid_ishtp_cl_reset() - ISHTP client driver reset
0884  * @cl_device:      ISHTP client device instance
0885  *
0886  * This function gets called on device reset on ISHTP bus
0887  *
0888  * Return: 0
0889  */
0890 static int hid_ishtp_cl_reset(struct ishtp_cl_device *cl_device)
0891 {
0892     struct ishtp_cl *hid_ishtp_cl = ishtp_get_drvdata(cl_device);
0893     struct ishtp_cl_data *client_data = ishtp_get_client_data(hid_ishtp_cl);
0894 
0895     hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__,
0896             hid_ishtp_cl);
0897 
0898     schedule_work(&client_data->work);
0899 
0900     return 0;
0901 }
0902 
0903 /**
0904  * hid_ishtp_cl_suspend() - ISHTP client driver suspend
0905  * @device: device instance
0906  *
0907  * This function gets called on system suspend
0908  *
0909  * Return: 0
0910  */
0911 static int hid_ishtp_cl_suspend(struct device *device)
0912 {
0913     struct ishtp_cl_device *cl_device = ishtp_dev_to_cl_device(device);
0914     struct ishtp_cl *hid_ishtp_cl = ishtp_get_drvdata(cl_device);
0915     struct ishtp_cl_data *client_data = ishtp_get_client_data(hid_ishtp_cl);
0916 
0917     hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__,
0918             hid_ishtp_cl);
0919     client_data->suspended = true;
0920 
0921     return 0;
0922 }
0923 
0924 /**
0925  * hid_ishtp_cl_resume() - ISHTP client driver resume
0926  * @device: device instance
0927  *
0928  * This function gets called on system resume
0929  *
0930  * Return: 0
0931  */
0932 static int hid_ishtp_cl_resume(struct device *device)
0933 {
0934     struct ishtp_cl_device *cl_device = ishtp_dev_to_cl_device(device);
0935     struct ishtp_cl *hid_ishtp_cl = ishtp_get_drvdata(cl_device);
0936     struct ishtp_cl_data *client_data = ishtp_get_client_data(hid_ishtp_cl);
0937 
0938     hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__,
0939             hid_ishtp_cl);
0940     schedule_work(&client_data->resume_work);
0941     return 0;
0942 }
0943 
0944 static const struct dev_pm_ops hid_ishtp_pm_ops = {
0945     .suspend = hid_ishtp_cl_suspend,
0946     .resume = hid_ishtp_cl_resume,
0947 };
0948 
0949 static struct ishtp_cl_driver   hid_ishtp_cl_driver = {
0950     .name = "ish-hid",
0951     .id = hid_ishtp_id_table,
0952     .probe = hid_ishtp_cl_probe,
0953     .remove = hid_ishtp_cl_remove,
0954     .reset = hid_ishtp_cl_reset,
0955     .driver.pm = &hid_ishtp_pm_ops,
0956 };
0957 
0958 static int __init ish_hid_init(void)
0959 {
0960     int rv;
0961 
0962     /* Register ISHTP client device driver with ISHTP Bus */
0963     rv = ishtp_cl_driver_register(&hid_ishtp_cl_driver, THIS_MODULE);
0964 
0965     return rv;
0966 
0967 }
0968 
0969 static void __exit ish_hid_exit(void)
0970 {
0971     ishtp_cl_driver_unregister(&hid_ishtp_cl_driver);
0972 }
0973 
0974 late_initcall(ish_hid_init);
0975 module_exit(ish_hid_exit);
0976 
0977 MODULE_DESCRIPTION("ISH ISHTP HID client driver");
0978 /* Primary author */
0979 MODULE_AUTHOR("Daniel Drubin <daniel.drubin@intel.com>");
0980 /*
0981  * Several modification for multi instance support
0982  * suspend/resume and clean up
0983  */
0984 MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
0985 
0986 MODULE_LICENSE("GPL");