2 * HID driver for Logitech Wireless Touchpad device
4 * Copyright (c) 2011 Logitech (c)
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 * Should you need to contact me, the author, you can do so by e-mail send
23 * your message to Benjamin Tissoires <benjamin.tissoires at gmail com>
27 #include <linux/device.h>
28 #include <linux/hid.h>
29 #include <linux/module.h>
30 #include <linux/slab.h>
31 #include <linux/input/mt.h>
33 MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>");
34 MODULE_AUTHOR("Nestor Lopez Casado <nlopezcasad@logitech.com>");
35 MODULE_DESCRIPTION("Logitech Wireless Touchpad");
36 MODULE_LICENSE("GPL");
39 #include "hid-logitech-hidpp.h"
41 #define SOFTWARE_ID 0xB
43 #define ORIGIN_LOWER_LEFT 0x1
44 #define ORIGIN_LOWER_RIGHT 0x2
45 #define ORIGIN_UPPER_LEFT 0x3
46 #define ORIGIN_UPPER_RIGHT 0x4
47 #define ORIGIN_IS_HIGH(origin) ((origin - 1) & 2)
48 #define ORIGIN_IS_RIGHT(origin) ((origin - 1) & 1)
50 /* Converts a value in DPI to dots-per-millimeter */
51 #define DPI_TO_DPMM(dpi) (((dpi) * 5) / 127)
55 #define CONTACT_STATUS_RELEASED 0
56 #define CONTACT_STATUS_TOUCH 1
57 #define CONTACT_STATUS_HOVER 2
58 #define CONTACT_STATUS_RESERVED 3
61 #define BUTTON_RIGHT 1
62 #define BUTTON_MIDDLE 2
64 #define BUTTON_LEFT_MASK (1 << BUTTON_LEFT)
65 #define BUTTON_RIGHT_MASK (1 << BUTTON_RIGHT)
66 #define BUTTON_MIDDLE_MASK (1 << BUTTON_MIDDLE)
68 #define ARRAYSIZE(array) (sizeof(array) / sizeof(*(array)))
70 /* Supported Devices */
71 static const struct hid_device_id wtp_devices[] = {
72 {HID_DEVICE(BUS_DJ, USB_VENDOR_ID_LOGITECH, UNIFYING_DEVICE_ID_WIRELESS_TOUCHPAD) },
73 {HID_DEVICE(BUS_DJ, USB_VENDOR_ID_LOGITECH, UNIFYING_DEVICE_ID_WIRELESS_TOUCHPAD_T650) },
74 {HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_WIRELESS_TOUCHPAD_T651) },
77 MODULE_DEVICE_TABLE(hid, wtp_devices);
80 /* This struct represents a finger including location, pressure and
82 struct wtp_event_finger {
90 /* This struct represents a touch data message from a touchpad */
92 struct wtp_event_finger fingers[4];
94 /* bitmask of button states. 1=down, 0=up. */
97 /* bitmask of buttons included within this event */
100 /* true if this event includes finger data */
103 /* false if there are events following with more data,
104 true if this is the last one */
108 /* Struct describing the touch devices axis properties */
109 struct wtp_device_info {
118 u16 abs_min_pressure;
119 u16 abs_max_pressure;
126 /* Struct storing feature-specific information. Each feature_id
127 has methods assigned that process messages from this feature. */
132 int (*init)(struct hidpp_device *);
133 int (*probe)(struct hidpp_device *, struct wtp_device_info *);
134 int (*parse_feature_event)(struct wtp_data *, struct hidpp_report *,
136 int (*parse_other_event)(struct wtp_data *, struct hidpp_report *,
140 /* Structure containing device data */
142 struct input_dev *input;
144 struct wtp_device_info info;
146 /* the touch feature supported by this device */
147 struct wtp_feature feature;
149 /* keep track of which buttons are down */
152 /* For assigning tracking IDs for MT-B protocol. */
153 u16 next_tracking_id;
154 u16 current_slots_used; /* slots = device IDs. Bitmask. */
155 u16 prev_slots_used; /* slots = device IDs. Bitmask. */
157 u8 fingers_seen_this_frame;
160 /* Bit Operations Helper */
161 static u16 make_u16(u8 high, u8 low)
163 return (high << 8) | low;
165 static u8 low_nib(u8 val)
169 static u8 high_nib(u8 val)
173 static bool get_bit(u8 mask, u8 idx)
175 return mask & (1 << idx);
179 Helper methods for parsing mouse events. Some devices
180 use mouse events to report buttons.
183 #define GENERIC_EVENT_MOUSE 0x02
185 static void generic_parse_mouse_button(struct hidpp_report *report,
186 struct wtp_event *event) {
187 u8 *raw = (u8 *)report;
188 event->has_buttons = BUTTON_LEFT_MASK | BUTTON_RIGHT_MASK |
190 event->buttons = raw[1] & event->has_buttons;
194 TouchPadRawXY (TPRXY) Feature
197 #define TPRXY_FEATURE 0x6100
198 #define TPRXY_CMD_GET_TOUCHPAD_INFO (0x00 & SOFTWARE_ID)
199 #define TPRXY_CMD_GET_RAW_REPORT_STATE (0x10 & SOFTWARE_ID)
200 #define TPRXY_CMD_SET_RAW_REPORT_STATE (0x20 & SOFTWARE_ID)
201 #define TPRXY_EVENT_TOUCHPAD_RAW_TOUCH_POINTS 0x00
203 #define TPRXY_FORMAT_RAW 0x01
204 #define TPRXY_FORMAT_MOUSE_EXTENDED 0x02
206 #define TPRXY_DEFAULT_RES 1000 /* DPI */
208 #define TPRXY_SLOTS_PER_FRAME 2
210 /* Initialize TouchPadRawXY feature:
211 Set touchpad into raw mode (except for T651, which allows for raw touch
212 data appended to mouse events). */
213 static int tprxy_init(struct hidpp_device *hidpp_dev)
215 struct wtp_data *fd = hidpp_dev->driver_data;
216 struct hidpp_report response;
220 dbg_hid("%s\n", __func__);
222 if (hidpp_dev->hid_dev->product ==
223 USB_DEVICE_ID_WIRELESS_TOUCHPAD_T651) {
224 params = 0x4; /* enhanced sensitivity */
225 fd->feature.event_format = TPRXY_FORMAT_MOUSE_EXTENDED;
227 params = 0x5; /* enhanced sensitivity + raw */
228 fd->feature.event_format = TPRXY_FORMAT_RAW;
231 ret = hidpp_send_fap_command_sync(hidpp_dev, fd->feature.index,
232 TPRXY_CMD_SET_RAW_REPORT_STATE, ¶ms, 1, &response);
237 /* Probe TouchPadRawXY feature */
238 static int tprxy_probe(struct hidpp_device *hidpp_dev,
239 struct wtp_device_info *info)
241 struct wtp_data *fd = hidpp_dev->driver_data;
242 struct hidpp_report response;
245 u8 *params = (u8 *)response.fap.params;
247 dbg_hid("%s\n", __func__);
249 ret = hidpp_send_fap_command_sync(hidpp_dev, fd->feature.index,
250 TPRXY_CMD_GET_TOUCHPAD_INFO, NULL, 0, &response);
255 info->abs_max_x = make_u16(params[0], params[1]);
256 info->abs_max_y = make_u16(params[2], params[3]);
257 info->abs_max_pressure = params[5];
258 info->max_contacts = params[7];
259 info->origin = params[8];
261 res = make_u16(params[13], params[14]);
263 res = TPRXY_DEFAULT_RES;
264 info->abs_res_x = res;
265 info->abs_res_y = res;
269 /* Parse other events while using TouchPadRawXY feature:
270 Mouse events might still be received in the following cases:
271 - Touchpad with separate buttons send mouse events on click
272 - Touchpad using extended mouse events send touch data as
274 static int tprxy_parse_other_event(struct wtp_data *wtp,
275 struct hidpp_report *report,
276 struct wtp_event *event) {
278 u8 *buf = &report->rap.params[0];
280 dbg_hid("%s\n", __func__);
282 if (report->report_id != GENERIC_EVENT_MOUSE)
285 generic_parse_mouse_button(report, event);
287 if (wtp->feature.event_format != TPRXY_FORMAT_MOUSE_EXTENDED)
290 for (i = 0; i < TPRXY_SLOTS_PER_FRAME; ++i) {
291 struct wtp_event_finger *finger = &event->fingers[i];
292 u8 *raw = buf + (5 + i * 6);
293 u8 width = low_nib(raw[5]);
294 u8 height = high_nib(raw[5]);
296 finger->pressure = (width * width + height * height) / 2;
297 finger->status = finger->pressure > 0;
298 finger->abs_x = make_u16(raw[2], raw[1]);
299 finger->abs_y = make_u16(raw[4], raw[3]);
302 event->end_of_frame = !get_bit(buf[3], 7);
303 event->has_abs = true;
308 /* Parse TouchPadRawXY events */
309 static int tprxy_parse_feature_event(struct wtp_data *wtp,
310 struct hidpp_report *report,
311 struct wtp_event *event) {
313 u8 *buf = &report->rap.params[0];
314 u8 fingers_this_frame;
316 dbg_hid("%s\n", __func__);
318 if (wtp->feature.event_format != TPRXY_FORMAT_RAW)
321 for (i = 0; i < TPRXY_SLOTS_PER_FRAME; ++i) {
322 u8 *raw = buf + (2 + i * 7);
323 event->fingers[i].status = raw[0];
324 event->fingers[i].abs_x = make_u16(raw[0] & 0x3f, raw[1]);
325 event->fingers[i].abs_y = make_u16(raw[2] & 0x3f, raw[3]);
326 event->fingers[i].pressure = raw[5];
327 event->fingers[i].id = high_nib(raw[6]);
329 event->buttons = get_bit(buf[8], 2);
330 event->end_of_frame = get_bit(buf[8], 0);
332 /* For single event frames, the end of frame flag is implied. */
333 fingers_this_frame = low_nib(buf[15]);
334 if (fingers_this_frame <= TPRXY_SLOTS_PER_FRAME)
335 event->end_of_frame = true;
337 event->has_abs = true;
338 event->has_buttons = 0x1;
342 /* Array enumerating all supported hidpp features */
343 static struct wtp_feature wtp_supported_features[] = {
349 &tprxy_parse_feature_event,
350 &tprxy_parse_other_event
356 Common code for all devices/features
359 /* Report a single finger as input_events. This method will also assign
360 tracking ids to each new finger. */
361 static void wtp_process_event_finger(struct wtp_data *fd,
362 struct wtp_event_finger *finger)
364 int slot = finger->id - 1;
366 bool new_finger = !(fd->prev_slots_used & (1 << slot));
367 fd->current_slots_used |= 1 << slot;
368 fd->fingers_seen_this_frame++;
370 dbg_hid("Finger %d: (%d,%d,%d) s=%d\n",
377 input_mt_slot(fd->input, slot);
379 input_event(fd->input, EV_ABS, ABS_MT_TRACKING_ID,
380 fd->next_tracking_id++);
381 if (fd->next_tracking_id == 0xffff)
382 fd->next_tracking_id = 1;
384 input_mt_report_slot_state(fd->input, MT_TOOL_FINGER, 1);
385 input_event(fd->input, EV_ABS, ABS_MT_POSITION_X,
386 ORIGIN_IS_RIGHT(fd->info.origin) ?
387 fd->info.abs_max_x - finger->abs_x : finger->abs_x);
388 input_event(fd->input, EV_ABS, ABS_MT_POSITION_Y,
389 ORIGIN_IS_HIGH(fd->info.origin) ?
390 finger->abs_y : fd->info.abs_max_y - finger->abs_y);
391 input_event(fd->input, EV_ABS, ABS_MT_PRESSURE, finger->pressure);
394 /* Report an event as input_events */
395 static int wtp_process_event(struct hidpp_device *hidpp_dev,
396 struct wtp_event *event)
398 struct wtp_data *fd = (struct wtp_data *)hidpp_dev->driver_data;
401 if (!hidpp_dev->initialized)
405 if (event->has_buttons != 0) {
406 fd->buttons &= ~event->has_buttons;
407 fd->buttons |= event->buttons & event->has_buttons;
408 dbg_hid("Button: 0x%x\n", fd->buttons);
409 input_report_key(fd->input, BTN_LEFT,
410 get_bit(fd->buttons, BUTTON_LEFT));
411 input_report_key(fd->input, BTN_RIGHT,
412 get_bit(fd->buttons, BUTTON_RIGHT));
413 input_report_key(fd->input, BTN_MIDDLE,
414 get_bit(fd->buttons, BUTTON_MIDDLE));
417 /* sync now if there is no touch data following */
418 if (!event->has_abs) {
419 input_sync(fd->input);
420 return 1; /* we successfully consumed the event */
424 for (i = 0; i < ARRAYSIZE(event->fingers); i++) {
425 if (event->fingers[i].status != CONTACT_STATUS_RELEASED)
426 wtp_process_event_finger(fd, &event->fingers[i]);
429 /* update released fingers and sync */
430 if (event->end_of_frame) {
431 for (i = 0; i < SLOT_COUNT; i++) {
432 __u16 slot_mask = 1 << i;
433 bool released = (fd->prev_slots_used & slot_mask) &&
434 !(fd->current_slots_used & slot_mask);
437 dbg_hid("Finger %d: released\n", i);
438 input_mt_slot(fd->input, i);
439 input_event(fd->input, EV_ABS, ABS_MT_TRACKING_ID, -1);
440 input_mt_report_slot_state(fd->input, MT_TOOL_FINGER, 0);
442 input_mt_report_pointer_emulation(fd->input, true);
444 input_sync(fd->input);
446 fd->prev_slots_used = fd->current_slots_used;
447 fd->current_slots_used = 0;
448 fd->fingers_seen_this_frame = 0;
450 return 1; /* we successfully consumed the event */
453 /* dispatches events to feature event parsing methods and reports
454 the result as input_events */
455 static int wtp_hidpp_event_handler(struct hidpp_device *hidpp_device,
456 struct hidpp_report *report)
458 struct wtp_event event;
459 struct wtp_data *fd = (struct wtp_data *)hidpp_device->driver_data;
462 memset(&event, 0, sizeof(event));
464 if (report->report_id == REPORT_ID_HIDPP_LONG &&
465 report->rap.sub_id == fd->feature.index) {
466 ret = (*fd->feature.parse_feature_event)(fd, report, &event);
468 ret = (*fd->feature.parse_other_event)(fd, report, &event);
472 return wtp_process_event(hidpp_device, &event);
475 /* report device info */
476 static int wtp_input_mapping(struct hid_device *hdev, struct hid_input *hi,
477 struct hid_field *field, struct hid_usage *usage,
478 unsigned long **bit, int *max)
480 struct hidpp_device *hidpp_dev = hid_get_drvdata(hdev);
481 struct wtp_data *fd = (struct wtp_data *)hidpp_dev->driver_data;
482 struct input_dev *input = hi->input;
483 int res_x_mm, res_y_mm;
485 dbg_hid("%s:\n", __func__);
487 if ((usage->hid & HID_USAGE_PAGE) != HID_UP_BUTTON)
490 fd->input = hi->input;
492 __set_bit(BTN_TOUCH, input->keybit);
493 __set_bit(BTN_TOOL_FINGER, input->keybit);
494 __set_bit(BTN_TOOL_DOUBLETAP, input->keybit);
495 __set_bit(BTN_TOOL_TRIPLETAP, input->keybit);
496 __set_bit(BTN_TOOL_QUADTAP, input->keybit);
497 __set_bit(BTN_TOOL_QUINTTAP, input->keybit);
499 __set_bit(EV_ABS, input->evbit);
501 input_mt_init_slots(input, SLOT_COUNT);
503 input_set_capability(input, EV_KEY, BTN_TOUCH);
505 input_set_abs_params(input, ABS_MT_PRESSURE, 0, 255, 0, 0);
506 input_set_abs_params(input, ABS_MT_POSITION_X,
507 0, fd->info.abs_max_x, 0, 0);
508 input_set_abs_params(input, ABS_MT_POSITION_Y,
509 0, fd->info.abs_max_y, 0, 0);
510 input_set_abs_params(input, ABS_X, 0, fd->info.abs_max_x, 0, 0);
511 input_set_abs_params(input, ABS_Y, 0, fd->info.abs_max_y, 0, 0);
513 res_x_mm = DPI_TO_DPMM(fd->info.abs_res_x);
514 res_y_mm = DPI_TO_DPMM(fd->info.abs_res_y);
516 input_abs_set_res(input, ABS_MT_POSITION_X, res_x_mm);
517 input_abs_set_res(input, ABS_MT_POSITION_Y, res_y_mm);
518 input_abs_set_res(input, ABS_X, res_x_mm);
519 input_abs_set_res(input, ABS_Y, res_y_mm);
524 /* probes for all supported features and uses the first available
525 to initialize the device */
526 static int wtp_init_feature(struct hidpp_device *hidpp_device)
528 struct wtp_feature *feature = wtp_supported_features;
529 struct wtp_data *fd = (struct wtp_data *)hidpp_device->driver_data;
530 dbg_hid("%s\n", __func__);
532 while (feature->id) {
534 dbg_hid("Probing feature 0x%x\n", feature->id);
535 ret = hidpp_get_hidpp2_feature_index(hidpp_device,
542 if (feature->index != 0) {
543 dbg_hid("Feature found at index: %d\n", feature->index);
544 fd->feature = *feature;
545 ret = (*fd->feature.probe)(hidpp_device, &fd->info);
548 ret = (*fd->feature.init)(hidpp_device);
551 dbg_hid("unavailable feature 0x%x\n", feature->id);
555 /* no supported feature found on this device */
559 static void wtp_connect_change(struct hidpp_device *hidpp_dev, bool connected)
561 struct wtp_data *fd = (struct wtp_data *)hidpp_dev->driver_data;
562 dbg_hid("%s: connected:%d\n", __func__, connected);
563 if (connected && hidpp_dev->initialized && fd->feature.init)
564 (*fd->feature.init)(hidpp_dev);
567 static int wtp_probe(struct hid_device *hdev, const struct hid_device_id *id)
569 struct wtp_data *fd = NULL;
570 struct hidpp_device *hidpp_device = NULL;
572 struct hidpp_report response;
574 dbg_hid("%s\n", __func__);
576 hidpp_device = kzalloc(sizeof(struct hidpp_device), GFP_KERNEL);
578 hid_err(hdev, "cannot allocate hidpp_device\n");
580 goto hidpp_alloc_failed;
583 fd = kzalloc(sizeof(struct wtp_data), GFP_KERNEL);
585 hid_err(hdev, "cannot allocate wtp Touch data\n");
587 goto fd_alloc_failed;
589 fd->next_tracking_id = 1;
591 hidpp_device->driver_data = (void *)fd;
592 hid_set_drvdata(hdev, hidpp_device);
594 hidpp_device->connect_change = wtp_connect_change;
596 ret = hid_parse(hdev);
602 ret = hidpp_init(hidpp_device, hdev);
608 hid_device_io_start(hdev);
610 /* Get hid++ version number */
611 ret = hidpp_send_hidpp2_sync(hidpp_device, REPORT_ID_HIDPP_LONG,
616 dbg_hid("send root cmd returned: %d", ret);
621 dbg_hid("HID++ version: %d.%d\n", response.rap.params[0],
622 response.rap.params[1]);
624 /* TODO(adlr): Consider requiring a specific/minimum HID++ version. */
626 ret = wtp_init_feature(hidpp_device);
628 dbg_hid("wtp_init_feature returned: %d", ret);
633 hid_device_io_stop(hdev);
635 hidpp_device->raw_event = wtp_hidpp_event_handler;
637 ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
646 hid_set_drvdata(hdev, NULL);
654 static void wtp_remove(struct hid_device *hdev)
656 struct hidpp_device *hidpp_dev = hid_get_drvdata(hdev);
657 struct wtp_data *fd = hidpp_dev->driver_data;
658 dbg_hid("%s\n", __func__);
660 hidpp_remove(hidpp_dev);
663 hid_set_drvdata(hdev, NULL);
666 static struct hid_driver wtp_driver = {
668 .id_table = wtp_devices,
670 .remove = wtp_remove,
671 .input_mapping = wtp_input_mapping,
672 .raw_event = hidpp_raw_event,
675 static int __init wtp_init(void)
677 return hid_register_driver(&wtp_driver);
680 static void __exit wtp_exit(void)
682 hid_unregister_driver(&wtp_driver);
685 module_init(wtp_init);
686 module_exit(wtp_exit);