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