diff options
Diffstat (limited to 'drivers/hid/hid-logitech-hidpp.c')
-rw-r--r-- | drivers/hid/hid-logitech-hidpp.c | 1241 |
1 files changed, 1241 insertions, 0 deletions
diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c new file mode 100644 index 000000000000..2f420c0b6609 --- /dev/null +++ b/drivers/hid/hid-logitech-hidpp.c | |||
@@ -0,0 +1,1241 @@ | |||
1 | /* | ||
2 | * HIDPP protocol for Logitech Unifying receivers | ||
3 | * | ||
4 | * Copyright (c) 2011 Logitech (c) | ||
5 | * Copyright (c) 2012-2013 Google (c) | ||
6 | * Copyright (c) 2013-2014 Red Hat Inc. | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * This program is free software; you can redistribute it and/or modify it | ||
11 | * under the terms of the GNU General Public License as published by the Free | ||
12 | * Software Foundation; version 2 of the License. | ||
13 | */ | ||
14 | |||
15 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
16 | |||
17 | #include <linux/device.h> | ||
18 | #include <linux/hid.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/slab.h> | ||
21 | #include <linux/sched.h> | ||
22 | #include <linux/kfifo.h> | ||
23 | #include <linux/input/mt.h> | ||
24 | #include <asm/unaligned.h> | ||
25 | #include "hid-ids.h" | ||
26 | |||
27 | MODULE_LICENSE("GPL"); | ||
28 | MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>"); | ||
29 | MODULE_AUTHOR("Nestor Lopez Casado <nlopezcasad@logitech.com>"); | ||
30 | |||
31 | #define REPORT_ID_HIDPP_SHORT 0x10 | ||
32 | #define REPORT_ID_HIDPP_LONG 0x11 | ||
33 | |||
34 | #define HIDPP_REPORT_SHORT_LENGTH 7 | ||
35 | #define HIDPP_REPORT_LONG_LENGTH 20 | ||
36 | |||
37 | #define HIDPP_QUIRK_CLASS_WTP BIT(0) | ||
38 | |||
39 | /* bits 1..20 are reserved for classes */ | ||
40 | #define HIDPP_QUIRK_DELAYED_INIT BIT(21) | ||
41 | #define HIDPP_QUIRK_WTP_PHYSICAL_BUTTONS BIT(22) | ||
42 | #define HIDPP_QUIRK_MULTI_INPUT BIT(23) | ||
43 | |||
44 | /* | ||
45 | * There are two hidpp protocols in use, the first version hidpp10 is known | ||
46 | * as register access protocol or RAP, the second version hidpp20 is known as | ||
47 | * feature access protocol or FAP | ||
48 | * | ||
49 | * Most older devices (including the Unifying usb receiver) use the RAP protocol | ||
50 | * where as most newer devices use the FAP protocol. Both protocols are | ||
51 | * compatible with the underlying transport, which could be usb, Unifiying, or | ||
52 | * bluetooth. The message lengths are defined by the hid vendor specific report | ||
53 | * descriptor for the HIDPP_SHORT report type (total message lenth 7 bytes) and | ||
54 | * the HIDPP_LONG report type (total message length 20 bytes) | ||
55 | * | ||
56 | * The RAP protocol uses both report types, whereas the FAP only uses HIDPP_LONG | ||
57 | * messages. The Unifying receiver itself responds to RAP messages (device index | ||
58 | * is 0xFF for the receiver), and all messages (short or long) with a device | ||
59 | * index between 1 and 6 are passed untouched to the corresponding paired | ||
60 | * Unifying device. | ||
61 | * | ||
62 | * The paired device can be RAP or FAP, it will receive the message untouched | ||
63 | * from the Unifiying receiver. | ||
64 | */ | ||
65 | |||
66 | struct fap { | ||
67 | u8 feature_index; | ||
68 | u8 funcindex_clientid; | ||
69 | u8 params[HIDPP_REPORT_LONG_LENGTH - 4U]; | ||
70 | }; | ||
71 | |||
72 | struct rap { | ||
73 | u8 sub_id; | ||
74 | u8 reg_address; | ||
75 | u8 params[HIDPP_REPORT_LONG_LENGTH - 4U]; | ||
76 | }; | ||
77 | |||
78 | struct hidpp_report { | ||
79 | u8 report_id; | ||
80 | u8 device_index; | ||
81 | union { | ||
82 | struct fap fap; | ||
83 | struct rap rap; | ||
84 | u8 rawbytes[sizeof(struct fap)]; | ||
85 | }; | ||
86 | } __packed; | ||
87 | |||
88 | struct hidpp_device { | ||
89 | struct hid_device *hid_dev; | ||
90 | struct mutex send_mutex; | ||
91 | void *send_receive_buf; | ||
92 | wait_queue_head_t wait; | ||
93 | bool answer_available; | ||
94 | u8 protocol_major; | ||
95 | u8 protocol_minor; | ||
96 | |||
97 | void *private_data; | ||
98 | |||
99 | struct work_struct work; | ||
100 | struct kfifo delayed_work_fifo; | ||
101 | atomic_t connected; | ||
102 | struct input_dev *delayed_input; | ||
103 | |||
104 | unsigned long quirks; | ||
105 | }; | ||
106 | |||
107 | |||
108 | #define HIDPP_ERROR 0x8f | ||
109 | #define HIDPP_ERROR_SUCCESS 0x00 | ||
110 | #define HIDPP_ERROR_INVALID_SUBID 0x01 | ||
111 | #define HIDPP_ERROR_INVALID_ADRESS 0x02 | ||
112 | #define HIDPP_ERROR_INVALID_VALUE 0x03 | ||
113 | #define HIDPP_ERROR_CONNECT_FAIL 0x04 | ||
114 | #define HIDPP_ERROR_TOO_MANY_DEVICES 0x05 | ||
115 | #define HIDPP_ERROR_ALREADY_EXISTS 0x06 | ||
116 | #define HIDPP_ERROR_BUSY 0x07 | ||
117 | #define HIDPP_ERROR_UNKNOWN_DEVICE 0x08 | ||
118 | #define HIDPP_ERROR_RESOURCE_ERROR 0x09 | ||
119 | #define HIDPP_ERROR_REQUEST_UNAVAILABLE 0x0a | ||
120 | #define HIDPP_ERROR_INVALID_PARAM_VALUE 0x0b | ||
121 | #define HIDPP_ERROR_WRONG_PIN_CODE 0x0c | ||
122 | |||
123 | static void hidpp_connect_event(struct hidpp_device *hidpp_dev); | ||
124 | |||
125 | static int __hidpp_send_report(struct hid_device *hdev, | ||
126 | struct hidpp_report *hidpp_report) | ||
127 | { | ||
128 | int fields_count, ret; | ||
129 | |||
130 | switch (hidpp_report->report_id) { | ||
131 | case REPORT_ID_HIDPP_SHORT: | ||
132 | fields_count = HIDPP_REPORT_SHORT_LENGTH; | ||
133 | break; | ||
134 | case REPORT_ID_HIDPP_LONG: | ||
135 | fields_count = HIDPP_REPORT_LONG_LENGTH; | ||
136 | break; | ||
137 | default: | ||
138 | return -ENODEV; | ||
139 | } | ||
140 | |||
141 | /* | ||
142 | * set the device_index as the receiver, it will be overwritten by | ||
143 | * hid_hw_request if needed | ||
144 | */ | ||
145 | hidpp_report->device_index = 0xff; | ||
146 | |||
147 | ret = hid_hw_raw_request(hdev, hidpp_report->report_id, | ||
148 | (u8 *)hidpp_report, fields_count, HID_OUTPUT_REPORT, | ||
149 | HID_REQ_SET_REPORT); | ||
150 | |||
151 | return ret == fields_count ? 0 : -1; | ||
152 | } | ||
153 | |||
154 | /** | ||
155 | * hidpp_send_message_sync() returns 0 in case of success, and something else | ||
156 | * in case of a failure. | ||
157 | * - If ' something else' is positive, that means that an error has been raised | ||
158 | * by the protocol itself. | ||
159 | * - If ' something else' is negative, that means that we had a classic error | ||
160 | * (-ENOMEM, -EPIPE, etc...) | ||
161 | */ | ||
162 | static int hidpp_send_message_sync(struct hidpp_device *hidpp, | ||
163 | struct hidpp_report *message, | ||
164 | struct hidpp_report *response) | ||
165 | { | ||
166 | int ret; | ||
167 | |||
168 | mutex_lock(&hidpp->send_mutex); | ||
169 | |||
170 | hidpp->send_receive_buf = response; | ||
171 | hidpp->answer_available = false; | ||
172 | |||
173 | /* | ||
174 | * So that we can later validate the answer when it arrives | ||
175 | * in hidpp_raw_event | ||
176 | */ | ||
177 | *response = *message; | ||
178 | |||
179 | ret = __hidpp_send_report(hidpp->hid_dev, message); | ||
180 | |||
181 | if (ret) { | ||
182 | dbg_hid("__hidpp_send_report returned err: %d\n", ret); | ||
183 | memset(response, 0, sizeof(struct hidpp_report)); | ||
184 | goto exit; | ||
185 | } | ||
186 | |||
187 | if (!wait_event_timeout(hidpp->wait, hidpp->answer_available, | ||
188 | 5*HZ)) { | ||
189 | dbg_hid("%s:timeout waiting for response\n", __func__); | ||
190 | memset(response, 0, sizeof(struct hidpp_report)); | ||
191 | ret = -ETIMEDOUT; | ||
192 | } | ||
193 | |||
194 | if (response->report_id == REPORT_ID_HIDPP_SHORT && | ||
195 | response->fap.feature_index == HIDPP_ERROR) { | ||
196 | ret = response->fap.params[1]; | ||
197 | dbg_hid("__hidpp_send_report got hidpp error %02X\n", ret); | ||
198 | goto exit; | ||
199 | } | ||
200 | |||
201 | exit: | ||
202 | mutex_unlock(&hidpp->send_mutex); | ||
203 | return ret; | ||
204 | |||
205 | } | ||
206 | |||
207 | static int hidpp_send_fap_command_sync(struct hidpp_device *hidpp, | ||
208 | u8 feat_index, u8 funcindex_clientid, u8 *params, int param_count, | ||
209 | struct hidpp_report *response) | ||
210 | { | ||
211 | struct hidpp_report *message; | ||
212 | int ret; | ||
213 | |||
214 | if (param_count > sizeof(message->fap.params)) | ||
215 | return -EINVAL; | ||
216 | |||
217 | message = kzalloc(sizeof(struct hidpp_report), GFP_KERNEL); | ||
218 | if (!message) | ||
219 | return -ENOMEM; | ||
220 | message->report_id = REPORT_ID_HIDPP_LONG; | ||
221 | message->fap.feature_index = feat_index; | ||
222 | message->fap.funcindex_clientid = funcindex_clientid; | ||
223 | memcpy(&message->fap.params, params, param_count); | ||
224 | |||
225 | ret = hidpp_send_message_sync(hidpp, message, response); | ||
226 | kfree(message); | ||
227 | return ret; | ||
228 | } | ||
229 | |||
230 | static int hidpp_send_rap_command_sync(struct hidpp_device *hidpp_dev, | ||
231 | u8 report_id, u8 sub_id, u8 reg_address, u8 *params, int param_count, | ||
232 | struct hidpp_report *response) | ||
233 | { | ||
234 | struct hidpp_report *message; | ||
235 | int ret; | ||
236 | |||
237 | if ((report_id != REPORT_ID_HIDPP_SHORT) && | ||
238 | (report_id != REPORT_ID_HIDPP_LONG)) | ||
239 | return -EINVAL; | ||
240 | |||
241 | if (param_count > sizeof(message->rap.params)) | ||
242 | return -EINVAL; | ||
243 | |||
244 | message = kzalloc(sizeof(struct hidpp_report), GFP_KERNEL); | ||
245 | if (!message) | ||
246 | return -ENOMEM; | ||
247 | message->report_id = report_id; | ||
248 | message->rap.sub_id = sub_id; | ||
249 | message->rap.reg_address = reg_address; | ||
250 | memcpy(&message->rap.params, params, param_count); | ||
251 | |||
252 | ret = hidpp_send_message_sync(hidpp_dev, message, response); | ||
253 | kfree(message); | ||
254 | return ret; | ||
255 | } | ||
256 | |||
257 | static void delayed_work_cb(struct work_struct *work) | ||
258 | { | ||
259 | struct hidpp_device *hidpp = container_of(work, struct hidpp_device, | ||
260 | work); | ||
261 | hidpp_connect_event(hidpp); | ||
262 | } | ||
263 | |||
264 | static inline bool hidpp_match_answer(struct hidpp_report *question, | ||
265 | struct hidpp_report *answer) | ||
266 | { | ||
267 | return (answer->fap.feature_index == question->fap.feature_index) && | ||
268 | (answer->fap.funcindex_clientid == question->fap.funcindex_clientid); | ||
269 | } | ||
270 | |||
271 | static inline bool hidpp_match_error(struct hidpp_report *question, | ||
272 | struct hidpp_report *answer) | ||
273 | { | ||
274 | return (answer->fap.feature_index == HIDPP_ERROR) && | ||
275 | (answer->fap.funcindex_clientid == question->fap.feature_index) && | ||
276 | (answer->fap.params[0] == question->fap.funcindex_clientid); | ||
277 | } | ||
278 | |||
279 | static inline bool hidpp_report_is_connect_event(struct hidpp_report *report) | ||
280 | { | ||
281 | return (report->report_id == REPORT_ID_HIDPP_SHORT) && | ||
282 | (report->rap.sub_id == 0x41); | ||
283 | } | ||
284 | |||
285 | /* -------------------------------------------------------------------------- */ | ||
286 | /* HIDP++ 1.0 commands */ | ||
287 | /* -------------------------------------------------------------------------- */ | ||
288 | |||
289 | #define HIDPP_SET_REGISTER 0x80 | ||
290 | #define HIDPP_GET_REGISTER 0x81 | ||
291 | #define HIDPP_SET_LONG_REGISTER 0x82 | ||
292 | #define HIDPP_GET_LONG_REGISTER 0x83 | ||
293 | |||
294 | #define HIDPP_REG_PAIRING_INFORMATION 0xB5 | ||
295 | #define DEVICE_NAME 0x40 | ||
296 | |||
297 | static char *hidpp_get_unifying_name(struct hidpp_device *hidpp_dev) | ||
298 | { | ||
299 | struct hidpp_report response; | ||
300 | int ret; | ||
301 | /* hid-logitech-dj is in charge of setting the right device index */ | ||
302 | u8 params[1] = { DEVICE_NAME }; | ||
303 | char *name; | ||
304 | int len; | ||
305 | |||
306 | ret = hidpp_send_rap_command_sync(hidpp_dev, | ||
307 | REPORT_ID_HIDPP_SHORT, | ||
308 | HIDPP_GET_LONG_REGISTER, | ||
309 | HIDPP_REG_PAIRING_INFORMATION, | ||
310 | params, 1, &response); | ||
311 | if (ret) | ||
312 | return NULL; | ||
313 | |||
314 | len = response.rap.params[1]; | ||
315 | |||
316 | if (2 + len > sizeof(response.rap.params)) | ||
317 | return NULL; | ||
318 | |||
319 | name = kzalloc(len + 1, GFP_KERNEL); | ||
320 | if (!name) | ||
321 | return NULL; | ||
322 | |||
323 | memcpy(name, &response.rap.params[2], len); | ||
324 | return name; | ||
325 | } | ||
326 | |||
327 | /* -------------------------------------------------------------------------- */ | ||
328 | /* 0x0000: Root */ | ||
329 | /* -------------------------------------------------------------------------- */ | ||
330 | |||
331 | #define HIDPP_PAGE_ROOT 0x0000 | ||
332 | #define HIDPP_PAGE_ROOT_IDX 0x00 | ||
333 | |||
334 | #define CMD_ROOT_GET_FEATURE 0x01 | ||
335 | #define CMD_ROOT_GET_PROTOCOL_VERSION 0x11 | ||
336 | |||
337 | static int hidpp_root_get_feature(struct hidpp_device *hidpp, u16 feature, | ||
338 | u8 *feature_index, u8 *feature_type) | ||
339 | { | ||
340 | struct hidpp_report response; | ||
341 | int ret; | ||
342 | u8 params[2] = { feature >> 8, feature & 0x00FF }; | ||
343 | |||
344 | ret = hidpp_send_fap_command_sync(hidpp, | ||
345 | HIDPP_PAGE_ROOT_IDX, | ||
346 | CMD_ROOT_GET_FEATURE, | ||
347 | params, 2, &response); | ||
348 | if (ret) | ||
349 | return ret; | ||
350 | |||
351 | *feature_index = response.fap.params[0]; | ||
352 | *feature_type = response.fap.params[1]; | ||
353 | |||
354 | return ret; | ||
355 | } | ||
356 | |||
357 | static int hidpp_root_get_protocol_version(struct hidpp_device *hidpp) | ||
358 | { | ||
359 | struct hidpp_report response; | ||
360 | int ret; | ||
361 | |||
362 | ret = hidpp_send_fap_command_sync(hidpp, | ||
363 | HIDPP_PAGE_ROOT_IDX, | ||
364 | CMD_ROOT_GET_PROTOCOL_VERSION, | ||
365 | NULL, 0, &response); | ||
366 | |||
367 | if (ret == HIDPP_ERROR_INVALID_SUBID) { | ||
368 | hidpp->protocol_major = 1; | ||
369 | hidpp->protocol_minor = 0; | ||
370 | return 0; | ||
371 | } | ||
372 | |||
373 | /* the device might not be connected */ | ||
374 | if (ret == HIDPP_ERROR_RESOURCE_ERROR) | ||
375 | return -EIO; | ||
376 | |||
377 | if (ret > 0) { | ||
378 | hid_err(hidpp->hid_dev, "%s: received protocol error 0x%02x\n", | ||
379 | __func__, ret); | ||
380 | return -EPROTO; | ||
381 | } | ||
382 | if (ret) | ||
383 | return ret; | ||
384 | |||
385 | hidpp->protocol_major = response.fap.params[0]; | ||
386 | hidpp->protocol_minor = response.fap.params[1]; | ||
387 | |||
388 | return ret; | ||
389 | } | ||
390 | |||
391 | static bool hidpp_is_connected(struct hidpp_device *hidpp) | ||
392 | { | ||
393 | int ret; | ||
394 | |||
395 | ret = hidpp_root_get_protocol_version(hidpp); | ||
396 | if (!ret) | ||
397 | hid_dbg(hidpp->hid_dev, "HID++ %u.%u device connected.\n", | ||
398 | hidpp->protocol_major, hidpp->protocol_minor); | ||
399 | return ret == 0; | ||
400 | } | ||
401 | |||
402 | /* -------------------------------------------------------------------------- */ | ||
403 | /* 0x0005: GetDeviceNameType */ | ||
404 | /* -------------------------------------------------------------------------- */ | ||
405 | |||
406 | #define HIDPP_PAGE_GET_DEVICE_NAME_TYPE 0x0005 | ||
407 | |||
408 | #define CMD_GET_DEVICE_NAME_TYPE_GET_COUNT 0x01 | ||
409 | #define CMD_GET_DEVICE_NAME_TYPE_GET_DEVICE_NAME 0x11 | ||
410 | #define CMD_GET_DEVICE_NAME_TYPE_GET_TYPE 0x21 | ||
411 | |||
412 | static int hidpp_devicenametype_get_count(struct hidpp_device *hidpp, | ||
413 | u8 feature_index, u8 *nameLength) | ||
414 | { | ||
415 | struct hidpp_report response; | ||
416 | int ret; | ||
417 | |||
418 | ret = hidpp_send_fap_command_sync(hidpp, feature_index, | ||
419 | CMD_GET_DEVICE_NAME_TYPE_GET_COUNT, NULL, 0, &response); | ||
420 | |||
421 | if (ret > 0) { | ||
422 | hid_err(hidpp->hid_dev, "%s: received protocol error 0x%02x\n", | ||
423 | __func__, ret); | ||
424 | return -EPROTO; | ||
425 | } | ||
426 | if (ret) | ||
427 | return ret; | ||
428 | |||
429 | *nameLength = response.fap.params[0]; | ||
430 | |||
431 | return ret; | ||
432 | } | ||
433 | |||
434 | static int hidpp_devicenametype_get_device_name(struct hidpp_device *hidpp, | ||
435 | u8 feature_index, u8 char_index, char *device_name, int len_buf) | ||
436 | { | ||
437 | struct hidpp_report response; | ||
438 | int ret, i; | ||
439 | int count; | ||
440 | |||
441 | ret = hidpp_send_fap_command_sync(hidpp, feature_index, | ||
442 | CMD_GET_DEVICE_NAME_TYPE_GET_DEVICE_NAME, &char_index, 1, | ||
443 | &response); | ||
444 | |||
445 | if (ret > 0) { | ||
446 | hid_err(hidpp->hid_dev, "%s: received protocol error 0x%02x\n", | ||
447 | __func__, ret); | ||
448 | return -EPROTO; | ||
449 | } | ||
450 | if (ret) | ||
451 | return ret; | ||
452 | |||
453 | if (response.report_id == REPORT_ID_HIDPP_LONG) | ||
454 | count = HIDPP_REPORT_LONG_LENGTH - 4; | ||
455 | else | ||
456 | count = HIDPP_REPORT_SHORT_LENGTH - 4; | ||
457 | |||
458 | if (len_buf < count) | ||
459 | count = len_buf; | ||
460 | |||
461 | for (i = 0; i < count; i++) | ||
462 | device_name[i] = response.fap.params[i]; | ||
463 | |||
464 | return count; | ||
465 | } | ||
466 | |||
467 | static char *hidpp_get_device_name(struct hidpp_device *hidpp) | ||
468 | { | ||
469 | u8 feature_type; | ||
470 | u8 feature_index; | ||
471 | u8 __name_length; | ||
472 | char *name; | ||
473 | unsigned index = 0; | ||
474 | int ret; | ||
475 | |||
476 | ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_GET_DEVICE_NAME_TYPE, | ||
477 | &feature_index, &feature_type); | ||
478 | if (ret) | ||
479 | return NULL; | ||
480 | |||
481 | ret = hidpp_devicenametype_get_count(hidpp, feature_index, | ||
482 | &__name_length); | ||
483 | if (ret) | ||
484 | return NULL; | ||
485 | |||
486 | name = kzalloc(__name_length + 1, GFP_KERNEL); | ||
487 | if (!name) | ||
488 | return NULL; | ||
489 | |||
490 | while (index < __name_length) { | ||
491 | ret = hidpp_devicenametype_get_device_name(hidpp, | ||
492 | feature_index, index, name + index, | ||
493 | __name_length - index); | ||
494 | if (ret <= 0) { | ||
495 | kfree(name); | ||
496 | return NULL; | ||
497 | } | ||
498 | index += ret; | ||
499 | } | ||
500 | |||
501 | return name; | ||
502 | } | ||
503 | |||
504 | /* -------------------------------------------------------------------------- */ | ||
505 | /* 0x6100: TouchPadRawXY */ | ||
506 | /* -------------------------------------------------------------------------- */ | ||
507 | |||
508 | #define HIDPP_PAGE_TOUCHPAD_RAW_XY 0x6100 | ||
509 | |||
510 | #define CMD_TOUCHPAD_GET_RAW_INFO 0x01 | ||
511 | #define CMD_TOUCHPAD_SET_RAW_REPORT_STATE 0x21 | ||
512 | |||
513 | #define EVENT_TOUCHPAD_RAW_XY 0x00 | ||
514 | |||
515 | #define TOUCHPAD_RAW_XY_ORIGIN_LOWER_LEFT 0x01 | ||
516 | #define TOUCHPAD_RAW_XY_ORIGIN_UPPER_LEFT 0x03 | ||
517 | |||
518 | struct hidpp_touchpad_raw_info { | ||
519 | u16 x_size; | ||
520 | u16 y_size; | ||
521 | u8 z_range; | ||
522 | u8 area_range; | ||
523 | u8 timestamp_unit; | ||
524 | u8 maxcontacts; | ||
525 | u8 origin; | ||
526 | u16 res; | ||
527 | }; | ||
528 | |||
529 | struct hidpp_touchpad_raw_xy_finger { | ||
530 | u8 contact_type; | ||
531 | u8 contact_status; | ||
532 | u16 x; | ||
533 | u16 y; | ||
534 | u8 z; | ||
535 | u8 area; | ||
536 | u8 finger_id; | ||
537 | }; | ||
538 | |||
539 | struct hidpp_touchpad_raw_xy { | ||
540 | u16 timestamp; | ||
541 | struct hidpp_touchpad_raw_xy_finger fingers[2]; | ||
542 | u8 spurious_flag; | ||
543 | u8 end_of_frame; | ||
544 | u8 finger_count; | ||
545 | u8 button; | ||
546 | }; | ||
547 | |||
548 | static int hidpp_touchpad_get_raw_info(struct hidpp_device *hidpp, | ||
549 | u8 feature_index, struct hidpp_touchpad_raw_info *raw_info) | ||
550 | { | ||
551 | struct hidpp_report response; | ||
552 | int ret; | ||
553 | u8 *params = (u8 *)response.fap.params; | ||
554 | |||
555 | ret = hidpp_send_fap_command_sync(hidpp, feature_index, | ||
556 | CMD_TOUCHPAD_GET_RAW_INFO, NULL, 0, &response); | ||
557 | |||
558 | if (ret > 0) { | ||
559 | hid_err(hidpp->hid_dev, "%s: received protocol error 0x%02x\n", | ||
560 | __func__, ret); | ||
561 | return -EPROTO; | ||
562 | } | ||
563 | if (ret) | ||
564 | return ret; | ||
565 | |||
566 | raw_info->x_size = get_unaligned_be16(¶ms[0]); | ||
567 | raw_info->y_size = get_unaligned_be16(¶ms[2]); | ||
568 | raw_info->z_range = params[4]; | ||
569 | raw_info->area_range = params[5]; | ||
570 | raw_info->maxcontacts = params[7]; | ||
571 | raw_info->origin = params[8]; | ||
572 | /* res is given in unit per inch */ | ||
573 | raw_info->res = get_unaligned_be16(¶ms[13]) * 2 / 51; | ||
574 | |||
575 | return ret; | ||
576 | } | ||
577 | |||
578 | static int hidpp_touchpad_set_raw_report_state(struct hidpp_device *hidpp_dev, | ||
579 | u8 feature_index, bool send_raw_reports, | ||
580 | bool sensor_enhanced_settings) | ||
581 | { | ||
582 | struct hidpp_report response; | ||
583 | |||
584 | /* | ||
585 | * Params: | ||
586 | * bit 0 - enable raw | ||
587 | * bit 1 - 16bit Z, no area | ||
588 | * bit 2 - enhanced sensitivity | ||
589 | * bit 3 - width, height (4 bits each) instead of area | ||
590 | * bit 4 - send raw + gestures (degrades smoothness) | ||
591 | * remaining bits - reserved | ||
592 | */ | ||
593 | u8 params = send_raw_reports | (sensor_enhanced_settings << 2); | ||
594 | |||
595 | return hidpp_send_fap_command_sync(hidpp_dev, feature_index, | ||
596 | CMD_TOUCHPAD_SET_RAW_REPORT_STATE, ¶ms, 1, &response); | ||
597 | } | ||
598 | |||
599 | static void hidpp_touchpad_touch_event(u8 *data, | ||
600 | struct hidpp_touchpad_raw_xy_finger *finger) | ||
601 | { | ||
602 | u8 x_m = data[0] << 2; | ||
603 | u8 y_m = data[2] << 2; | ||
604 | |||
605 | finger->x = x_m << 6 | data[1]; | ||
606 | finger->y = y_m << 6 | data[3]; | ||
607 | |||
608 | finger->contact_type = data[0] >> 6; | ||
609 | finger->contact_status = data[2] >> 6; | ||
610 | |||
611 | finger->z = data[4]; | ||
612 | finger->area = data[5]; | ||
613 | finger->finger_id = data[6] >> 4; | ||
614 | } | ||
615 | |||
616 | static void hidpp_touchpad_raw_xy_event(struct hidpp_device *hidpp_dev, | ||
617 | u8 *data, struct hidpp_touchpad_raw_xy *raw_xy) | ||
618 | { | ||
619 | memset(raw_xy, 0, sizeof(struct hidpp_touchpad_raw_xy)); | ||
620 | raw_xy->end_of_frame = data[8] & 0x01; | ||
621 | raw_xy->spurious_flag = (data[8] >> 1) & 0x01; | ||
622 | raw_xy->finger_count = data[15] & 0x0f; | ||
623 | raw_xy->button = (data[8] >> 2) & 0x01; | ||
624 | |||
625 | if (raw_xy->finger_count) { | ||
626 | hidpp_touchpad_touch_event(&data[2], &raw_xy->fingers[0]); | ||
627 | hidpp_touchpad_touch_event(&data[9], &raw_xy->fingers[1]); | ||
628 | } | ||
629 | } | ||
630 | |||
631 | /* ************************************************************************** */ | ||
632 | /* */ | ||
633 | /* Device Support */ | ||
634 | /* */ | ||
635 | /* ************************************************************************** */ | ||
636 | |||
637 | /* -------------------------------------------------------------------------- */ | ||
638 | /* Touchpad HID++ devices */ | ||
639 | /* -------------------------------------------------------------------------- */ | ||
640 | |||
641 | #define WTP_MANUAL_RESOLUTION 39 | ||
642 | |||
643 | struct wtp_data { | ||
644 | struct input_dev *input; | ||
645 | u16 x_size, y_size; | ||
646 | u8 finger_count; | ||
647 | u8 mt_feature_index; | ||
648 | u8 button_feature_index; | ||
649 | u8 maxcontacts; | ||
650 | bool flip_y; | ||
651 | unsigned int resolution; | ||
652 | }; | ||
653 | |||
654 | static int wtp_input_mapping(struct hid_device *hdev, struct hid_input *hi, | ||
655 | struct hid_field *field, struct hid_usage *usage, | ||
656 | unsigned long **bit, int *max) | ||
657 | { | ||
658 | struct hidpp_device *hidpp = hid_get_drvdata(hdev); | ||
659 | |||
660 | if ((hidpp->quirks & HIDPP_QUIRK_MULTI_INPUT) && | ||
661 | (field->application == HID_GD_KEYBOARD)) | ||
662 | return 0; | ||
663 | |||
664 | return -1; | ||
665 | } | ||
666 | |||
667 | static void wtp_populate_input(struct hidpp_device *hidpp, | ||
668 | struct input_dev *input_dev, bool origin_is_hid_core) | ||
669 | { | ||
670 | struct wtp_data *wd = hidpp->private_data; | ||
671 | |||
672 | if ((hidpp->quirks & HIDPP_QUIRK_MULTI_INPUT) && origin_is_hid_core) | ||
673 | /* this is the generic hid-input call */ | ||
674 | return; | ||
675 | |||
676 | __set_bit(EV_ABS, input_dev->evbit); | ||
677 | __set_bit(EV_KEY, input_dev->evbit); | ||
678 | __clear_bit(EV_REL, input_dev->evbit); | ||
679 | __clear_bit(EV_LED, input_dev->evbit); | ||
680 | |||
681 | input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, wd->x_size, 0, 0); | ||
682 | input_abs_set_res(input_dev, ABS_MT_POSITION_X, wd->resolution); | ||
683 | input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, wd->y_size, 0, 0); | ||
684 | input_abs_set_res(input_dev, ABS_MT_POSITION_Y, wd->resolution); | ||
685 | |||
686 | /* Max pressure is not given by the devices, pick one */ | ||
687 | input_set_abs_params(input_dev, ABS_MT_PRESSURE, 0, 50, 0, 0); | ||
688 | |||
689 | input_set_capability(input_dev, EV_KEY, BTN_LEFT); | ||
690 | |||
691 | if (hidpp->quirks & HIDPP_QUIRK_WTP_PHYSICAL_BUTTONS) | ||
692 | input_set_capability(input_dev, EV_KEY, BTN_RIGHT); | ||
693 | else | ||
694 | __set_bit(INPUT_PROP_BUTTONPAD, input_dev->propbit); | ||
695 | |||
696 | input_mt_init_slots(input_dev, wd->maxcontacts, INPUT_MT_POINTER | | ||
697 | INPUT_MT_DROP_UNUSED); | ||
698 | |||
699 | wd->input = input_dev; | ||
700 | } | ||
701 | |||
702 | static void wtp_touch_event(struct wtp_data *wd, | ||
703 | struct hidpp_touchpad_raw_xy_finger *touch_report) | ||
704 | { | ||
705 | int slot; | ||
706 | |||
707 | if (!touch_report->finger_id || touch_report->contact_type) | ||
708 | /* no actual data */ | ||
709 | return; | ||
710 | |||
711 | slot = input_mt_get_slot_by_key(wd->input, touch_report->finger_id); | ||
712 | |||
713 | input_mt_slot(wd->input, slot); | ||
714 | input_mt_report_slot_state(wd->input, MT_TOOL_FINGER, | ||
715 | touch_report->contact_status); | ||
716 | if (touch_report->contact_status) { | ||
717 | input_event(wd->input, EV_ABS, ABS_MT_POSITION_X, | ||
718 | touch_report->x); | ||
719 | input_event(wd->input, EV_ABS, ABS_MT_POSITION_Y, | ||
720 | wd->flip_y ? wd->y_size - touch_report->y : | ||
721 | touch_report->y); | ||
722 | input_event(wd->input, EV_ABS, ABS_MT_PRESSURE, | ||
723 | touch_report->area); | ||
724 | } | ||
725 | } | ||
726 | |||
727 | static void wtp_send_raw_xy_event(struct hidpp_device *hidpp, | ||
728 | struct hidpp_touchpad_raw_xy *raw) | ||
729 | { | ||
730 | struct wtp_data *wd = hidpp->private_data; | ||
731 | int i; | ||
732 | |||
733 | for (i = 0; i < 2; i++) | ||
734 | wtp_touch_event(wd, &(raw->fingers[i])); | ||
735 | |||
736 | if (raw->end_of_frame && | ||
737 | !(hidpp->quirks & HIDPP_QUIRK_WTP_PHYSICAL_BUTTONS)) | ||
738 | input_event(wd->input, EV_KEY, BTN_LEFT, raw->button); | ||
739 | |||
740 | if (raw->end_of_frame || raw->finger_count <= 2) { | ||
741 | input_mt_sync_frame(wd->input); | ||
742 | input_sync(wd->input); | ||
743 | } | ||
744 | } | ||
745 | |||
746 | static int wtp_mouse_raw_xy_event(struct hidpp_device *hidpp, u8 *data) | ||
747 | { | ||
748 | struct wtp_data *wd = hidpp->private_data; | ||
749 | u8 c1_area = ((data[7] & 0xf) * (data[7] & 0xf) + | ||
750 | (data[7] >> 4) * (data[7] >> 4)) / 2; | ||
751 | u8 c2_area = ((data[13] & 0xf) * (data[13] & 0xf) + | ||
752 | (data[13] >> 4) * (data[13] >> 4)) / 2; | ||
753 | struct hidpp_touchpad_raw_xy raw = { | ||
754 | .timestamp = data[1], | ||
755 | .fingers = { | ||
756 | { | ||
757 | .contact_type = 0, | ||
758 | .contact_status = !!data[7], | ||
759 | .x = get_unaligned_le16(&data[3]), | ||
760 | .y = get_unaligned_le16(&data[5]), | ||
761 | .z = c1_area, | ||
762 | .area = c1_area, | ||
763 | .finger_id = data[2], | ||
764 | }, { | ||
765 | .contact_type = 0, | ||
766 | .contact_status = !!data[13], | ||
767 | .x = get_unaligned_le16(&data[9]), | ||
768 | .y = get_unaligned_le16(&data[11]), | ||
769 | .z = c2_area, | ||
770 | .area = c2_area, | ||
771 | .finger_id = data[8], | ||
772 | } | ||
773 | }, | ||
774 | .finger_count = wd->maxcontacts, | ||
775 | .spurious_flag = 0, | ||
776 | .end_of_frame = (data[0] >> 7) == 0, | ||
777 | .button = data[0] & 0x01, | ||
778 | }; | ||
779 | |||
780 | wtp_send_raw_xy_event(hidpp, &raw); | ||
781 | |||
782 | return 1; | ||
783 | } | ||
784 | |||
785 | static int wtp_raw_event(struct hid_device *hdev, u8 *data, int size) | ||
786 | { | ||
787 | struct hidpp_device *hidpp = hid_get_drvdata(hdev); | ||
788 | struct wtp_data *wd = hidpp->private_data; | ||
789 | struct hidpp_report *report = (struct hidpp_report *)data; | ||
790 | struct hidpp_touchpad_raw_xy raw; | ||
791 | |||
792 | if (!wd || !wd->input) | ||
793 | return 1; | ||
794 | |||
795 | switch (data[0]) { | ||
796 | case 0x02: | ||
797 | if (hidpp->quirks & HIDPP_QUIRK_WTP_PHYSICAL_BUTTONS) { | ||
798 | input_event(wd->input, EV_KEY, BTN_LEFT, | ||
799 | !!(data[1] & 0x01)); | ||
800 | input_event(wd->input, EV_KEY, BTN_RIGHT, | ||
801 | !!(data[1] & 0x02)); | ||
802 | input_sync(wd->input); | ||
803 | } else { | ||
804 | if (size < 21) | ||
805 | return 1; | ||
806 | return wtp_mouse_raw_xy_event(hidpp, &data[7]); | ||
807 | } | ||
808 | case REPORT_ID_HIDPP_LONG: | ||
809 | if ((report->fap.feature_index != wd->mt_feature_index) || | ||
810 | (report->fap.funcindex_clientid != EVENT_TOUCHPAD_RAW_XY)) | ||
811 | return 1; | ||
812 | hidpp_touchpad_raw_xy_event(hidpp, data + 4, &raw); | ||
813 | |||
814 | wtp_send_raw_xy_event(hidpp, &raw); | ||
815 | return 0; | ||
816 | } | ||
817 | |||
818 | return 0; | ||
819 | } | ||
820 | |||
821 | static int wtp_get_config(struct hidpp_device *hidpp) | ||
822 | { | ||
823 | struct wtp_data *wd = hidpp->private_data; | ||
824 | struct hidpp_touchpad_raw_info raw_info = {0}; | ||
825 | u8 feature_type; | ||
826 | int ret; | ||
827 | |||
828 | ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_TOUCHPAD_RAW_XY, | ||
829 | &wd->mt_feature_index, &feature_type); | ||
830 | if (ret) | ||
831 | /* means that the device is not powered up */ | ||
832 | return ret; | ||
833 | |||
834 | ret = hidpp_touchpad_get_raw_info(hidpp, wd->mt_feature_index, | ||
835 | &raw_info); | ||
836 | if (ret) | ||
837 | return ret; | ||
838 | |||
839 | wd->x_size = raw_info.x_size; | ||
840 | wd->y_size = raw_info.y_size; | ||
841 | wd->maxcontacts = raw_info.maxcontacts; | ||
842 | wd->flip_y = raw_info.origin == TOUCHPAD_RAW_XY_ORIGIN_LOWER_LEFT; | ||
843 | wd->resolution = raw_info.res; | ||
844 | if (!wd->resolution) | ||
845 | wd->resolution = WTP_MANUAL_RESOLUTION; | ||
846 | |||
847 | return 0; | ||
848 | } | ||
849 | |||
850 | static int wtp_allocate(struct hid_device *hdev, const struct hid_device_id *id) | ||
851 | { | ||
852 | struct hidpp_device *hidpp = hid_get_drvdata(hdev); | ||
853 | struct wtp_data *wd; | ||
854 | |||
855 | wd = devm_kzalloc(&hdev->dev, sizeof(struct wtp_data), | ||
856 | GFP_KERNEL); | ||
857 | if (!wd) | ||
858 | return -ENOMEM; | ||
859 | |||
860 | hidpp->private_data = wd; | ||
861 | |||
862 | return 0; | ||
863 | }; | ||
864 | |||
865 | static void wtp_connect(struct hid_device *hdev, bool connected) | ||
866 | { | ||
867 | struct hidpp_device *hidpp = hid_get_drvdata(hdev); | ||
868 | struct wtp_data *wd = hidpp->private_data; | ||
869 | int ret; | ||
870 | |||
871 | if (!connected) | ||
872 | return; | ||
873 | |||
874 | if (!wd->x_size) { | ||
875 | ret = wtp_get_config(hidpp); | ||
876 | if (ret) { | ||
877 | hid_err(hdev, "Can not get wtp config: %d\n", ret); | ||
878 | return; | ||
879 | } | ||
880 | } | ||
881 | |||
882 | hidpp_touchpad_set_raw_report_state(hidpp, wd->mt_feature_index, | ||
883 | true, true); | ||
884 | } | ||
885 | |||
886 | /* -------------------------------------------------------------------------- */ | ||
887 | /* Generic HID++ devices */ | ||
888 | /* -------------------------------------------------------------------------- */ | ||
889 | |||
890 | static int hidpp_input_mapping(struct hid_device *hdev, struct hid_input *hi, | ||
891 | struct hid_field *field, struct hid_usage *usage, | ||
892 | unsigned long **bit, int *max) | ||
893 | { | ||
894 | struct hidpp_device *hidpp = hid_get_drvdata(hdev); | ||
895 | |||
896 | if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP) | ||
897 | return wtp_input_mapping(hdev, hi, field, usage, bit, max); | ||
898 | |||
899 | return 0; | ||
900 | } | ||
901 | |||
902 | static void hidpp_populate_input(struct hidpp_device *hidpp, | ||
903 | struct input_dev *input, bool origin_is_hid_core) | ||
904 | { | ||
905 | if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP) | ||
906 | wtp_populate_input(hidpp, input, origin_is_hid_core); | ||
907 | } | ||
908 | |||
909 | static void hidpp_input_configured(struct hid_device *hdev, | ||
910 | struct hid_input *hidinput) | ||
911 | { | ||
912 | struct hidpp_device *hidpp = hid_get_drvdata(hdev); | ||
913 | struct input_dev *input = hidinput->input; | ||
914 | |||
915 | hidpp_populate_input(hidpp, input, true); | ||
916 | } | ||
917 | |||
918 | static int hidpp_raw_hidpp_event(struct hidpp_device *hidpp, u8 *data, | ||
919 | int size) | ||
920 | { | ||
921 | struct hidpp_report *question = hidpp->send_receive_buf; | ||
922 | struct hidpp_report *answer = hidpp->send_receive_buf; | ||
923 | struct hidpp_report *report = (struct hidpp_report *)data; | ||
924 | |||
925 | /* | ||
926 | * If the mutex is locked then we have a pending answer from a | ||
927 | * previoulsly sent command | ||
928 | */ | ||
929 | if (unlikely(mutex_is_locked(&hidpp->send_mutex))) { | ||
930 | /* | ||
931 | * Check for a correct hidpp20 answer or the corresponding | ||
932 | * error | ||
933 | */ | ||
934 | if (hidpp_match_answer(question, report) || | ||
935 | hidpp_match_error(question, report)) { | ||
936 | *answer = *report; | ||
937 | hidpp->answer_available = true; | ||
938 | wake_up(&hidpp->wait); | ||
939 | /* | ||
940 | * This was an answer to a command that this driver sent | ||
941 | * We return 1 to hid-core to avoid forwarding the | ||
942 | * command upstream as it has been treated by the driver | ||
943 | */ | ||
944 | |||
945 | return 1; | ||
946 | } | ||
947 | } | ||
948 | |||
949 | if (unlikely(hidpp_report_is_connect_event(report))) { | ||
950 | atomic_set(&hidpp->connected, | ||
951 | !(report->rap.params[0] & (1 << 6))); | ||
952 | if ((hidpp->quirks & HIDPP_QUIRK_DELAYED_INIT) && | ||
953 | (schedule_work(&hidpp->work) == 0)) | ||
954 | dbg_hid("%s: connect event already queued\n", __func__); | ||
955 | return 1; | ||
956 | } | ||
957 | |||
958 | if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP) | ||
959 | return wtp_raw_event(hidpp->hid_dev, data, size); | ||
960 | |||
961 | return 0; | ||
962 | } | ||
963 | |||
964 | static int hidpp_raw_event(struct hid_device *hdev, struct hid_report *report, | ||
965 | u8 *data, int size) | ||
966 | { | ||
967 | struct hidpp_device *hidpp = hid_get_drvdata(hdev); | ||
968 | |||
969 | switch (data[0]) { | ||
970 | case REPORT_ID_HIDPP_LONG: | ||
971 | if (size != HIDPP_REPORT_LONG_LENGTH) { | ||
972 | hid_err(hdev, "received hid++ report of bad size (%d)", | ||
973 | size); | ||
974 | return 1; | ||
975 | } | ||
976 | return hidpp_raw_hidpp_event(hidpp, data, size); | ||
977 | case REPORT_ID_HIDPP_SHORT: | ||
978 | if (size != HIDPP_REPORT_SHORT_LENGTH) { | ||
979 | hid_err(hdev, "received hid++ report of bad size (%d)", | ||
980 | size); | ||
981 | return 1; | ||
982 | } | ||
983 | return hidpp_raw_hidpp_event(hidpp, data, size); | ||
984 | } | ||
985 | |||
986 | if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP) | ||
987 | return wtp_raw_event(hdev, data, size); | ||
988 | |||
989 | return 0; | ||
990 | } | ||
991 | |||
992 | static void hidpp_overwrite_name(struct hid_device *hdev, bool use_unifying) | ||
993 | { | ||
994 | struct hidpp_device *hidpp = hid_get_drvdata(hdev); | ||
995 | char *name; | ||
996 | |||
997 | if (use_unifying) | ||
998 | /* | ||
999 | * the device is connected through an Unifying receiver, and | ||
1000 | * might not be already connected. | ||
1001 | * Ask the receiver for its name. | ||
1002 | */ | ||
1003 | name = hidpp_get_unifying_name(hidpp); | ||
1004 | else | ||
1005 | name = hidpp_get_device_name(hidpp); | ||
1006 | |||
1007 | if (!name) | ||
1008 | hid_err(hdev, "unable to retrieve the name of the device"); | ||
1009 | else | ||
1010 | snprintf(hdev->name, sizeof(hdev->name), "%s", name); | ||
1011 | |||
1012 | kfree(name); | ||
1013 | } | ||
1014 | |||
1015 | static int hidpp_input_open(struct input_dev *dev) | ||
1016 | { | ||
1017 | struct hid_device *hid = input_get_drvdata(dev); | ||
1018 | |||
1019 | return hid_hw_open(hid); | ||
1020 | } | ||
1021 | |||
1022 | static void hidpp_input_close(struct input_dev *dev) | ||
1023 | { | ||
1024 | struct hid_device *hid = input_get_drvdata(dev); | ||
1025 | |||
1026 | hid_hw_close(hid); | ||
1027 | } | ||
1028 | |||
1029 | static struct input_dev *hidpp_allocate_input(struct hid_device *hdev) | ||
1030 | { | ||
1031 | struct input_dev *input_dev = devm_input_allocate_device(&hdev->dev); | ||
1032 | |||
1033 | if (!input_dev) | ||
1034 | return NULL; | ||
1035 | |||
1036 | input_set_drvdata(input_dev, hdev); | ||
1037 | input_dev->open = hidpp_input_open; | ||
1038 | input_dev->close = hidpp_input_close; | ||
1039 | |||
1040 | input_dev->name = hdev->name; | ||
1041 | input_dev->phys = hdev->phys; | ||
1042 | input_dev->uniq = hdev->uniq; | ||
1043 | input_dev->id.bustype = hdev->bus; | ||
1044 | input_dev->id.vendor = hdev->vendor; | ||
1045 | input_dev->id.product = hdev->product; | ||
1046 | input_dev->id.version = hdev->version; | ||
1047 | input_dev->dev.parent = &hdev->dev; | ||
1048 | |||
1049 | return input_dev; | ||
1050 | } | ||
1051 | |||
1052 | static void hidpp_connect_event(struct hidpp_device *hidpp) | ||
1053 | { | ||
1054 | struct hid_device *hdev = hidpp->hid_dev; | ||
1055 | int ret = 0; | ||
1056 | bool connected = atomic_read(&hidpp->connected); | ||
1057 | struct input_dev *input; | ||
1058 | char *name, *devm_name; | ||
1059 | |||
1060 | if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP) | ||
1061 | wtp_connect(hdev, connected); | ||
1062 | |||
1063 | if (!connected || hidpp->delayed_input) | ||
1064 | return; | ||
1065 | |||
1066 | if (!hidpp->protocol_major) { | ||
1067 | ret = !hidpp_is_connected(hidpp); | ||
1068 | if (ret) { | ||
1069 | hid_err(hdev, "Can not get the protocol version.\n"); | ||
1070 | return; | ||
1071 | } | ||
1072 | } | ||
1073 | |||
1074 | /* the device is already connected, we can ask for its name and | ||
1075 | * protocol */ | ||
1076 | hid_info(hdev, "HID++ %u.%u device connected.\n", | ||
1077 | hidpp->protocol_major, hidpp->protocol_minor); | ||
1078 | |||
1079 | input = hidpp_allocate_input(hdev); | ||
1080 | if (!input) { | ||
1081 | hid_err(hdev, "cannot allocate new input device: %d\n", ret); | ||
1082 | return; | ||
1083 | } | ||
1084 | |||
1085 | name = hidpp_get_device_name(hidpp); | ||
1086 | if (!name) { | ||
1087 | hid_err(hdev, "unable to retrieve the name of the device"); | ||
1088 | } else { | ||
1089 | devm_name = devm_kasprintf(&hdev->dev, GFP_KERNEL, "%s", name); | ||
1090 | if (devm_name) | ||
1091 | input->name = devm_name; | ||
1092 | kfree(name); | ||
1093 | } | ||
1094 | |||
1095 | hidpp_populate_input(hidpp, input, false); | ||
1096 | |||
1097 | ret = input_register_device(input); | ||
1098 | if (ret) | ||
1099 | input_free_device(input); | ||
1100 | |||
1101 | hidpp->delayed_input = input; | ||
1102 | } | ||
1103 | |||
1104 | static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id) | ||
1105 | { | ||
1106 | struct hidpp_device *hidpp; | ||
1107 | int ret; | ||
1108 | bool connected; | ||
1109 | unsigned int connect_mask = HID_CONNECT_DEFAULT; | ||
1110 | |||
1111 | hidpp = devm_kzalloc(&hdev->dev, sizeof(struct hidpp_device), | ||
1112 | GFP_KERNEL); | ||
1113 | if (!hidpp) | ||
1114 | return -ENOMEM; | ||
1115 | |||
1116 | hidpp->hid_dev = hdev; | ||
1117 | hid_set_drvdata(hdev, hidpp); | ||
1118 | |||
1119 | hidpp->quirks = id->driver_data; | ||
1120 | |||
1121 | if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP) { | ||
1122 | ret = wtp_allocate(hdev, id); | ||
1123 | if (ret) | ||
1124 | goto wtp_allocate_fail; | ||
1125 | } | ||
1126 | |||
1127 | INIT_WORK(&hidpp->work, delayed_work_cb); | ||
1128 | mutex_init(&hidpp->send_mutex); | ||
1129 | init_waitqueue_head(&hidpp->wait); | ||
1130 | |||
1131 | ret = hid_parse(hdev); | ||
1132 | if (ret) { | ||
1133 | hid_err(hdev, "%s:parse failed\n", __func__); | ||
1134 | goto hid_parse_fail; | ||
1135 | } | ||
1136 | |||
1137 | /* Allow incoming packets */ | ||
1138 | hid_device_io_start(hdev); | ||
1139 | |||
1140 | connected = hidpp_is_connected(hidpp); | ||
1141 | if (id->group != HID_GROUP_LOGITECH_DJ_DEVICE) { | ||
1142 | if (!connected) { | ||
1143 | hid_err(hdev, "Device not connected"); | ||
1144 | hid_device_io_stop(hdev); | ||
1145 | goto hid_parse_fail; | ||
1146 | } | ||
1147 | |||
1148 | hid_info(hdev, "HID++ %u.%u device connected.\n", | ||
1149 | hidpp->protocol_major, hidpp->protocol_minor); | ||
1150 | } | ||
1151 | |||
1152 | hidpp_overwrite_name(hdev, id->group == HID_GROUP_LOGITECH_DJ_DEVICE); | ||
1153 | atomic_set(&hidpp->connected, connected); | ||
1154 | |||
1155 | if (connected && (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP)) { | ||
1156 | ret = wtp_get_config(hidpp); | ||
1157 | if (ret) | ||
1158 | goto hid_parse_fail; | ||
1159 | } | ||
1160 | |||
1161 | /* Block incoming packets */ | ||
1162 | hid_device_io_stop(hdev); | ||
1163 | |||
1164 | if (hidpp->quirks & HIDPP_QUIRK_DELAYED_INIT) | ||
1165 | connect_mask &= ~HID_CONNECT_HIDINPUT; | ||
1166 | |||
1167 | /* Re-enable hidinput for multi-input devices */ | ||
1168 | if (hidpp->quirks & HIDPP_QUIRK_MULTI_INPUT) | ||
1169 | connect_mask |= HID_CONNECT_HIDINPUT; | ||
1170 | |||
1171 | ret = hid_hw_start(hdev, connect_mask); | ||
1172 | if (ret) { | ||
1173 | hid_err(hdev, "%s:hid_hw_start returned error\n", __func__); | ||
1174 | goto hid_hw_start_fail; | ||
1175 | } | ||
1176 | |||
1177 | if (hidpp->quirks & HIDPP_QUIRK_DELAYED_INIT) { | ||
1178 | /* Allow incoming packets */ | ||
1179 | hid_device_io_start(hdev); | ||
1180 | |||
1181 | hidpp_connect_event(hidpp); | ||
1182 | } | ||
1183 | |||
1184 | return ret; | ||
1185 | |||
1186 | hid_hw_start_fail: | ||
1187 | hid_parse_fail: | ||
1188 | cancel_work_sync(&hidpp->work); | ||
1189 | mutex_destroy(&hidpp->send_mutex); | ||
1190 | wtp_allocate_fail: | ||
1191 | hid_set_drvdata(hdev, NULL); | ||
1192 | return ret; | ||
1193 | } | ||
1194 | |||
1195 | static void hidpp_remove(struct hid_device *hdev) | ||
1196 | { | ||
1197 | struct hidpp_device *hidpp = hid_get_drvdata(hdev); | ||
1198 | |||
1199 | cancel_work_sync(&hidpp->work); | ||
1200 | mutex_destroy(&hidpp->send_mutex); | ||
1201 | hid_hw_stop(hdev); | ||
1202 | } | ||
1203 | |||
1204 | static const struct hid_device_id hidpp_devices[] = { | ||
1205 | { /* wireless touchpad */ | ||
1206 | HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, | ||
1207 | USB_VENDOR_ID_LOGITECH, 0x4011), | ||
1208 | .driver_data = HIDPP_QUIRK_CLASS_WTP | HIDPP_QUIRK_DELAYED_INIT | | ||
1209 | HIDPP_QUIRK_WTP_PHYSICAL_BUTTONS }, | ||
1210 | { /* wireless touchpad T650 */ | ||
1211 | HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, | ||
1212 | USB_VENDOR_ID_LOGITECH, 0x4101), | ||
1213 | .driver_data = HIDPP_QUIRK_CLASS_WTP | HIDPP_QUIRK_DELAYED_INIT }, | ||
1214 | { /* wireless touchpad T651 */ | ||
1215 | HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, | ||
1216 | USB_DEVICE_ID_LOGITECH_T651), | ||
1217 | .driver_data = HIDPP_QUIRK_CLASS_WTP }, | ||
1218 | { /* Keyboard TK820 */ | ||
1219 | HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, | ||
1220 | USB_VENDOR_ID_LOGITECH, 0x4102), | ||
1221 | .driver_data = HIDPP_QUIRK_DELAYED_INIT | HIDPP_QUIRK_MULTI_INPUT | | ||
1222 | HIDPP_QUIRK_CLASS_WTP }, | ||
1223 | |||
1224 | { HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, | ||
1225 | USB_VENDOR_ID_LOGITECH, HID_ANY_ID)}, | ||
1226 | {} | ||
1227 | }; | ||
1228 | |||
1229 | MODULE_DEVICE_TABLE(hid, hidpp_devices); | ||
1230 | |||
1231 | static struct hid_driver hidpp_driver = { | ||
1232 | .name = "logitech-hidpp-device", | ||
1233 | .id_table = hidpp_devices, | ||
1234 | .probe = hidpp_probe, | ||
1235 | .remove = hidpp_remove, | ||
1236 | .raw_event = hidpp_raw_event, | ||
1237 | .input_configured = hidpp_input_configured, | ||
1238 | .input_mapping = hidpp_input_mapping, | ||
1239 | }; | ||
1240 | |||
1241 | module_hid_driver(hidpp_driver); | ||