cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ishtp-hid.c (6523B)


      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}