linux/drivers/hid/intel-ish-hid/ishtp-hid.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * ISHTP-HID glue driver.
   4 *
   5 * Copyright (c) 2012-2016, Intel Corporation.
   6 */
   7
   8#include <linux/hid.h>
   9#include <linux/intel-ish-client-if.h>
  10#include <uapi/linux/input.h>
  11#include "ishtp-hid.h"
  12
  13/**
  14 * ishtp_hid_parse() - hid-core .parse() callback
  15 * @hid:        hid device instance
  16 *
  17 * This function gets called during call to hid_add_device
  18 *
  19 * Return: 0 on success and non zero on error
  20 */
  21static int ishtp_hid_parse(struct hid_device *hid)
  22{
  23        struct ishtp_hid_data *hid_data =  hid->driver_data;
  24        struct ishtp_cl_data *client_data = hid_data->client_data;
  25        int rv;
  26
  27        rv = hid_parse_report(hid, client_data->report_descr[hid_data->index],
  28                              client_data->report_descr_size[hid_data->index]);
  29        if (rv)
  30                return  rv;
  31
  32        return 0;
  33}
  34
  35/* Empty callbacks with success return code */
  36static int ishtp_hid_start(struct hid_device *hid)
  37{
  38        return 0;
  39}
  40
  41static void ishtp_hid_stop(struct hid_device *hid)
  42{
  43}
  44
  45static int ishtp_hid_open(struct hid_device *hid)
  46{
  47        return 0;
  48}
  49
  50static void ishtp_hid_close(struct hid_device *hid)
  51{
  52}
  53
  54static int ishtp_raw_request(struct hid_device *hid, unsigned char reportnum,
  55                             __u8 *buf, size_t len, unsigned char rtype,
  56                             int reqtype)
  57{
  58        struct ishtp_hid_data *hid_data =  hid->driver_data;
  59        char *ishtp_buf = NULL;
  60        size_t ishtp_buf_len;
  61        unsigned int header_size = sizeof(struct hostif_msg);
  62
  63        if (rtype == HID_OUTPUT_REPORT)
  64                return -EINVAL;
  65
  66        hid_data->request_done = false;
  67        switch (reqtype) {
  68        case HID_REQ_GET_REPORT:
  69                hid_data->raw_buf = buf;
  70                hid_data->raw_buf_size = len;
  71                hid_data->raw_get_req = true;
  72
  73                hid_ishtp_get_report(hid, reportnum, rtype);
  74                break;
  75        case HID_REQ_SET_REPORT:
  76                /*
  77                 * Spare 7 bytes for 64b accesses through
  78                 * get/put_unaligned_le64()
  79                 */
  80                ishtp_buf_len = len + header_size;
  81                ishtp_buf = kzalloc(ishtp_buf_len + 7, GFP_KERNEL);
  82                if (!ishtp_buf)
  83                        return -ENOMEM;
  84
  85                memcpy(ishtp_buf + header_size, buf, len);
  86                hid_ishtp_set_feature(hid, ishtp_buf, ishtp_buf_len, reportnum);
  87                kfree(ishtp_buf);
  88                break;
  89        }
  90
  91        hid_hw_wait(hid);
  92
  93        return len;
  94}
  95
  96/**
  97 * ishtp_hid_request() - hid-core .request() callback
  98 * @hid:        hid device instance
  99 * @rep:        pointer to hid_report
 100 * @reqtype:    type of req. [GET|SET]_REPORT
 101 *
 102 * This function is used to set/get feaure/input report.
 103 */
 104static void ishtp_hid_request(struct hid_device *hid, struct hid_report *rep,
 105        int reqtype)
 106{
 107        struct ishtp_hid_data *hid_data =  hid->driver_data;
 108        /* the specific report length, just HID part of it */
 109        unsigned int len = ((rep->size - 1) >> 3) + 1 + (rep->id > 0);
 110        char *buf;
 111        unsigned int header_size = sizeof(struct hostif_msg);
 112
 113        len += header_size;
 114
 115        hid_data->request_done = false;
 116        switch (reqtype) {
 117        case HID_REQ_GET_REPORT:
 118                hid_data->raw_get_req = false;
 119                hid_ishtp_get_report(hid, rep->id, rep->type);
 120                break;
 121        case HID_REQ_SET_REPORT:
 122                /*
 123                 * Spare 7 bytes for 64b accesses through
 124                 * get/put_unaligned_le64()
 125                 */
 126                buf = kzalloc(len + 7, GFP_KERNEL);
 127                if (!buf)
 128                        return;
 129
 130                hid_output_report(rep, buf + header_size);
 131                hid_ishtp_set_feature(hid, buf, len, rep->id);
 132                kfree(buf);
 133                break;
 134        }
 135}
 136
 137/**
 138 * ishtp_wait_for_response() - hid-core .wait() callback
 139 * @hid:        hid device instance
 140 *
 141 * This function is used to wait after get feaure/input report.
 142 *
 143 * Return: 0 on success and non zero on error
 144 */
 145static int ishtp_wait_for_response(struct hid_device *hid)
 146{
 147        struct ishtp_hid_data *hid_data =  hid->driver_data;
 148        int rv;
 149
 150        hid_ishtp_trace(client_data,  "%s hid %p\n", __func__, hid);
 151
 152        rv = ishtp_hid_link_ready_wait(hid_data->client_data);
 153        if (rv)
 154                return rv;
 155
 156        if (!hid_data->request_done)
 157                wait_event_interruptible_timeout(hid_data->hid_wait,
 158                                        hid_data->request_done, 3 * HZ);
 159
 160        if (!hid_data->request_done) {
 161                hid_err(hid,
 162                        "timeout waiting for response from ISHTP device\n");
 163                return -ETIMEDOUT;
 164        }
 165        hid_ishtp_trace(client_data,  "%s hid %p done\n", __func__, hid);
 166
 167        hid_data->request_done = false;
 168
 169        return 0;
 170}
 171
 172/**
 173 * ishtp_hid_wakeup() - Wakeup caller
 174 * @hid:        hid device instance
 175 *
 176 * This function will wakeup caller waiting for Get/Set feature report
 177 */
 178void ishtp_hid_wakeup(struct hid_device *hid)
 179{
 180        struct ishtp_hid_data *hid_data = hid->driver_data;
 181
 182        hid_data->request_done = true;
 183        wake_up_interruptible(&hid_data->hid_wait);
 184}
 185
 186static struct hid_ll_driver ishtp_hid_ll_driver = {
 187        .parse = ishtp_hid_parse,
 188        .start = ishtp_hid_start,
 189        .stop = ishtp_hid_stop,
 190        .open = ishtp_hid_open,
 191        .close = ishtp_hid_close,
 192        .request = ishtp_hid_request,
 193        .wait = ishtp_wait_for_response,
 194        .raw_request = ishtp_raw_request
 195};
 196
 197/**
 198 * ishtp_hid_probe() - hid register ll driver
 199 * @cur_hid_dev:        Index of hid device calling to register
 200 * @client_data:        Client data pointer
 201 *
 202 * This function is used to allocate and add HID device.
 203 *
 204 * Return: 0 on success, non zero on error
 205 */
 206int ishtp_hid_probe(unsigned int cur_hid_dev,
 207                    struct ishtp_cl_data *client_data)
 208{
 209        int rv;
 210        struct hid_device *hid;
 211        struct ishtp_hid_data *hid_data;
 212
 213        hid = hid_allocate_device();
 214        if (IS_ERR(hid))
 215                return PTR_ERR(hid);
 216
 217        hid_data = kzalloc(sizeof(*hid_data), GFP_KERNEL);
 218        if (!hid_data) {
 219                rv = -ENOMEM;
 220                goto err_hid_data;
 221        }
 222
 223        hid_data->index = cur_hid_dev;
 224        hid_data->client_data = client_data;
 225        init_waitqueue_head(&hid_data->hid_wait);
 226
 227        hid->driver_data = hid_data;
 228
 229        client_data->hid_sensor_hubs[cur_hid_dev] = hid;
 230
 231        hid->ll_driver = &ishtp_hid_ll_driver;
 232        hid->bus = BUS_INTEL_ISHTP;
 233        hid->dev.parent = ishtp_device(client_data->cl_device);
 234
 235        hid->version = le16_to_cpu(ISH_HID_VERSION);
 236        hid->vendor = le16_to_cpu(client_data->hid_devices[cur_hid_dev].vid);
 237        hid->product = le16_to_cpu(client_data->hid_devices[cur_hid_dev].pid);
 238        snprintf(hid->name, sizeof(hid->name), "%s %04X:%04X", "hid-ishtp",
 239                hid->vendor, hid->product);
 240
 241        rv = hid_add_device(hid);
 242        if (rv)
 243                goto err_hid_device;
 244
 245        hid_ishtp_trace(client_data,  "%s allocated hid %p\n", __func__, hid);
 246
 247        return 0;
 248
 249err_hid_device:
 250        kfree(hid_data);
 251err_hid_data:
 252        hid_destroy_device(hid);
 253        return rv;
 254}
 255
 256/**
 257 * ishtp_hid_remove() - Remove registered hid device
 258 * @client_data:        client data pointer
 259 *
 260 * This function is used to destroy allocatd HID device.
 261 */
 262void ishtp_hid_remove(struct ishtp_cl_data *client_data)
 263{
 264        int i;
 265
 266        for (i = 0; i < client_data->num_hid_devices; ++i) {
 267                if (client_data->hid_sensor_hubs[i]) {
 268                        kfree(client_data->hid_sensor_hubs[i]->driver_data);
 269                        hid_destroy_device(client_data->hid_sensor_hubs[i]);
 270                        client_data->hid_sensor_hubs[i] = NULL;
 271                }
 272        }
 273}
 274