xref: /linux/drivers/hid/intel-ish-hid/ishtp-hid.c (revision 1578461a18596cf33093b392d1b7853ba4276154)
10b28cb4bSSrinivas Pandruvada /*
20b28cb4bSSrinivas Pandruvada  * ISHTP-HID glue driver.
30b28cb4bSSrinivas Pandruvada  *
40b28cb4bSSrinivas Pandruvada  * Copyright (c) 2012-2016, Intel Corporation.
50b28cb4bSSrinivas Pandruvada  *
60b28cb4bSSrinivas Pandruvada  * This program is free software; you can redistribute it and/or modify it
70b28cb4bSSrinivas Pandruvada  * under the terms and conditions of the GNU General Public License,
80b28cb4bSSrinivas Pandruvada  * version 2, as published by the Free Software Foundation.
90b28cb4bSSrinivas Pandruvada  *
100b28cb4bSSrinivas Pandruvada  * This program is distributed in the hope it will be useful, but WITHOUT
110b28cb4bSSrinivas Pandruvada  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
120b28cb4bSSrinivas Pandruvada  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
130b28cb4bSSrinivas Pandruvada  * more details.
140b28cb4bSSrinivas Pandruvada  */
150b28cb4bSSrinivas Pandruvada 
160b28cb4bSSrinivas Pandruvada #include <linux/hid.h>
170b28cb4bSSrinivas Pandruvada #include <uapi/linux/input.h>
180b28cb4bSSrinivas Pandruvada #include "ishtp/client.h"
190b28cb4bSSrinivas Pandruvada #include "ishtp-hid.h"
200b28cb4bSSrinivas Pandruvada 
210b28cb4bSSrinivas Pandruvada /**
220b28cb4bSSrinivas Pandruvada  * ishtp_hid_parse() - hid-core .parse() callback
230b28cb4bSSrinivas Pandruvada  * @hid:	hid device instance
240b28cb4bSSrinivas Pandruvada  *
250b28cb4bSSrinivas Pandruvada  * This function gets called during call to hid_add_device
260b28cb4bSSrinivas Pandruvada  *
270b28cb4bSSrinivas Pandruvada  * Return: 0 on success and non zero on error
280b28cb4bSSrinivas Pandruvada  */
290b28cb4bSSrinivas Pandruvada static int ishtp_hid_parse(struct hid_device *hid)
300b28cb4bSSrinivas Pandruvada {
310b28cb4bSSrinivas Pandruvada 	struct ishtp_hid_data *hid_data =  hid->driver_data;
320b28cb4bSSrinivas Pandruvada 	struct ishtp_cl_data *client_data = hid_data->client_data;
330b28cb4bSSrinivas Pandruvada 	int rv;
340b28cb4bSSrinivas Pandruvada 
350b28cb4bSSrinivas Pandruvada 	rv = hid_parse_report(hid, client_data->report_descr[hid_data->index],
360b28cb4bSSrinivas Pandruvada 			      client_data->report_descr_size[hid_data->index]);
370b28cb4bSSrinivas Pandruvada 	if (rv)
380b28cb4bSSrinivas Pandruvada 		return	rv;
390b28cb4bSSrinivas Pandruvada 
400b28cb4bSSrinivas Pandruvada 	return 0;
410b28cb4bSSrinivas Pandruvada }
420b28cb4bSSrinivas Pandruvada 
430b28cb4bSSrinivas Pandruvada /* Empty callbacks with success return code */
440b28cb4bSSrinivas Pandruvada static int ishtp_hid_start(struct hid_device *hid)
450b28cb4bSSrinivas Pandruvada {
460b28cb4bSSrinivas Pandruvada 	return 0;
470b28cb4bSSrinivas Pandruvada }
480b28cb4bSSrinivas Pandruvada 
490b28cb4bSSrinivas Pandruvada static void ishtp_hid_stop(struct hid_device *hid)
500b28cb4bSSrinivas Pandruvada {
510b28cb4bSSrinivas Pandruvada }
520b28cb4bSSrinivas Pandruvada 
530b28cb4bSSrinivas Pandruvada static int ishtp_hid_open(struct hid_device *hid)
540b28cb4bSSrinivas Pandruvada {
550b28cb4bSSrinivas Pandruvada 	return 0;
560b28cb4bSSrinivas Pandruvada }
570b28cb4bSSrinivas Pandruvada 
580b28cb4bSSrinivas Pandruvada static void ishtp_hid_close(struct hid_device *hid)
590b28cb4bSSrinivas Pandruvada {
600b28cb4bSSrinivas Pandruvada }
610b28cb4bSSrinivas Pandruvada 
620b28cb4bSSrinivas Pandruvada static int ishtp_raw_request(struct hid_device *hdev, unsigned char reportnum,
630b28cb4bSSrinivas Pandruvada 	__u8 *buf, size_t len, unsigned char rtype, int reqtype)
640b28cb4bSSrinivas Pandruvada {
650b28cb4bSSrinivas Pandruvada 	return 0;
660b28cb4bSSrinivas Pandruvada }
670b28cb4bSSrinivas Pandruvada 
680b28cb4bSSrinivas Pandruvada /**
690b28cb4bSSrinivas Pandruvada  * ishtp_hid_request() - hid-core .request() callback
700b28cb4bSSrinivas Pandruvada  * @hid:	hid device instance
710b28cb4bSSrinivas Pandruvada  * @rep:	pointer to hid_report
720b28cb4bSSrinivas Pandruvada  * @reqtype:	type of req. [GET|SET]_REPORT
730b28cb4bSSrinivas Pandruvada  *
740b28cb4bSSrinivas Pandruvada  * This function is used to set/get feaure/input report.
750b28cb4bSSrinivas Pandruvada  */
760b28cb4bSSrinivas Pandruvada static void ishtp_hid_request(struct hid_device *hid, struct hid_report *rep,
770b28cb4bSSrinivas Pandruvada 	int reqtype)
780b28cb4bSSrinivas Pandruvada {
790b28cb4bSSrinivas Pandruvada 	struct ishtp_hid_data *hid_data =  hid->driver_data;
800b28cb4bSSrinivas Pandruvada 	/* the specific report length, just HID part of it */
810b28cb4bSSrinivas Pandruvada 	unsigned int len = ((rep->size - 1) >> 3) + 1 + (rep->id > 0);
820b28cb4bSSrinivas Pandruvada 	char *buf;
830b28cb4bSSrinivas Pandruvada 	unsigned int header_size = sizeof(struct hostif_msg);
840b28cb4bSSrinivas Pandruvada 
850b28cb4bSSrinivas Pandruvada 	len += header_size;
860b28cb4bSSrinivas Pandruvada 
870b28cb4bSSrinivas Pandruvada 	hid_data->request_done = false;
880b28cb4bSSrinivas Pandruvada 	switch (reqtype) {
890b28cb4bSSrinivas Pandruvada 	case HID_REQ_GET_REPORT:
900b28cb4bSSrinivas Pandruvada 		hid_ishtp_get_report(hid, rep->id, rep->type);
910b28cb4bSSrinivas Pandruvada 		break;
920b28cb4bSSrinivas Pandruvada 	case HID_REQ_SET_REPORT:
930b28cb4bSSrinivas Pandruvada 		/*
940b28cb4bSSrinivas Pandruvada 		 * Spare 7 bytes for 64b accesses through
950b28cb4bSSrinivas Pandruvada 		 * get/put_unaligned_le64()
960b28cb4bSSrinivas Pandruvada 		 */
970b28cb4bSSrinivas Pandruvada 		buf = kzalloc(len + 7, GFP_KERNEL);
980b28cb4bSSrinivas Pandruvada 		if (!buf)
990b28cb4bSSrinivas Pandruvada 			return;
1000b28cb4bSSrinivas Pandruvada 
1010b28cb4bSSrinivas Pandruvada 		hid_output_report(rep, buf + header_size);
1020b28cb4bSSrinivas Pandruvada 		hid_ishtp_set_feature(hid, buf, len, rep->id);
1030b28cb4bSSrinivas Pandruvada 		kfree(buf);
1040b28cb4bSSrinivas Pandruvada 		break;
1050b28cb4bSSrinivas Pandruvada 	}
1060b28cb4bSSrinivas Pandruvada }
1070b28cb4bSSrinivas Pandruvada 
1080b28cb4bSSrinivas Pandruvada /**
1090b28cb4bSSrinivas Pandruvada  * ishtp_wait_for_response() - hid-core .wait() callback
1100b28cb4bSSrinivas Pandruvada  * @hid:	hid device instance
1110b28cb4bSSrinivas Pandruvada  *
1120b28cb4bSSrinivas Pandruvada  * This function is used to wait after get feaure/input report.
1130b28cb4bSSrinivas Pandruvada  *
1140b28cb4bSSrinivas Pandruvada  * Return: 0 on success and non zero on error
1150b28cb4bSSrinivas Pandruvada  */
1160b28cb4bSSrinivas Pandruvada static int ishtp_wait_for_response(struct hid_device *hid)
1170b28cb4bSSrinivas Pandruvada {
1180b28cb4bSSrinivas Pandruvada 	struct ishtp_hid_data *hid_data =  hid->driver_data;
1190b28cb4bSSrinivas Pandruvada 	struct ishtp_cl_data *client_data = hid_data->client_data;
1200b28cb4bSSrinivas Pandruvada 	int rv;
1210b28cb4bSSrinivas Pandruvada 
1220b28cb4bSSrinivas Pandruvada 	hid_ishtp_trace(client_data,  "%s hid %p\n", __func__, hid);
1230b28cb4bSSrinivas Pandruvada 
1240b28cb4bSSrinivas Pandruvada 	rv = ishtp_hid_link_ready_wait(hid_data->client_data);
1250b28cb4bSSrinivas Pandruvada 	if (rv)
1260b28cb4bSSrinivas Pandruvada 		return rv;
1270b28cb4bSSrinivas Pandruvada 
1280b28cb4bSSrinivas Pandruvada 	if (!hid_data->request_done)
1290b28cb4bSSrinivas Pandruvada 		wait_event_interruptible_timeout(hid_data->hid_wait,
1300b28cb4bSSrinivas Pandruvada 					hid_data->request_done, 3 * HZ);
1310b28cb4bSSrinivas Pandruvada 
1320b28cb4bSSrinivas Pandruvada 	if (!hid_data->request_done) {
1330b28cb4bSSrinivas Pandruvada 		hid_err(hid,
1340b28cb4bSSrinivas Pandruvada 			"timeout waiting for response from ISHTP device\n");
1350b28cb4bSSrinivas Pandruvada 		return -ETIMEDOUT;
1360b28cb4bSSrinivas Pandruvada 	}
1370b28cb4bSSrinivas Pandruvada 	hid_ishtp_trace(client_data,  "%s hid %p done\n", __func__, hid);
1380b28cb4bSSrinivas Pandruvada 
1390b28cb4bSSrinivas Pandruvada 	hid_data->request_done = false;
1400b28cb4bSSrinivas Pandruvada 
1410b28cb4bSSrinivas Pandruvada 	return 0;
1420b28cb4bSSrinivas Pandruvada }
1430b28cb4bSSrinivas Pandruvada 
1440b28cb4bSSrinivas Pandruvada /**
1450b28cb4bSSrinivas Pandruvada  * ishtp_hid_wakeup() - Wakeup caller
1460b28cb4bSSrinivas Pandruvada  * @hid:	hid device instance
1470b28cb4bSSrinivas Pandruvada  *
1480b28cb4bSSrinivas Pandruvada  * This function will wakeup caller waiting for Get/Set feature report
1490b28cb4bSSrinivas Pandruvada  */
1500b28cb4bSSrinivas Pandruvada void ishtp_hid_wakeup(struct hid_device *hid)
1510b28cb4bSSrinivas Pandruvada {
1520b28cb4bSSrinivas Pandruvada 	struct ishtp_hid_data *hid_data = hid->driver_data;
1530b28cb4bSSrinivas Pandruvada 
1540b28cb4bSSrinivas Pandruvada 	hid_data->request_done = true;
1550b28cb4bSSrinivas Pandruvada 	wake_up_interruptible(&hid_data->hid_wait);
1560b28cb4bSSrinivas Pandruvada }
1570b28cb4bSSrinivas Pandruvada 
1580b28cb4bSSrinivas Pandruvada static struct hid_ll_driver ishtp_hid_ll_driver = {
1590b28cb4bSSrinivas Pandruvada 	.parse = ishtp_hid_parse,
1600b28cb4bSSrinivas Pandruvada 	.start = ishtp_hid_start,
1610b28cb4bSSrinivas Pandruvada 	.stop = ishtp_hid_stop,
1620b28cb4bSSrinivas Pandruvada 	.open = ishtp_hid_open,
1630b28cb4bSSrinivas Pandruvada 	.close = ishtp_hid_close,
1640b28cb4bSSrinivas Pandruvada 	.request = ishtp_hid_request,
1650b28cb4bSSrinivas Pandruvada 	.wait = ishtp_wait_for_response,
1660b28cb4bSSrinivas Pandruvada 	.raw_request = ishtp_raw_request
1670b28cb4bSSrinivas Pandruvada };
1680b28cb4bSSrinivas Pandruvada 
1690b28cb4bSSrinivas Pandruvada /**
1700b28cb4bSSrinivas Pandruvada  * ishtp_hid_probe() - hid register ll driver
1710b28cb4bSSrinivas Pandruvada  * @cur_hid_dev:	Index of hid device calling to register
1720b28cb4bSSrinivas Pandruvada  * @client_data:	Client data pointer
1730b28cb4bSSrinivas Pandruvada  *
1740b28cb4bSSrinivas Pandruvada  * This function is used to allocate and add HID device.
1750b28cb4bSSrinivas Pandruvada  *
1760b28cb4bSSrinivas Pandruvada  * Return: 0 on success, non zero on error
1770b28cb4bSSrinivas Pandruvada  */
1780b28cb4bSSrinivas Pandruvada int ishtp_hid_probe(unsigned int cur_hid_dev,
1790b28cb4bSSrinivas Pandruvada 		    struct ishtp_cl_data *client_data)
1800b28cb4bSSrinivas Pandruvada {
1810b28cb4bSSrinivas Pandruvada 	int rv;
1820b28cb4bSSrinivas Pandruvada 	struct hid_device *hid;
1830b28cb4bSSrinivas Pandruvada 	struct ishtp_hid_data *hid_data;
1840b28cb4bSSrinivas Pandruvada 
1850b28cb4bSSrinivas Pandruvada 	hid = hid_allocate_device();
1860b28cb4bSSrinivas Pandruvada 	if (IS_ERR(hid)) {
1870b28cb4bSSrinivas Pandruvada 		rv = PTR_ERR(hid);
1880b28cb4bSSrinivas Pandruvada 		return	-ENOMEM;
1890b28cb4bSSrinivas Pandruvada 	}
1900b28cb4bSSrinivas Pandruvada 
1910b28cb4bSSrinivas Pandruvada 	hid_data = kzalloc(sizeof(*hid_data), GFP_KERNEL);
1920b28cb4bSSrinivas Pandruvada 	if (!hid_data) {
1930b28cb4bSSrinivas Pandruvada 		rv = -ENOMEM;
1940b28cb4bSSrinivas Pandruvada 		goto err_hid_data;
1950b28cb4bSSrinivas Pandruvada 	}
1960b28cb4bSSrinivas Pandruvada 
1970b28cb4bSSrinivas Pandruvada 	hid_data->index = cur_hid_dev;
1980b28cb4bSSrinivas Pandruvada 	hid_data->client_data = client_data;
1990b28cb4bSSrinivas Pandruvada 	init_waitqueue_head(&hid_data->hid_wait);
2000b28cb4bSSrinivas Pandruvada 
2010b28cb4bSSrinivas Pandruvada 	hid->driver_data = hid_data;
2020b28cb4bSSrinivas Pandruvada 
2030b28cb4bSSrinivas Pandruvada 	client_data->hid_sensor_hubs[cur_hid_dev] = hid;
2040b28cb4bSSrinivas Pandruvada 
2050b28cb4bSSrinivas Pandruvada 	hid->ll_driver = &ishtp_hid_ll_driver;
2060b28cb4bSSrinivas Pandruvada 	hid->bus = BUS_INTEL_ISHTP;
2070b28cb4bSSrinivas Pandruvada 	hid->dev.parent = &client_data->cl_device->dev;
2080b28cb4bSSrinivas Pandruvada 	hid->version = le16_to_cpu(ISH_HID_VERSION);
209*1578461aSSrinivas Pandruvada 	hid->vendor = le16_to_cpu(client_data->hid_devices[cur_hid_dev].vid);
210*1578461aSSrinivas Pandruvada 	hid->product = le16_to_cpu(client_data->hid_devices[cur_hid_dev].pid);
2115299a92aSNicolas Iooss 	snprintf(hid->name, sizeof(hid->name), "%s %04X:%04X", "hid-ishtp",
2120b28cb4bSSrinivas Pandruvada 		hid->vendor, hid->product);
2130b28cb4bSSrinivas Pandruvada 
2140b28cb4bSSrinivas Pandruvada 	rv = hid_add_device(hid);
2150b28cb4bSSrinivas Pandruvada 	if (rv)
2160b28cb4bSSrinivas Pandruvada 		goto err_hid_device;
2170b28cb4bSSrinivas Pandruvada 
2180b28cb4bSSrinivas Pandruvada 	hid_ishtp_trace(client_data,  "%s allocated hid %p\n", __func__, hid);
2190b28cb4bSSrinivas Pandruvada 
2200b28cb4bSSrinivas Pandruvada 	return 0;
2210b28cb4bSSrinivas Pandruvada 
2220b28cb4bSSrinivas Pandruvada err_hid_device:
2230b28cb4bSSrinivas Pandruvada 	kfree(hid_data);
2240b28cb4bSSrinivas Pandruvada err_hid_data:
2256e0856d3SPan Bian 	hid_destroy_device(hid);
2260b28cb4bSSrinivas Pandruvada 	return rv;
2270b28cb4bSSrinivas Pandruvada }
2280b28cb4bSSrinivas Pandruvada 
2290b28cb4bSSrinivas Pandruvada /**
2300b28cb4bSSrinivas Pandruvada  * ishtp_hid_probe() - Remove registered hid device
2310b28cb4bSSrinivas Pandruvada  * @client_data:	client data pointer
2320b28cb4bSSrinivas Pandruvada  *
2330b28cb4bSSrinivas Pandruvada  * This function is used to destroy allocatd HID device.
2340b28cb4bSSrinivas Pandruvada  */
2350b28cb4bSSrinivas Pandruvada void ishtp_hid_remove(struct ishtp_cl_data *client_data)
2360b28cb4bSSrinivas Pandruvada {
2370b28cb4bSSrinivas Pandruvada 	int i;
2380b28cb4bSSrinivas Pandruvada 
2390b28cb4bSSrinivas Pandruvada 	for (i = 0; i < client_data->num_hid_devices; ++i) {
2400b28cb4bSSrinivas Pandruvada 		if (client_data->hid_sensor_hubs[i]) {
2410b28cb4bSSrinivas Pandruvada 			kfree(client_data->hid_sensor_hubs[i]->driver_data);
2420b28cb4bSSrinivas Pandruvada 			hid_destroy_device(client_data->hid_sensor_hubs[i]);
2430b28cb4bSSrinivas Pandruvada 			client_data->hid_sensor_hubs[i] = NULL;
2440b28cb4bSSrinivas Pandruvada 		}
2450b28cb4bSSrinivas Pandruvada 	}
2460b28cb4bSSrinivas Pandruvada }
247