root/drivers/hid/intel-ish-hid/ishtp-hid-client.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. report_bad_packet
  2. process_recv
  3. ish_cl_event_cb
  4. hid_ishtp_set_feature
  5. hid_ishtp_get_report
  6. ishtp_hid_link_ready_wait
  7. ishtp_enum_enum_devices
  8. ishtp_get_hid_descriptor
  9. ishtp_get_report_descriptor
  10. hid_ishtp_cl_init
  11. hid_ishtp_cl_deinit
  12. hid_ishtp_cl_reset_handler
  13. hid_ishtp_cl_probe
  14. hid_ishtp_cl_remove
  15. hid_ishtp_cl_reset
  16. hid_ishtp_cl_suspend
  17. hid_ishtp_cl_resume
  18. ish_hid_init
  19. ish_hid_exit

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * ISHTP client driver for HID (ISH)
   4  *
   5  * Copyright (c) 2014-2016, Intel Corporation.
   6  */
   7 
   8 #include <linux/module.h>
   9 #include <linux/hid.h>
  10 #include <linux/intel-ish-client-if.h>
  11 #include <linux/sched.h>
  12 #include "ishtp-hid.h"
  13 
  14 /* Rx ring buffer pool size */
  15 #define HID_CL_RX_RING_SIZE     32
  16 #define HID_CL_TX_RING_SIZE     16
  17 
  18 #define cl_data_to_dev(client_data) ishtp_device(client_data->cl_device)
  19 
  20 /**
  21  * report_bad_packets() - Report bad packets
  22  * @hid_ishtp_cl:       Client instance to get stats
  23  * @recv_buf:           Raw received host interface message
  24  * @cur_pos:            Current position index in payload
  25  * @payload_len:        Length of payload expected
  26  *
  27  * Dumps error in case bad packet is received
  28  */
  29 static void report_bad_packet(struct ishtp_cl *hid_ishtp_cl, void *recv_buf,
  30                               size_t cur_pos,  size_t payload_len)
  31 {
  32         struct hostif_msg *recv_msg = recv_buf;
  33         struct ishtp_cl_data *client_data = ishtp_get_client_data(hid_ishtp_cl);
  34 
  35         dev_err(cl_data_to_dev(client_data), "[hid-ish]: BAD packet %02X\n"
  36                 "total_bad=%u cur_pos=%u\n"
  37                 "[%02X %02X %02X %02X]\n"
  38                 "payload_len=%u\n"
  39                 "multi_packet_cnt=%u\n"
  40                 "is_response=%02X\n",
  41                 recv_msg->hdr.command, client_data->bad_recv_cnt,
  42                 (unsigned int)cur_pos,
  43                 ((unsigned char *)recv_msg)[0], ((unsigned char *)recv_msg)[1],
  44                 ((unsigned char *)recv_msg)[2], ((unsigned char *)recv_msg)[3],
  45                 (unsigned int)payload_len, client_data->multi_packet_cnt,
  46                 recv_msg->hdr.command & ~CMD_MASK);
  47 }
  48 
  49 /**
  50  * process_recv() - Received and parse incoming packet
  51  * @hid_ishtp_cl:       Client instance to get stats
  52  * @recv_buf:           Raw received host interface message
  53  * @data_len:           length of the message
  54  *
  55  * Parse the incoming packet. If it is a response packet then it will update
  56  * per instance flags and wake up the caller waiting to for the response.
  57  */
  58 static void process_recv(struct ishtp_cl *hid_ishtp_cl, void *recv_buf,
  59                          size_t data_len)
  60 {
  61         struct hostif_msg *recv_msg;
  62         unsigned char *payload;
  63         struct device_info *dev_info;
  64         int i, j;
  65         size_t  payload_len, total_len, cur_pos, raw_len;
  66         int report_type;
  67         struct report_list *reports_list;
  68         char *reports;
  69         size_t report_len;
  70         struct ishtp_cl_data *client_data = ishtp_get_client_data(hid_ishtp_cl);
  71         int curr_hid_dev = client_data->cur_hid_dev;
  72         struct ishtp_hid_data *hid_data = NULL;
  73         struct hid_device *hid = NULL;
  74 
  75         payload = recv_buf + sizeof(struct hostif_msg_hdr);
  76         total_len = data_len;
  77         cur_pos = 0;
  78 
  79         do {
  80                 if (cur_pos + sizeof(struct hostif_msg) > total_len) {
  81                         dev_err(cl_data_to_dev(client_data),
  82                                 "[hid-ish]: error, received %u which is less than data header %u\n",
  83                                 (unsigned int)data_len,
  84                                 (unsigned int)sizeof(struct hostif_msg_hdr));
  85                         ++client_data->bad_recv_cnt;
  86                         ish_hw_reset(ishtp_get_ishtp_device(hid_ishtp_cl));
  87                         break;
  88                 }
  89 
  90                 recv_msg = (struct hostif_msg *)(recv_buf + cur_pos);
  91                 payload_len = recv_msg->hdr.size;
  92 
  93                 /* Sanity checks */
  94                 if (cur_pos + payload_len + sizeof(struct hostif_msg) >
  95                                 total_len) {
  96                         ++client_data->bad_recv_cnt;
  97                         report_bad_packet(hid_ishtp_cl, recv_msg, cur_pos,
  98                                           payload_len);
  99                         ish_hw_reset(ishtp_get_ishtp_device(hid_ishtp_cl));
 100                         break;
 101                 }
 102 
 103                 hid_ishtp_trace(client_data,  "%s %d\n",
 104                                 __func__, recv_msg->hdr.command & CMD_MASK);
 105 
 106                 switch (recv_msg->hdr.command & CMD_MASK) {
 107                 case HOSTIF_DM_ENUM_DEVICES:
 108                         if ((!(recv_msg->hdr.command & ~CMD_MASK) ||
 109                                         client_data->init_done)) {
 110                                 ++client_data->bad_recv_cnt;
 111                                 report_bad_packet(hid_ishtp_cl, recv_msg,
 112                                                   cur_pos,
 113                                                   payload_len);
 114                                 ish_hw_reset(ishtp_get_ishtp_device(hid_ishtp_cl));
 115                                 break;
 116                         }
 117                         client_data->hid_dev_count = (unsigned int)*payload;
 118                         if (!client_data->hid_devices)
 119                                 client_data->hid_devices = devm_kcalloc(
 120                                                 cl_data_to_dev(client_data),
 121                                                 client_data->hid_dev_count,
 122                                                 sizeof(struct device_info),
 123                                                 GFP_KERNEL);
 124                         if (!client_data->hid_devices) {
 125                                 dev_err(cl_data_to_dev(client_data),
 126                                 "Mem alloc failed for hid device info\n");
 127                                 wake_up_interruptible(&client_data->init_wait);
 128                                 break;
 129                         }
 130                         for (i = 0; i < client_data->hid_dev_count; ++i) {
 131                                 if (1 + sizeof(struct device_info) * i >=
 132                                                 payload_len) {
 133                                         dev_err(cl_data_to_dev(client_data),
 134                                                 "[hid-ish]: [ENUM_DEVICES]: content size %zu is bigger than payload_len %zu\n",
 135                                                 1 + sizeof(struct device_info)
 136                                                 * i, payload_len);
 137                                 }
 138 
 139                                 if (1 + sizeof(struct device_info) * i >=
 140                                                 data_len)
 141                                         break;
 142 
 143                                 dev_info = (struct device_info *)(payload + 1 +
 144                                         sizeof(struct device_info) * i);
 145                                 if (client_data->hid_devices)
 146                                         memcpy(client_data->hid_devices + i,
 147                                                dev_info,
 148                                                sizeof(struct device_info));
 149                         }
 150 
 151                         client_data->enum_devices_done = true;
 152                         wake_up_interruptible(&client_data->init_wait);
 153 
 154                         break;
 155 
 156                 case HOSTIF_GET_HID_DESCRIPTOR:
 157                         if ((!(recv_msg->hdr.command & ~CMD_MASK) ||
 158                                         client_data->init_done)) {
 159                                 ++client_data->bad_recv_cnt;
 160                                 report_bad_packet(hid_ishtp_cl, recv_msg,
 161                                                   cur_pos,
 162                                                   payload_len);
 163                                 ish_hw_reset(ishtp_get_ishtp_device(hid_ishtp_cl));
 164                                 break;
 165                         }
 166                         if (!client_data->hid_descr[curr_hid_dev])
 167                                 client_data->hid_descr[curr_hid_dev] =
 168                                 devm_kmalloc(cl_data_to_dev(client_data),
 169                                              payload_len, GFP_KERNEL);
 170                         if (client_data->hid_descr[curr_hid_dev]) {
 171                                 memcpy(client_data->hid_descr[curr_hid_dev],
 172                                        payload, payload_len);
 173                                 client_data->hid_descr_size[curr_hid_dev] =
 174                                         payload_len;
 175                                 client_data->hid_descr_done = true;
 176                         }
 177                         wake_up_interruptible(&client_data->init_wait);
 178 
 179                         break;
 180 
 181                 case HOSTIF_GET_REPORT_DESCRIPTOR:
 182                         if ((!(recv_msg->hdr.command & ~CMD_MASK) ||
 183                                         client_data->init_done)) {
 184                                 ++client_data->bad_recv_cnt;
 185                                 report_bad_packet(hid_ishtp_cl, recv_msg,
 186                                                   cur_pos,
 187                                                   payload_len);
 188                                 ish_hw_reset(ishtp_get_ishtp_device(hid_ishtp_cl));
 189                                 break;
 190                         }
 191                         if (!client_data->report_descr[curr_hid_dev])
 192                                 client_data->report_descr[curr_hid_dev] =
 193                                 devm_kmalloc(cl_data_to_dev(client_data),
 194                                              payload_len, GFP_KERNEL);
 195                         if (client_data->report_descr[curr_hid_dev])  {
 196                                 memcpy(client_data->report_descr[curr_hid_dev],
 197                                        payload,
 198                                        payload_len);
 199                                 client_data->report_descr_size[curr_hid_dev] =
 200                                         payload_len;
 201                                 client_data->report_descr_done = true;
 202                         }
 203                         wake_up_interruptible(&client_data->init_wait);
 204 
 205                         break;
 206 
 207                 case HOSTIF_GET_FEATURE_REPORT:
 208                         report_type = HID_FEATURE_REPORT;
 209                         goto    do_get_report;
 210 
 211                 case HOSTIF_GET_INPUT_REPORT:
 212                         report_type = HID_INPUT_REPORT;
 213 do_get_report:
 214                         /* Get index of device that matches this id */
 215                         for (i = 0; i < client_data->num_hid_devices; ++i) {
 216                                 if (recv_msg->hdr.device_id ==
 217                                           client_data->hid_devices[i].dev_id) {
 218                                         hid = client_data->hid_sensor_hubs[i];
 219                                         if (!hid)
 220                                                 break;
 221 
 222                                         hid_data = hid->driver_data;
 223                                         if (hid_data->raw_get_req) {
 224                                                 raw_len =
 225                                                   (hid_data->raw_buf_size <
 226                                                                 payload_len) ?
 227                                                   hid_data->raw_buf_size :
 228                                                   payload_len;
 229 
 230                                                 memcpy(hid_data->raw_buf,
 231                                                        payload, raw_len);
 232                                         } else {
 233                                                 hid_input_report
 234                                                         (hid, report_type,
 235                                                          payload, payload_len,
 236                                                          0);
 237                                         }
 238 
 239                                         ishtp_hid_wakeup(hid);
 240                                         break;
 241                                 }
 242                         }
 243                         break;
 244 
 245                 case HOSTIF_SET_FEATURE_REPORT:
 246                         /* Get index of device that matches this id */
 247                         for (i = 0; i < client_data->num_hid_devices; ++i) {
 248                                 if (recv_msg->hdr.device_id ==
 249                                         client_data->hid_devices[i].dev_id)
 250                                         if (client_data->hid_sensor_hubs[i]) {
 251                                                 ishtp_hid_wakeup(
 252                                                 client_data->hid_sensor_hubs[
 253                                                         i]);
 254                                                 break;
 255                                         }
 256                         }
 257                         break;
 258 
 259                 case HOSTIF_PUBLISH_INPUT_REPORT:
 260                         report_type = HID_INPUT_REPORT;
 261                         for (i = 0; i < client_data->num_hid_devices; ++i)
 262                                 if (recv_msg->hdr.device_id ==
 263                                         client_data->hid_devices[i].dev_id)
 264                                         if (client_data->hid_sensor_hubs[i])
 265                                                 hid_input_report(
 266                                                 client_data->hid_sensor_hubs[
 267                                                                         i],
 268                                                 report_type, payload,
 269                                                 payload_len, 0);
 270                         break;
 271 
 272                 case HOSTIF_PUBLISH_INPUT_REPORT_LIST:
 273                         report_type = HID_INPUT_REPORT;
 274                         reports_list = (struct report_list *)payload;
 275                         reports = (char *)reports_list->reports;
 276 
 277                         for (j = 0; j < reports_list->num_of_reports; j++) {
 278                                 recv_msg = (struct hostif_msg *)(reports +
 279                                         sizeof(uint16_t));
 280                                 report_len = *(uint16_t *)reports;
 281                                 payload = reports + sizeof(uint16_t) +
 282                                         sizeof(struct hostif_msg_hdr);
 283                                 payload_len = report_len -
 284                                         sizeof(struct hostif_msg_hdr);
 285 
 286                                 for (i = 0; i < client_data->num_hid_devices;
 287                                      ++i)
 288                                         if (recv_msg->hdr.device_id ==
 289                                         client_data->hid_devices[i].dev_id &&
 290                                         client_data->hid_sensor_hubs[i]) {
 291                                                 hid_input_report(
 292                                                 client_data->hid_sensor_hubs[
 293                                                                         i],
 294                                                 report_type,
 295                                                 payload, payload_len,
 296                                                 0);
 297                                         }
 298 
 299                                 reports += sizeof(uint16_t) + report_len;
 300                         }
 301                         break;
 302                 default:
 303                         ++client_data->bad_recv_cnt;
 304                         report_bad_packet(hid_ishtp_cl, recv_msg, cur_pos,
 305                                           payload_len);
 306                         ish_hw_reset(ishtp_get_ishtp_device(hid_ishtp_cl));
 307                         break;
 308 
 309                 }
 310 
 311                 if (!cur_pos && cur_pos + payload_len +
 312                                 sizeof(struct hostif_msg) < total_len)
 313                         ++client_data->multi_packet_cnt;
 314 
 315                 cur_pos += payload_len + sizeof(struct hostif_msg);
 316                 payload += payload_len + sizeof(struct hostif_msg);
 317 
 318         } while (cur_pos < total_len);
 319 }
 320 
 321 /**
 322  * ish_cl_event_cb() - bus driver callback for incoming message/packet
 323  * @device:     Pointer to the the ishtp client device for which this message
 324  *              is targeted
 325  *
 326  * Remove the packet from the list and process the message by calling
 327  * process_recv
 328  */
 329 static void ish_cl_event_cb(struct ishtp_cl_device *device)
 330 {
 331         struct ishtp_cl *hid_ishtp_cl = ishtp_get_drvdata(device);
 332         struct ishtp_cl_rb *rb_in_proc;
 333         size_t r_length;
 334 
 335         if (!hid_ishtp_cl)
 336                 return;
 337 
 338         while ((rb_in_proc = ishtp_cl_rx_get_rb(hid_ishtp_cl)) != NULL) {
 339                 if (!rb_in_proc->buffer.data)
 340                         return;
 341 
 342                 r_length = rb_in_proc->buf_idx;
 343 
 344                 /* decide what to do with received data */
 345                 process_recv(hid_ishtp_cl, rb_in_proc->buffer.data, r_length);
 346 
 347                 ishtp_cl_io_rb_recycle(rb_in_proc);
 348         }
 349 }
 350 
 351 /**
 352  * hid_ishtp_set_feature() - send request to ISH FW to set a feature request
 353  * @hid:        hid device instance for this request
 354  * @buf:        feature buffer
 355  * @len:        Length of feature buffer
 356  * @report_id:  Report id for the feature set request
 357  *
 358  * This is called from hid core .request() callback. This function doesn't wait
 359  * for response.
 360  */
 361 void hid_ishtp_set_feature(struct hid_device *hid, char *buf, unsigned int len,
 362                            int report_id)
 363 {
 364         struct ishtp_hid_data *hid_data =  hid->driver_data;
 365         struct ishtp_cl_data *client_data = hid_data->client_data;
 366         struct hostif_msg *msg = (struct hostif_msg *)buf;
 367         int     rv;
 368         int     i;
 369 
 370         hid_ishtp_trace(client_data,  "%s hid %p\n", __func__, hid);
 371 
 372         rv = ishtp_hid_link_ready_wait(client_data);
 373         if (rv) {
 374                 hid_ishtp_trace(client_data,  "%s hid %p link not ready\n",
 375                                 __func__, hid);
 376                 return;
 377         }
 378 
 379         memset(msg, 0, sizeof(struct hostif_msg));
 380         msg->hdr.command = HOSTIF_SET_FEATURE_REPORT;
 381         for (i = 0; i < client_data->num_hid_devices; ++i) {
 382                 if (hid == client_data->hid_sensor_hubs[i]) {
 383                         msg->hdr.device_id =
 384                                 client_data->hid_devices[i].dev_id;
 385                         break;
 386                 }
 387         }
 388 
 389         if (i == client_data->num_hid_devices)
 390                 return;
 391 
 392         rv = ishtp_cl_send(client_data->hid_ishtp_cl, buf, len);
 393         if (rv)
 394                 hid_ishtp_trace(client_data,  "%s hid %p send failed\n",
 395                                 __func__, hid);
 396 }
 397 
 398 /**
 399  * hid_ishtp_get_report() - request to get feature/input report
 400  * @hid:        hid device instance for this request
 401  * @report_id:  Report id for the get request
 402  * @report_type:        Report type for the this request
 403  *
 404  * This is called from hid core .request() callback. This function will send
 405  * request to FW and return without waiting for response.
 406  */
 407 void hid_ishtp_get_report(struct hid_device *hid, int report_id,
 408                           int report_type)
 409 {
 410         struct ishtp_hid_data *hid_data =  hid->driver_data;
 411         struct ishtp_cl_data *client_data = hid_data->client_data;
 412         struct hostif_msg_to_sensor msg = {};
 413         int     rv;
 414         int     i;
 415 
 416         hid_ishtp_trace(client_data,  "%s hid %p\n", __func__, hid);
 417         rv = ishtp_hid_link_ready_wait(client_data);
 418         if (rv) {
 419                 hid_ishtp_trace(client_data,  "%s hid %p link not ready\n",
 420                                 __func__, hid);
 421                 return;
 422         }
 423 
 424         msg.hdr.command = (report_type == HID_FEATURE_REPORT) ?
 425                 HOSTIF_GET_FEATURE_REPORT : HOSTIF_GET_INPUT_REPORT;
 426         for (i = 0; i < client_data->num_hid_devices; ++i) {
 427                 if (hid == client_data->hid_sensor_hubs[i]) {
 428                         msg.hdr.device_id =
 429                                 client_data->hid_devices[i].dev_id;
 430                         break;
 431                 }
 432         }
 433 
 434         if (i == client_data->num_hid_devices)
 435                 return;
 436 
 437         msg.report_id = report_id;
 438         rv = ishtp_cl_send(client_data->hid_ishtp_cl, (uint8_t *)&msg,
 439                             sizeof(msg));
 440         if (rv)
 441                 hid_ishtp_trace(client_data,  "%s hid %p send failed\n",
 442                                 __func__, hid);
 443 }
 444 
 445 /**
 446  * ishtp_hid_link_ready_wait() - Wait for link ready
 447  * @client_data:        client data instance
 448  *
 449  * If the transport link started suspend process, then wait, till either
 450  * resumed or timeout
 451  *
 452  * Return: 0 on success, non zero on error
 453  */
 454 int ishtp_hid_link_ready_wait(struct ishtp_cl_data *client_data)
 455 {
 456         int rc;
 457 
 458         if (client_data->suspended) {
 459                 hid_ishtp_trace(client_data,  "wait for link ready\n");
 460                 rc = wait_event_interruptible_timeout(
 461                                         client_data->ishtp_resume_wait,
 462                                         !client_data->suspended,
 463                                         5 * HZ);
 464 
 465                 if (rc == 0) {
 466                         hid_ishtp_trace(client_data,  "link not ready\n");
 467                         return -EIO;
 468                 }
 469                 hid_ishtp_trace(client_data,  "link ready\n");
 470         }
 471 
 472         return 0;
 473 }
 474 
 475 /**
 476  * ishtp_enum_enum_devices() - Enumerate hid devices
 477  * @hid_ishtp_cl:       client instance
 478  *
 479  * Helper function to send request to firmware to enumerate HID devices
 480  *
 481  * Return: 0 on success, non zero on error
 482  */
 483 static int ishtp_enum_enum_devices(struct ishtp_cl *hid_ishtp_cl)
 484 {
 485         struct hostif_msg msg;
 486         struct ishtp_cl_data *client_data = ishtp_get_client_data(hid_ishtp_cl);
 487         int retry_count;
 488         int rv;
 489 
 490         /* Send HOSTIF_DM_ENUM_DEVICES */
 491         memset(&msg, 0, sizeof(struct hostif_msg));
 492         msg.hdr.command = HOSTIF_DM_ENUM_DEVICES;
 493         rv = ishtp_cl_send(hid_ishtp_cl, (unsigned char *)&msg,
 494                            sizeof(struct hostif_msg));
 495         if (rv)
 496                 return rv;
 497 
 498         retry_count = 0;
 499         while (!client_data->enum_devices_done &&
 500                retry_count < 10) {
 501                 wait_event_interruptible_timeout(client_data->init_wait,
 502                                          client_data->enum_devices_done,
 503                                          3 * HZ);
 504                 ++retry_count;
 505                 if (!client_data->enum_devices_done)
 506                         /* Send HOSTIF_DM_ENUM_DEVICES */
 507                         rv = ishtp_cl_send(hid_ishtp_cl,
 508                                            (unsigned char *) &msg,
 509                                            sizeof(struct hostif_msg));
 510         }
 511         if (!client_data->enum_devices_done) {
 512                 dev_err(cl_data_to_dev(client_data),
 513                         "[hid-ish]: timed out waiting for enum_devices\n");
 514                 return -ETIMEDOUT;
 515         }
 516         if (!client_data->hid_devices) {
 517                 dev_err(cl_data_to_dev(client_data),
 518                         "[hid-ish]: failed to allocate HID dev structures\n");
 519                 return -ENOMEM;
 520         }
 521 
 522         client_data->num_hid_devices = client_data->hid_dev_count;
 523         dev_info(ishtp_device(client_data->cl_device),
 524                 "[hid-ish]: enum_devices_done OK, num_hid_devices=%d\n",
 525                 client_data->num_hid_devices);
 526 
 527         return  0;
 528 }
 529 
 530 /**
 531  * ishtp_get_hid_descriptor() - Get hid descriptor
 532  * @hid_ishtp_cl:       client instance
 533  * @index:              Index into the hid_descr array
 534  *
 535  * Helper function to send request to firmware get HID descriptor of a device
 536  *
 537  * Return: 0 on success, non zero on error
 538  */
 539 static int ishtp_get_hid_descriptor(struct ishtp_cl *hid_ishtp_cl, int index)
 540 {
 541         struct hostif_msg msg;
 542         struct ishtp_cl_data *client_data = ishtp_get_client_data(hid_ishtp_cl);
 543         int rv;
 544 
 545         /* Get HID descriptor */
 546         client_data->hid_descr_done = false;
 547         memset(&msg, 0, sizeof(struct hostif_msg));
 548         msg.hdr.command = HOSTIF_GET_HID_DESCRIPTOR;
 549         msg.hdr.device_id = client_data->hid_devices[index].dev_id;
 550         rv = ishtp_cl_send(hid_ishtp_cl, (unsigned char *) &msg,
 551                            sizeof(struct hostif_msg));
 552         if (rv)
 553                 return rv;
 554 
 555         if (!client_data->hid_descr_done) {
 556                 wait_event_interruptible_timeout(client_data->init_wait,
 557                                                  client_data->hid_descr_done,
 558                                                  3 * HZ);
 559                 if (!client_data->hid_descr_done) {
 560                         dev_err(cl_data_to_dev(client_data),
 561                                 "[hid-ish]: timed out for hid_descr_done\n");
 562                         return -EIO;
 563                 }
 564 
 565                 if (!client_data->hid_descr[index]) {
 566                         dev_err(cl_data_to_dev(client_data),
 567                                 "[hid-ish]: allocation HID desc fail\n");
 568                         return -ENOMEM;
 569                 }
 570         }
 571 
 572         return 0;
 573 }
 574 
 575 /**
 576  * ishtp_get_report_descriptor() - Get report descriptor
 577  * @hid_ishtp_cl:       client instance
 578  * @index:              Index into the hid_descr array
 579  *
 580  * Helper function to send request to firmware get HID report descriptor of
 581  * a device
 582  *
 583  * Return: 0 on success, non zero on error
 584  */
 585 static int ishtp_get_report_descriptor(struct ishtp_cl *hid_ishtp_cl,
 586                                        int index)
 587 {
 588         struct hostif_msg msg;
 589         struct ishtp_cl_data *client_data = ishtp_get_client_data(hid_ishtp_cl);
 590         int rv;
 591 
 592         /* Get report descriptor */
 593         client_data->report_descr_done = false;
 594         memset(&msg, 0, sizeof(struct hostif_msg));
 595         msg.hdr.command = HOSTIF_GET_REPORT_DESCRIPTOR;
 596         msg.hdr.device_id = client_data->hid_devices[index].dev_id;
 597         rv = ishtp_cl_send(hid_ishtp_cl, (unsigned char *) &msg,
 598                            sizeof(struct hostif_msg));
 599         if (rv)
 600                 return rv;
 601 
 602         if (!client_data->report_descr_done)
 603                 wait_event_interruptible_timeout(client_data->init_wait,
 604                                          client_data->report_descr_done,
 605                                          3 * HZ);
 606         if (!client_data->report_descr_done) {
 607                 dev_err(cl_data_to_dev(client_data),
 608                                 "[hid-ish]: timed out for report descr\n");
 609                 return -EIO;
 610         }
 611         if (!client_data->report_descr[index]) {
 612                 dev_err(cl_data_to_dev(client_data),
 613                         "[hid-ish]: failed to alloc report descr\n");
 614                 return -ENOMEM;
 615         }
 616 
 617         return 0;
 618 }
 619 
 620 /**
 621  * hid_ishtp_cl_init() - Init function for ISHTP client
 622  * @hid_ishtp_cl:       ISHTP client instance
 623  * @reset:              true if called for init after reset
 624  *
 625  * This function complete the initializtion of the client. The summary of
 626  * processing:
 627  * - Send request to enumerate the hid clients
 628  *      Get the HID descriptor for each enumearated device
 629  *      Get report description of each device
 630  *      Register each device wik hid core by calling ishtp_hid_probe
 631  *
 632  * Return: 0 on success, non zero on error
 633  */
 634 static int hid_ishtp_cl_init(struct ishtp_cl *hid_ishtp_cl, int reset)
 635 {
 636         struct ishtp_device *dev;
 637         struct ishtp_cl_data *client_data = ishtp_get_client_data(hid_ishtp_cl);
 638         struct ishtp_fw_client *fw_client;
 639         int i;
 640         int rv;
 641 
 642         dev_dbg(cl_data_to_dev(client_data), "%s\n", __func__);
 643         hid_ishtp_trace(client_data,  "%s reset flag: %d\n", __func__, reset);
 644 
 645         rv = ishtp_cl_link(hid_ishtp_cl);
 646         if (rv) {
 647                 dev_err(cl_data_to_dev(client_data),
 648                         "ishtp_cl_link failed\n");
 649                 return  -ENOMEM;
 650         }
 651 
 652         client_data->init_done = 0;
 653 
 654         dev = ishtp_get_ishtp_device(hid_ishtp_cl);
 655 
 656         /* Connect to FW client */
 657         ishtp_set_tx_ring_size(hid_ishtp_cl, HID_CL_TX_RING_SIZE);
 658         ishtp_set_rx_ring_size(hid_ishtp_cl, HID_CL_RX_RING_SIZE);
 659 
 660         fw_client = ishtp_fw_cl_get_client(dev, &hid_ishtp_guid);
 661         if (!fw_client) {
 662                 dev_err(cl_data_to_dev(client_data),
 663                         "ish client uuid not found\n");
 664                 return -ENOENT;
 665         }
 666         ishtp_cl_set_fw_client_id(hid_ishtp_cl,
 667                                   ishtp_get_fw_client_id(fw_client));
 668         ishtp_set_connection_state(hid_ishtp_cl, ISHTP_CL_CONNECTING);
 669 
 670         rv = ishtp_cl_connect(hid_ishtp_cl);
 671         if (rv) {
 672                 dev_err(cl_data_to_dev(client_data),
 673                         "client connect fail\n");
 674                 goto err_cl_unlink;
 675         }
 676 
 677         hid_ishtp_trace(client_data,  "%s client connected\n", __func__);
 678 
 679         /* Register read callback */
 680         ishtp_register_event_cb(client_data->cl_device, ish_cl_event_cb);
 681 
 682         rv = ishtp_enum_enum_devices(hid_ishtp_cl);
 683         if (rv)
 684                 goto err_cl_disconnect;
 685 
 686         hid_ishtp_trace(client_data,  "%s enumerated device count %d\n",
 687                         __func__, client_data->num_hid_devices);
 688 
 689         for (i = 0; i < client_data->num_hid_devices; ++i) {
 690                 client_data->cur_hid_dev = i;
 691 
 692                 rv = ishtp_get_hid_descriptor(hid_ishtp_cl, i);
 693                 if (rv)
 694                         goto err_cl_disconnect;
 695 
 696                 rv = ishtp_get_report_descriptor(hid_ishtp_cl, i);
 697                 if (rv)
 698                         goto err_cl_disconnect;
 699 
 700                 if (!reset) {
 701                         rv = ishtp_hid_probe(i, client_data);
 702                         if (rv) {
 703                                 dev_err(cl_data_to_dev(client_data),
 704                                 "[hid-ish]: HID probe for #%u failed: %d\n",
 705                                 i, rv);
 706                                 goto err_cl_disconnect;
 707                         }
 708                 }
 709         } /* for() on all hid devices */
 710 
 711         client_data->init_done = 1;
 712         client_data->suspended = false;
 713         wake_up_interruptible(&client_data->ishtp_resume_wait);
 714         hid_ishtp_trace(client_data,  "%s successful init\n", __func__);
 715         return 0;
 716 
 717 err_cl_disconnect:
 718         ishtp_set_connection_state(hid_ishtp_cl, ISHTP_CL_DISCONNECTING);
 719         ishtp_cl_disconnect(hid_ishtp_cl);
 720 err_cl_unlink:
 721         ishtp_cl_unlink(hid_ishtp_cl);
 722         return rv;
 723 }
 724 
 725 /**
 726  * hid_ishtp_cl_deinit() - Deinit function for ISHTP client
 727  * @hid_ishtp_cl:       ISHTP client instance
 728  *
 729  * Unlink and free hid client
 730  */
 731 static void hid_ishtp_cl_deinit(struct ishtp_cl *hid_ishtp_cl)
 732 {
 733         ishtp_cl_unlink(hid_ishtp_cl);
 734         ishtp_cl_flush_queues(hid_ishtp_cl);
 735 
 736         /* disband and free all Tx and Rx client-level rings */
 737         ishtp_cl_free(hid_ishtp_cl);
 738 }
 739 
 740 static void hid_ishtp_cl_reset_handler(struct work_struct *work)
 741 {
 742         struct ishtp_cl_data *client_data;
 743         struct ishtp_cl *hid_ishtp_cl;
 744         struct ishtp_cl_device *cl_device;
 745         int retry;
 746         int rv;
 747 
 748         client_data = container_of(work, struct ishtp_cl_data, work);
 749 
 750         hid_ishtp_cl = client_data->hid_ishtp_cl;
 751         cl_device = client_data->cl_device;
 752 
 753         hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__,
 754                         hid_ishtp_cl);
 755         dev_dbg(ishtp_device(client_data->cl_device), "%s\n", __func__);
 756 
 757         hid_ishtp_cl_deinit(hid_ishtp_cl);
 758 
 759         hid_ishtp_cl = ishtp_cl_allocate(cl_device);
 760         if (!hid_ishtp_cl)
 761                 return;
 762 
 763         ishtp_set_drvdata(cl_device, hid_ishtp_cl);
 764         ishtp_set_client_data(hid_ishtp_cl, client_data);
 765         client_data->hid_ishtp_cl = hid_ishtp_cl;
 766 
 767         client_data->num_hid_devices = 0;
 768 
 769         for (retry = 0; retry < 3; ++retry) {
 770                 rv = hid_ishtp_cl_init(hid_ishtp_cl, 1);
 771                 if (!rv)
 772                         break;
 773                 dev_err(cl_data_to_dev(client_data), "Retry reset init\n");
 774         }
 775         if (rv) {
 776                 dev_err(cl_data_to_dev(client_data), "Reset Failed\n");
 777                 hid_ishtp_trace(client_data, "%s Failed hid_ishtp_cl %p\n",
 778                                 __func__, hid_ishtp_cl);
 779         }
 780 }
 781 
 782 void (*hid_print_trace)(void *unused, const char *format, ...);
 783 
 784 /**
 785  * hid_ishtp_cl_probe() - ISHTP client driver probe
 786  * @cl_device:          ISHTP client device instance
 787  *
 788  * This function gets called on device create on ISHTP bus
 789  *
 790  * Return: 0 on success, non zero on error
 791  */
 792 static int hid_ishtp_cl_probe(struct ishtp_cl_device *cl_device)
 793 {
 794         struct ishtp_cl *hid_ishtp_cl;
 795         struct ishtp_cl_data *client_data;
 796         int rv;
 797 
 798         if (!cl_device)
 799                 return  -ENODEV;
 800 
 801         client_data = devm_kzalloc(ishtp_device(cl_device),
 802                                    sizeof(*client_data),
 803                                    GFP_KERNEL);
 804         if (!client_data)
 805                 return -ENOMEM;
 806 
 807         hid_ishtp_cl = ishtp_cl_allocate(cl_device);
 808         if (!hid_ishtp_cl)
 809                 return -ENOMEM;
 810 
 811         ishtp_set_drvdata(cl_device, hid_ishtp_cl);
 812         ishtp_set_client_data(hid_ishtp_cl, client_data);
 813         client_data->hid_ishtp_cl = hid_ishtp_cl;
 814         client_data->cl_device = cl_device;
 815 
 816         init_waitqueue_head(&client_data->init_wait);
 817         init_waitqueue_head(&client_data->ishtp_resume_wait);
 818 
 819         INIT_WORK(&client_data->work, hid_ishtp_cl_reset_handler);
 820 
 821         hid_print_trace = ishtp_trace_callback(cl_device);
 822 
 823         rv = hid_ishtp_cl_init(hid_ishtp_cl, 0);
 824         if (rv) {
 825                 ishtp_cl_free(hid_ishtp_cl);
 826                 return rv;
 827         }
 828         ishtp_get_device(cl_device);
 829 
 830         return 0;
 831 }
 832 
 833 /**
 834  * hid_ishtp_cl_remove() - ISHTP client driver remove
 835  * @cl_device:          ISHTP client device instance
 836  *
 837  * This function gets called on device remove on ISHTP bus
 838  *
 839  * Return: 0
 840  */
 841 static int hid_ishtp_cl_remove(struct ishtp_cl_device *cl_device)
 842 {
 843         struct ishtp_cl *hid_ishtp_cl = ishtp_get_drvdata(cl_device);
 844         struct ishtp_cl_data *client_data = ishtp_get_client_data(hid_ishtp_cl);
 845 
 846         hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__,
 847                         hid_ishtp_cl);
 848 
 849         dev_dbg(ishtp_device(cl_device), "%s\n", __func__);
 850         ishtp_set_connection_state(hid_ishtp_cl, ISHTP_CL_DISCONNECTING);
 851         ishtp_cl_disconnect(hid_ishtp_cl);
 852         ishtp_put_device(cl_device);
 853         ishtp_hid_remove(client_data);
 854         hid_ishtp_cl_deinit(hid_ishtp_cl);
 855 
 856         hid_ishtp_cl = NULL;
 857 
 858         client_data->num_hid_devices = 0;
 859 
 860         return 0;
 861 }
 862 
 863 /**
 864  * hid_ishtp_cl_reset() - ISHTP client driver reset
 865  * @cl_device:          ISHTP client device instance
 866  *
 867  * This function gets called on device reset on ISHTP bus
 868  *
 869  * Return: 0
 870  */
 871 static int hid_ishtp_cl_reset(struct ishtp_cl_device *cl_device)
 872 {
 873         struct ishtp_cl *hid_ishtp_cl = ishtp_get_drvdata(cl_device);
 874         struct ishtp_cl_data *client_data = ishtp_get_client_data(hid_ishtp_cl);
 875 
 876         hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__,
 877                         hid_ishtp_cl);
 878 
 879         schedule_work(&client_data->work);
 880 
 881         return 0;
 882 }
 883 
 884 /**
 885  * hid_ishtp_cl_suspend() - ISHTP client driver suspend
 886  * @device:     device instance
 887  *
 888  * This function gets called on system suspend
 889  *
 890  * Return: 0
 891  */
 892 static int hid_ishtp_cl_suspend(struct device *device)
 893 {
 894         struct ishtp_cl_device *cl_device = ishtp_dev_to_cl_device(device);
 895         struct ishtp_cl *hid_ishtp_cl = ishtp_get_drvdata(cl_device);
 896         struct ishtp_cl_data *client_data = ishtp_get_client_data(hid_ishtp_cl);
 897 
 898         hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__,
 899                         hid_ishtp_cl);
 900         client_data->suspended = true;
 901 
 902         return 0;
 903 }
 904 
 905 /**
 906  * hid_ishtp_cl_resume() - ISHTP client driver resume
 907  * @device:     device instance
 908  *
 909  * This function gets called on system resume
 910  *
 911  * Return: 0
 912  */
 913 static int hid_ishtp_cl_resume(struct device *device)
 914 {
 915         struct ishtp_cl_device *cl_device = ishtp_dev_to_cl_device(device);
 916         struct ishtp_cl *hid_ishtp_cl = ishtp_get_drvdata(cl_device);
 917         struct ishtp_cl_data *client_data = ishtp_get_client_data(hid_ishtp_cl);
 918 
 919         hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__,
 920                         hid_ishtp_cl);
 921         client_data->suspended = false;
 922         return 0;
 923 }
 924 
 925 static const struct dev_pm_ops hid_ishtp_pm_ops = {
 926         .suspend = hid_ishtp_cl_suspend,
 927         .resume = hid_ishtp_cl_resume,
 928 };
 929 
 930 static struct ishtp_cl_driver   hid_ishtp_cl_driver = {
 931         .name = "ish-hid",
 932         .guid = &hid_ishtp_guid,
 933         .probe = hid_ishtp_cl_probe,
 934         .remove = hid_ishtp_cl_remove,
 935         .reset = hid_ishtp_cl_reset,
 936         .driver.pm = &hid_ishtp_pm_ops,
 937 };
 938 
 939 static int __init ish_hid_init(void)
 940 {
 941         int     rv;
 942 
 943         /* Register ISHTP client device driver with ISHTP Bus */
 944         rv = ishtp_cl_driver_register(&hid_ishtp_cl_driver, THIS_MODULE);
 945 
 946         return rv;
 947 
 948 }
 949 
 950 static void __exit ish_hid_exit(void)
 951 {
 952         ishtp_cl_driver_unregister(&hid_ishtp_cl_driver);
 953 }
 954 
 955 late_initcall(ish_hid_init);
 956 module_exit(ish_hid_exit);
 957 
 958 MODULE_DESCRIPTION("ISH ISHTP HID client driver");
 959 /* Primary author */
 960 MODULE_AUTHOR("Daniel Drubin <daniel.drubin@intel.com>");
 961 /*
 962  * Several modification for multi instance support
 963  * suspend/resume and clean up
 964  */
 965 MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
 966 
 967 MODULE_LICENSE("GPL");
 968 MODULE_ALIAS("ishtp:*");

/* [<][>][^][v][top][bottom][index][help] */