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