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