1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * HID class driver for the Greybus. |
4 | * |
5 | * Copyright 2014 Google Inc. |
6 | * Copyright 2014 Linaro Ltd. |
7 | */ |
8 | |
9 | #include <linux/bitops.h> |
10 | #include <linux/hid.h> |
11 | #include <linux/kernel.h> |
12 | #include <linux/module.h> |
13 | #include <linux/mutex.h> |
14 | #include <linux/slab.h> |
15 | #include <linux/greybus.h> |
16 | |
17 | /* Greybus HID device's structure */ |
18 | struct gb_hid { |
19 | struct gb_bundle *bundle; |
20 | struct gb_connection *connection; |
21 | |
22 | struct hid_device *hid; |
23 | struct gb_hid_desc_response hdesc; |
24 | |
25 | unsigned long flags; |
26 | #define GB_HID_STARTED 0x01 |
27 | #define GB_HID_READ_PENDING 0x04 |
28 | |
29 | unsigned int bufsize; |
30 | char *inbuf; |
31 | }; |
32 | |
33 | /* Routines to get controller's information over greybus */ |
34 | |
35 | /* Operations performed on greybus */ |
36 | static int gb_hid_get_desc(struct gb_hid *ghid) |
37 | { |
38 | return gb_operation_sync(connection: ghid->connection, GB_HID_TYPE_GET_DESC, NULL, |
39 | request_size: 0, response: &ghid->hdesc, response_size: sizeof(ghid->hdesc)); |
40 | } |
41 | |
42 | static int gb_hid_get_report_desc(struct gb_hid *ghid, char *rdesc) |
43 | { |
44 | int ret; |
45 | |
46 | ret = gb_pm_runtime_get_sync(bundle: ghid->bundle); |
47 | if (ret) |
48 | return ret; |
49 | |
50 | ret = gb_operation_sync(connection: ghid->connection, GB_HID_TYPE_GET_REPORT_DESC, |
51 | NULL, request_size: 0, response: rdesc, |
52 | le16_to_cpu(ghid->hdesc.wReportDescLength)); |
53 | |
54 | gb_pm_runtime_put_autosuspend(bundle: ghid->bundle); |
55 | |
56 | return ret; |
57 | } |
58 | |
59 | static int gb_hid_set_power(struct gb_hid *ghid, int type) |
60 | { |
61 | int ret; |
62 | |
63 | ret = gb_pm_runtime_get_sync(bundle: ghid->bundle); |
64 | if (ret) |
65 | return ret; |
66 | |
67 | ret = gb_operation_sync(connection: ghid->connection, type, NULL, request_size: 0, NULL, response_size: 0); |
68 | |
69 | gb_pm_runtime_put_autosuspend(bundle: ghid->bundle); |
70 | |
71 | return ret; |
72 | } |
73 | |
74 | static int gb_hid_get_report(struct gb_hid *ghid, u8 report_type, u8 report_id, |
75 | unsigned char *buf, int len) |
76 | { |
77 | struct gb_hid_get_report_request request; |
78 | int ret; |
79 | |
80 | ret = gb_pm_runtime_get_sync(bundle: ghid->bundle); |
81 | if (ret) |
82 | return ret; |
83 | |
84 | request.report_type = report_type; |
85 | request.report_id = report_id; |
86 | |
87 | ret = gb_operation_sync(connection: ghid->connection, GB_HID_TYPE_GET_REPORT, |
88 | request: &request, request_size: sizeof(request), response: buf, response_size: len); |
89 | |
90 | gb_pm_runtime_put_autosuspend(bundle: ghid->bundle); |
91 | |
92 | return ret; |
93 | } |
94 | |
95 | static int gb_hid_set_report(struct gb_hid *ghid, u8 report_type, u8 report_id, |
96 | unsigned char *buf, int len) |
97 | { |
98 | struct gb_hid_set_report_request *request; |
99 | struct gb_operation *operation; |
100 | int ret, size = sizeof(*request) + len - 1; |
101 | |
102 | ret = gb_pm_runtime_get_sync(bundle: ghid->bundle); |
103 | if (ret) |
104 | return ret; |
105 | |
106 | operation = gb_operation_create(connection: ghid->connection, |
107 | GB_HID_TYPE_SET_REPORT, request_size: size, response_size: 0, |
108 | GFP_KERNEL); |
109 | if (!operation) { |
110 | gb_pm_runtime_put_autosuspend(bundle: ghid->bundle); |
111 | return -ENOMEM; |
112 | } |
113 | |
114 | request = operation->request->payload; |
115 | request->report_type = report_type; |
116 | request->report_id = report_id; |
117 | memcpy(request->report, buf, len); |
118 | |
119 | ret = gb_operation_request_send_sync(operation); |
120 | if (ret) { |
121 | dev_err(&operation->connection->bundle->dev, |
122 | "failed to set report: %d\n" , ret); |
123 | } else { |
124 | ret = len; |
125 | } |
126 | |
127 | gb_operation_put(operation); |
128 | gb_pm_runtime_put_autosuspend(bundle: ghid->bundle); |
129 | |
130 | return ret; |
131 | } |
132 | |
133 | static int gb_hid_request_handler(struct gb_operation *op) |
134 | { |
135 | struct gb_connection *connection = op->connection; |
136 | struct gb_hid *ghid = gb_connection_get_data(connection); |
137 | struct gb_hid_input_report_request *request = op->request->payload; |
138 | |
139 | if (op->type != GB_HID_TYPE_IRQ_EVENT) { |
140 | dev_err(&connection->bundle->dev, |
141 | "unsupported unsolicited request\n" ); |
142 | return -EINVAL; |
143 | } |
144 | |
145 | if (test_bit(GB_HID_STARTED, &ghid->flags)) |
146 | hid_input_report(hid: ghid->hid, type: HID_INPUT_REPORT, |
147 | data: request->report, size: op->request->payload_size, interrupt: 1); |
148 | |
149 | return 0; |
150 | } |
151 | |
152 | static int gb_hid_report_len(struct hid_report *report) |
153 | { |
154 | return ((report->size - 1) >> 3) + 1 + |
155 | report->device->report_enum[report->type].numbered; |
156 | } |
157 | |
158 | static void gb_hid_find_max_report(struct hid_device *hid, unsigned int type, |
159 | unsigned int *max) |
160 | { |
161 | struct hid_report *report; |
162 | unsigned int size; |
163 | |
164 | list_for_each_entry(report, &hid->report_enum[type].report_list, list) { |
165 | size = gb_hid_report_len(report); |
166 | if (*max < size) |
167 | *max = size; |
168 | } |
169 | } |
170 | |
171 | static void gb_hid_free_buffers(struct gb_hid *ghid) |
172 | { |
173 | kfree(objp: ghid->inbuf); |
174 | ghid->inbuf = NULL; |
175 | ghid->bufsize = 0; |
176 | } |
177 | |
178 | static int gb_hid_alloc_buffers(struct gb_hid *ghid, size_t bufsize) |
179 | { |
180 | ghid->inbuf = kzalloc(size: bufsize, GFP_KERNEL); |
181 | if (!ghid->inbuf) |
182 | return -ENOMEM; |
183 | |
184 | ghid->bufsize = bufsize; |
185 | |
186 | return 0; |
187 | } |
188 | |
189 | /* Routines dealing with reports */ |
190 | static void gb_hid_init_report(struct gb_hid *ghid, struct hid_report *report) |
191 | { |
192 | unsigned int size; |
193 | |
194 | size = gb_hid_report_len(report); |
195 | if (gb_hid_get_report(ghid, report_type: report->type, report_id: report->id, buf: ghid->inbuf, |
196 | len: size)) |
197 | return; |
198 | |
199 | /* |
200 | * hid->driver_lock is held as we are in probe function, |
201 | * we just need to setup the input fields, so using |
202 | * hid_report_raw_event is safe. |
203 | */ |
204 | hid_report_raw_event(hid: ghid->hid, type: report->type, data: ghid->inbuf, size, interrupt: 1); |
205 | } |
206 | |
207 | static void gb_hid_init_reports(struct gb_hid *ghid) |
208 | { |
209 | struct hid_device *hid = ghid->hid; |
210 | struct hid_report *report; |
211 | |
212 | list_for_each_entry(report, |
213 | &hid->report_enum[HID_INPUT_REPORT].report_list, |
214 | list) |
215 | gb_hid_init_report(ghid, report); |
216 | |
217 | list_for_each_entry(report, |
218 | &hid->report_enum[HID_FEATURE_REPORT].report_list, |
219 | list) |
220 | gb_hid_init_report(ghid, report); |
221 | } |
222 | |
223 | static int __gb_hid_get_raw_report(struct hid_device *hid, |
224 | unsigned char report_number, __u8 *buf, size_t count, |
225 | unsigned char report_type) |
226 | { |
227 | struct gb_hid *ghid = hid->driver_data; |
228 | int ret; |
229 | |
230 | if (report_type == HID_OUTPUT_REPORT) |
231 | return -EINVAL; |
232 | |
233 | ret = gb_hid_get_report(ghid, report_type, report_id: report_number, buf, len: count); |
234 | if (!ret) |
235 | ret = count; |
236 | |
237 | return ret; |
238 | } |
239 | |
240 | static int __gb_hid_output_raw_report(struct hid_device *hid, __u8 *buf, |
241 | size_t len, unsigned char report_type) |
242 | { |
243 | struct gb_hid *ghid = hid->driver_data; |
244 | int report_id = buf[0]; |
245 | int ret; |
246 | |
247 | if (report_type == HID_INPUT_REPORT) |
248 | return -EINVAL; |
249 | |
250 | if (report_id) { |
251 | buf++; |
252 | len--; |
253 | } |
254 | |
255 | ret = gb_hid_set_report(ghid, report_type, report_id, buf, len); |
256 | if (report_id && ret >= 0) |
257 | ret++; /* add report_id to the number of transferred bytes */ |
258 | |
259 | return 0; |
260 | } |
261 | |
262 | static int gb_hid_raw_request(struct hid_device *hid, unsigned char reportnum, |
263 | __u8 *buf, size_t len, unsigned char rtype, |
264 | int reqtype) |
265 | { |
266 | switch (reqtype) { |
267 | case HID_REQ_GET_REPORT: |
268 | return __gb_hid_get_raw_report(hid, report_number: reportnum, buf, count: len, report_type: rtype); |
269 | case HID_REQ_SET_REPORT: |
270 | if (buf[0] != reportnum) |
271 | return -EINVAL; |
272 | return __gb_hid_output_raw_report(hid, buf, len, report_type: rtype); |
273 | default: |
274 | return -EIO; |
275 | } |
276 | } |
277 | |
278 | /* HID Callbacks */ |
279 | static int gb_hid_parse(struct hid_device *hid) |
280 | { |
281 | struct gb_hid *ghid = hid->driver_data; |
282 | unsigned int rsize; |
283 | char *rdesc; |
284 | int ret; |
285 | |
286 | rsize = le16_to_cpu(ghid->hdesc.wReportDescLength); |
287 | if (!rsize || rsize > HID_MAX_DESCRIPTOR_SIZE) { |
288 | dbg_hid("weird size of report descriptor (%u)\n" , rsize); |
289 | return -EINVAL; |
290 | } |
291 | |
292 | rdesc = kzalloc(size: rsize, GFP_KERNEL); |
293 | if (!rdesc) |
294 | return -ENOMEM; |
295 | |
296 | ret = gb_hid_get_report_desc(ghid, rdesc); |
297 | if (ret) { |
298 | hid_err(hid, "reading report descriptor failed\n" ); |
299 | goto free_rdesc; |
300 | } |
301 | |
302 | ret = hid_parse_report(hid, start: rdesc, size: rsize); |
303 | if (ret) |
304 | dbg_hid("parsing report descriptor failed\n" ); |
305 | |
306 | free_rdesc: |
307 | kfree(objp: rdesc); |
308 | |
309 | return ret; |
310 | } |
311 | |
312 | static int gb_hid_start(struct hid_device *hid) |
313 | { |
314 | struct gb_hid *ghid = hid->driver_data; |
315 | unsigned int bufsize = HID_MIN_BUFFER_SIZE; |
316 | int ret; |
317 | |
318 | gb_hid_find_max_report(hid, type: HID_INPUT_REPORT, max: &bufsize); |
319 | gb_hid_find_max_report(hid, type: HID_OUTPUT_REPORT, max: &bufsize); |
320 | gb_hid_find_max_report(hid, type: HID_FEATURE_REPORT, max: &bufsize); |
321 | |
322 | if (bufsize > HID_MAX_BUFFER_SIZE) |
323 | bufsize = HID_MAX_BUFFER_SIZE; |
324 | |
325 | ret = gb_hid_alloc_buffers(ghid, bufsize); |
326 | if (ret) |
327 | return ret; |
328 | |
329 | if (!(hid->quirks & HID_QUIRK_NO_INIT_REPORTS)) |
330 | gb_hid_init_reports(ghid); |
331 | |
332 | return 0; |
333 | } |
334 | |
335 | static void gb_hid_stop(struct hid_device *hid) |
336 | { |
337 | struct gb_hid *ghid = hid->driver_data; |
338 | |
339 | gb_hid_free_buffers(ghid); |
340 | } |
341 | |
342 | static int gb_hid_open(struct hid_device *hid) |
343 | { |
344 | struct gb_hid *ghid = hid->driver_data; |
345 | int ret; |
346 | |
347 | ret = gb_hid_set_power(ghid, GB_HID_TYPE_PWR_ON); |
348 | if (ret < 0) |
349 | return ret; |
350 | |
351 | set_bit(GB_HID_STARTED, addr: &ghid->flags); |
352 | return 0; |
353 | } |
354 | |
355 | static void gb_hid_close(struct hid_device *hid) |
356 | { |
357 | struct gb_hid *ghid = hid->driver_data; |
358 | int ret; |
359 | |
360 | clear_bit(GB_HID_STARTED, addr: &ghid->flags); |
361 | |
362 | /* Save some power */ |
363 | ret = gb_hid_set_power(ghid, GB_HID_TYPE_PWR_OFF); |
364 | if (ret) |
365 | dev_err(&ghid->connection->bundle->dev, |
366 | "failed to power off (%d)\n" , ret); |
367 | } |
368 | |
369 | static int gb_hid_power(struct hid_device *hid, int lvl) |
370 | { |
371 | struct gb_hid *ghid = hid->driver_data; |
372 | |
373 | switch (lvl) { |
374 | case PM_HINT_FULLON: |
375 | return gb_hid_set_power(ghid, GB_HID_TYPE_PWR_ON); |
376 | case PM_HINT_NORMAL: |
377 | return gb_hid_set_power(ghid, GB_HID_TYPE_PWR_OFF); |
378 | } |
379 | |
380 | return 0; |
381 | } |
382 | |
383 | /* HID structure to pass callbacks */ |
384 | static const struct hid_ll_driver gb_hid_ll_driver = { |
385 | .parse = gb_hid_parse, |
386 | .start = gb_hid_start, |
387 | .stop = gb_hid_stop, |
388 | .open = gb_hid_open, |
389 | .close = gb_hid_close, |
390 | .power = gb_hid_power, |
391 | .raw_request = gb_hid_raw_request, |
392 | }; |
393 | |
394 | static int gb_hid_init(struct gb_hid *ghid) |
395 | { |
396 | struct hid_device *hid = ghid->hid; |
397 | int ret; |
398 | |
399 | ret = gb_hid_get_desc(ghid); |
400 | if (ret) |
401 | return ret; |
402 | |
403 | hid->version = le16_to_cpu(ghid->hdesc.bcdHID); |
404 | hid->vendor = le16_to_cpu(ghid->hdesc.wVendorID); |
405 | hid->product = le16_to_cpu(ghid->hdesc.wProductID); |
406 | hid->country = ghid->hdesc.bCountryCode; |
407 | |
408 | hid->driver_data = ghid; |
409 | hid->ll_driver = &gb_hid_ll_driver; |
410 | hid->dev.parent = &ghid->connection->bundle->dev; |
411 | // hid->bus = BUS_GREYBUS; /* Need a bustype for GREYBUS in <linux/input.h> */ |
412 | |
413 | /* Set HID device's name */ |
414 | snprintf(buf: hid->name, size: sizeof(hid->name), fmt: "%s %04X:%04X" , |
415 | dev_name(dev: &ghid->connection->bundle->dev), |
416 | hid->vendor, hid->product); |
417 | |
418 | return 0; |
419 | } |
420 | |
421 | static int gb_hid_probe(struct gb_bundle *bundle, |
422 | const struct greybus_bundle_id *id) |
423 | { |
424 | struct greybus_descriptor_cport *cport_desc; |
425 | struct gb_connection *connection; |
426 | struct hid_device *hid; |
427 | struct gb_hid *ghid; |
428 | int ret; |
429 | |
430 | if (bundle->num_cports != 1) |
431 | return -ENODEV; |
432 | |
433 | cport_desc = &bundle->cport_desc[0]; |
434 | if (cport_desc->protocol_id != GREYBUS_PROTOCOL_HID) |
435 | return -ENODEV; |
436 | |
437 | ghid = kzalloc(size: sizeof(*ghid), GFP_KERNEL); |
438 | if (!ghid) |
439 | return -ENOMEM; |
440 | |
441 | connection = gb_connection_create(bundle, le16_to_cpu(cport_desc->id), |
442 | handler: gb_hid_request_handler); |
443 | if (IS_ERR(ptr: connection)) { |
444 | ret = PTR_ERR(ptr: connection); |
445 | goto err_free_ghid; |
446 | } |
447 | |
448 | gb_connection_set_data(connection, data: ghid); |
449 | ghid->connection = connection; |
450 | |
451 | hid = hid_allocate_device(); |
452 | if (IS_ERR(ptr: hid)) { |
453 | ret = PTR_ERR(ptr: hid); |
454 | goto err_connection_destroy; |
455 | } |
456 | |
457 | ghid->hid = hid; |
458 | ghid->bundle = bundle; |
459 | |
460 | greybus_set_drvdata(bundle, data: ghid); |
461 | |
462 | ret = gb_connection_enable(connection); |
463 | if (ret) |
464 | goto err_destroy_hid; |
465 | |
466 | ret = gb_hid_init(ghid); |
467 | if (ret) |
468 | goto err_connection_disable; |
469 | |
470 | ret = hid_add_device(hid); |
471 | if (ret) { |
472 | hid_err(hid, "can't add hid device: %d\n" , ret); |
473 | goto err_connection_disable; |
474 | } |
475 | |
476 | gb_pm_runtime_put_autosuspend(bundle); |
477 | |
478 | return 0; |
479 | |
480 | err_connection_disable: |
481 | gb_connection_disable(connection); |
482 | err_destroy_hid: |
483 | hid_destroy_device(hid); |
484 | err_connection_destroy: |
485 | gb_connection_destroy(connection); |
486 | err_free_ghid: |
487 | kfree(objp: ghid); |
488 | |
489 | return ret; |
490 | } |
491 | |
492 | static void gb_hid_disconnect(struct gb_bundle *bundle) |
493 | { |
494 | struct gb_hid *ghid = greybus_get_drvdata(bundle); |
495 | |
496 | if (gb_pm_runtime_get_sync(bundle)) |
497 | gb_pm_runtime_get_noresume(bundle); |
498 | |
499 | hid_destroy_device(ghid->hid); |
500 | gb_connection_disable(connection: ghid->connection); |
501 | gb_connection_destroy(connection: ghid->connection); |
502 | kfree(objp: ghid); |
503 | } |
504 | |
505 | static const struct greybus_bundle_id gb_hid_id_table[] = { |
506 | { GREYBUS_DEVICE_CLASS(GREYBUS_CLASS_HID) }, |
507 | { } |
508 | }; |
509 | MODULE_DEVICE_TABLE(greybus, gb_hid_id_table); |
510 | |
511 | static struct greybus_driver gb_hid_driver = { |
512 | .name = "hid" , |
513 | .probe = gb_hid_probe, |
514 | .disconnect = gb_hid_disconnect, |
515 | .id_table = gb_hid_id_table, |
516 | }; |
517 | module_greybus_driver(gb_hid_driver); |
518 | |
519 | MODULE_LICENSE("GPL v2" ); |
520 | |