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

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

DEFINITIONS

This source file includes following definitions.
  1. ishtp_hid_parse
  2. ishtp_hid_start
  3. ishtp_hid_stop
  4. ishtp_hid_open
  5. ishtp_hid_close
  6. ishtp_raw_request
  7. ishtp_hid_request
  8. ishtp_wait_for_response
  9. ishtp_hid_wakeup
  10. ishtp_hid_probe
  11. ishtp_hid_remove

   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  */
  21 static 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 */
  36 static int ishtp_hid_start(struct hid_device *hid)
  37 {
  38         return 0;
  39 }
  40 
  41 static void ishtp_hid_stop(struct hid_device *hid)
  42 {
  43 }
  44 
  45 static int ishtp_hid_open(struct hid_device *hid)
  46 {
  47         return 0;
  48 }
  49 
  50 static void ishtp_hid_close(struct hid_device *hid)
  51 {
  52 }
  53 
  54 static 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  */
 104 static 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  */
 145 static 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  */
 178 void 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 
 186 static 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  */
 206 int 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                 rv = PTR_ERR(hid);
 216                 return  -ENOMEM;
 217         }
 218 
 219         hid_data = kzalloc(sizeof(*hid_data), GFP_KERNEL);
 220         if (!hid_data) {
 221                 rv = -ENOMEM;
 222                 goto err_hid_data;
 223         }
 224 
 225         hid_data->index = cur_hid_dev;
 226         hid_data->client_data = client_data;
 227         init_waitqueue_head(&hid_data->hid_wait);
 228 
 229         hid->driver_data = hid_data;
 230 
 231         client_data->hid_sensor_hubs[cur_hid_dev] = hid;
 232 
 233         hid->ll_driver = &ishtp_hid_ll_driver;
 234         hid->bus = BUS_INTEL_ISHTP;
 235         hid->dev.parent = ishtp_device(client_data->cl_device);
 236 
 237         hid->version = le16_to_cpu(ISH_HID_VERSION);
 238         hid->vendor = le16_to_cpu(client_data->hid_devices[cur_hid_dev].vid);
 239         hid->product = le16_to_cpu(client_data->hid_devices[cur_hid_dev].pid);
 240         snprintf(hid->name, sizeof(hid->name), "%s %04X:%04X", "hid-ishtp",
 241                 hid->vendor, hid->product);
 242 
 243         rv = hid_add_device(hid);
 244         if (rv)
 245                 goto err_hid_device;
 246 
 247         hid_ishtp_trace(client_data,  "%s allocated hid %p\n", __func__, hid);
 248 
 249         return 0;
 250 
 251 err_hid_device:
 252         kfree(hid_data);
 253 err_hid_data:
 254         hid_destroy_device(hid);
 255         return rv;
 256 }
 257 
 258 /**
 259  * ishtp_hid_probe() - Remove registered hid device
 260  * @client_data:        client data pointer
 261  *
 262  * This function is used to destroy allocatd HID device.
 263  */
 264 void ishtp_hid_remove(struct ishtp_cl_data *client_data)
 265 {
 266         int i;
 267 
 268         for (i = 0; i < client_data->num_hid_devices; ++i) {
 269                 if (client_data->hid_sensor_hubs[i]) {
 270                         kfree(client_data->hid_sensor_hubs[i]->driver_data);
 271                         hid_destroy_device(client_data->hid_sensor_hubs[i]);
 272                         client_data->hid_sensor_hubs[i] = NULL;
 273                 }
 274         }
 275 }

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