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