79e3aae5edb0f22500106f6511ae4b6a4bca8801
[cascardo/linux.git] / drivers / hid / hid-logitech-wtp.c
1 /*
2  *  HID driver for Logitech Wireless Touchpad device
3  *
4  *  Copyright (c) 2011 Logitech (c)
5  */
6
7 /*
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.
11
12  *
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.
17  *
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
21  *
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>
24  *
25  */
26
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>
32
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");
37
38 #include "hid-ids.h"
39 #include "hid-logitech-hidpp.h"
40
41 #define SOFTWARE_ID 0xB
42
43 #define CMD_TOUCHPAD_GET_RAW_INFO               0x01
44 #define CMD_TOUCHPAD_GET_RAW_REPORT_STATE       0x11
45 #define CMD_TOUCHPAD_SET_RAW_REPORT_STATE       0x21
46 #define WTP_RAW_XY_FEAT_ID                      0x6100
47 #define WTP_RAW_XY_EVENT_INDEX                  0
48
49 #define ORIGIN_LOWER_LEFT 0x1
50 #define ORIGIN_LOWER_RIGHT 0x2
51 #define ORIGIN_UPPER_LEFT 0x3
52 #define ORIGIN_UPPER_RIGHT 0x4
53
54 #define ORIGIN_IS_HIGH(origin) ((origin - 1) & 2)
55 #define ORIGIN_IS_RIGHT(origin) ((origin - 1) & 1)
56
57 /* Converts a value in DPI to dots-per-millimeter */
58 #define DPI_TO_DPMM(dpi) (((dpi) * 5) / 127)
59
60 #define SLOT_COUNT 16
61
62 /* The WTP touchpad doesn't supply a resolution, so we hardcode it in
63    this driver. */
64 #define WTP_RES 1000  /* DPI */
65
66 #define CONTACT_STATUS_RELEASED 0
67 #define CONTACT_STATUS_TOUCH 1
68 #define CONTACT_STATUS_HOVER 2
69 #define CONTACT_STATUS_RESERVED 3
70
71 /* These two structs represent a single raw data input message */
72 struct hidpp_touchpad_raw_xy_finger {
73         u8 contact_type;
74         u8 contact_status;
75         u16 x;
76         u16 y;
77         u8 z;
78         u8 area;
79         u8 finger_id;
80 };
81 struct hidpp_touchpad_raw_xy {
82         u16 timestamp;
83         struct hidpp_touchpad_raw_xy_finger fingers[2];
84         u8 fingers_this_frame;
85         bool proximity_detection:1;
86         bool mechanical_button:1;
87         bool spurious_flag:1;
88         bool end_of_frame:1;
89 };
90
91 struct wtp_data {
92         struct input_dev *input;
93
94         /* Properties of the device. Filled by hidpp_touchpad_get_raw_info() */
95         __u16 x_size, y_size;
96         __u8 origin;
97         __u8 z_range, area_range;
98         __u8 maxcontacts;
99         __u16 res;  /* points per inch */
100
101         /* Feature index of the raw data feature */
102         __u8 mt_feature_index;
103
104         /* For assigning tracking IDs for MT-B protocol. */
105         __u16 next_tracking_id;
106         __u16 current_slots_used;  /* slots = device IDs. Bitmask. */
107         __u16 prev_slots_used;  /* slots = device IDs. Bitmask. */
108 };
109
110 static void wtp_touch_event(struct wtp_data *fd,
111         struct hidpp_touchpad_raw_xy_finger *touch_report)
112 {
113         int slot = touch_report->finger_id - 1;
114
115         bool new_finger = !(fd->prev_slots_used & (1 << slot));
116         fd->current_slots_used |= 1 << slot;
117
118         input_mt_slot(fd->input, slot);
119         if (new_finger) {
120                 input_event(fd->input, EV_ABS, ABS_MT_TRACKING_ID,
121                                 fd->next_tracking_id++);
122                 if (fd->next_tracking_id == 0xffff)
123                         fd->next_tracking_id = 1;
124         }
125         input_mt_report_slot_state(fd->input, MT_TOOL_FINGER, 1);
126         input_event(fd->input, EV_ABS, ABS_MT_POSITION_X,
127                         ORIGIN_IS_RIGHT(fd->origin) ?
128                         fd->x_size - touch_report->x : touch_report->x);
129         input_event(fd->input, EV_ABS, ABS_MT_POSITION_Y,
130                         ORIGIN_IS_HIGH(fd->origin) ?
131                         touch_report->y : fd->y_size - touch_report->y);
132         input_event(fd->input, EV_ABS, ABS_MT_PRESSURE, touch_report->area);
133 }
134
135 static int wtp_touchpad_raw_xy_event(struct hidpp_device *hidpp_dev,
136                                 struct hidpp_touchpad_raw_xy *event)
137 {
138         struct wtp_data *fd = (struct wtp_data *)hidpp_dev->driver_data;
139         u8 finger_count = event->fingers_this_frame;
140
141         int i;
142
143         if (!hidpp_dev->initialized)
144                 return 0;
145
146         for (i = 0; i < 2; i++) {
147                 if (event->fingers[i].contact_status != CONTACT_STATUS_RELEASED)
148                         wtp_touch_event(fd, &event->fingers[i]);
149         }
150
151         if (event->end_of_frame || finger_count <= 2) {
152                 for (i = 0; i < SLOT_COUNT; i++) {
153                         __u16 slot_mask = 1 << i;
154                         bool released = (fd->prev_slots_used & slot_mask) &&
155                                 !(fd->current_slots_used & slot_mask);
156                         if (!released)
157                                 continue;
158                         input_mt_slot(fd->input, i);
159                         input_event(fd->input, EV_ABS, ABS_MT_TRACKING_ID, -1);
160                         input_mt_report_slot_state(fd->input, MT_TOOL_FINGER, 0);
161                 }
162                 input_mt_report_pointer_emulation(fd->input, true);
163                 input_report_key(fd->input, BTN_TOOL_FINGER,
164                                  finger_count == 1);
165                 input_report_key(fd->input, BTN_TOOL_DOUBLETAP,
166                                  finger_count == 2);
167                 input_report_key(fd->input, BTN_TOOL_TRIPLETAP,
168                                  finger_count == 3);
169                 input_report_key(fd->input, BTN_TOOL_QUADTAP,
170                                  finger_count == 4);
171                 input_report_key(fd->input, BTN_TOOL_QUINTTAP,
172                                  finger_count == 5);
173                 /* WTP Uses normal mouse reports for button state */
174                 if (hidpp_dev->hid_dev->product !=
175                         UNIFYING_DEVICE_ID_WIRELESS_TOUCHPAD)
176                         input_report_key(fd->input, BTN_LEFT,
177                                          event->mechanical_button);
178                 input_sync(fd->input);
179
180                 fd->prev_slots_used = fd->current_slots_used;
181                 fd->current_slots_used = 0;
182         }
183         return 1;
184 }
185
186
187 static int hidpp_touchpad_raw_xy_event(struct hidpp_device *hidpp_device,
188                 struct hidpp_report *hidpp_report)
189 {
190         u8 *buf = &hidpp_report->rap.params[0];  /* 4 strips off the DJ header */
191         struct wtp_data *fd = (struct wtp_data *)hidpp_device->driver_data;
192
193         /* Parse the message into a more convenient struct */
194         struct hidpp_touchpad_raw_xy raw_xy = {
195                 (buf[0] << 8) | buf[1],  /* Timestamp */
196                 { {
197                         buf[2] >> 6,  /* Contact type */
198                         buf[4] >> 6,  /* Contact status */
199                         ((buf[2] & 0x3f) << 8) | buf[3],  /* X */
200                         ((buf[4] & 0x3f) << 8) | buf[5],  /* Y */
201                         buf[6],  /* Z/Force */
202                         buf[7],  /* Area */
203                         buf[8] >> 4  /* Finger ID */
204                 }, {
205                         buf[9] >> 6,  /* Contact type */
206                         buf[11] >> 6,  /* Contact status */
207                         ((buf[9] & 0x3f) << 8) | buf[10],  /* X */
208                         ((buf[11] & 0x3f) << 8) | buf[12],  /* Y */
209                         buf[13],  /* Z/Force */
210                         buf[14],  /* Area */
211                         buf[15] >> 4  /* Finger ID */
212                 } },
213                 buf[15] & 0xf,  /* Fingers this frame */
214                 (buf[8] & (1 << 3)) != 0,  /* Proximity detection */
215                 (buf[8] & (1 << 2)) != 0,  /* Mechanical button */
216                 (buf[8] & (1 << 1)) != 0,  /* Spurious flag */
217                 (buf[8] & (1 << 0)) != 0,  /* End-of-frame */
218         };
219
220         /* Ensure we get the proper raw data report here. We do this after
221            the parsing above to avoid mixed declarations and code. */
222         if (hidpp_report->report_id != REPORT_ID_HIDPP_LONG ||
223                 hidpp_report->rap.sub_id != fd->mt_feature_index ||
224                 (hidpp_report->rap.reg_address >> 4) != WTP_RAW_XY_EVENT_INDEX) {
225                 dbg_hid("Unhandled event type\n");
226                 return 0;
227         }
228
229         dbg_hid("EVT: %d {ty: %d, st: %d, (%d,%d,%d,%d) id:%d} {ty: %d, st: %d, (%d,%d,%d,%d) id:%d} cnt:%d pr:%d but:%d sf:%d eof:%d\n",
230                 raw_xy.timestamp,
231                 raw_xy.fingers[0].contact_type,
232                 raw_xy.fingers[0].contact_status,
233                 raw_xy.fingers[0].x,
234                 raw_xy.fingers[0].y,
235                 raw_xy.fingers[0].z,
236                 raw_xy.fingers[0].area,
237                 raw_xy.fingers[0].finger_id,
238                 raw_xy.fingers[1].contact_type,
239                 raw_xy.fingers[1].contact_status,
240                 raw_xy.fingers[1].x,
241                 raw_xy.fingers[1].y,
242                 raw_xy.fingers[1].z,
243                 raw_xy.fingers[1].area,
244                 raw_xy.fingers[1].finger_id,
245                 raw_xy.fingers_this_frame,
246                 raw_xy.proximity_detection,
247                 raw_xy.mechanical_button,
248                 raw_xy.spurious_flag,
249                 raw_xy.end_of_frame);
250         return wtp_touchpad_raw_xy_event(hidpp_device, &raw_xy);
251 }
252
253 static int hidpp_touchpad_get_raw_info(struct hidpp_device *hidpp_dev)
254 {
255         struct wtp_data *fd = hidpp_dev->driver_data;
256         struct hidpp_report response;
257         int ret;
258         u8 *params = (u8 *)response.fap.params;
259
260         ret = hidpp_send_fap_command_sync(hidpp_dev, fd->mt_feature_index,
261                         CMD_TOUCHPAD_GET_RAW_INFO, NULL, 0, &response);
262
263         if (ret)
264                 return -ret;
265
266         fd->x_size = (params[0] << 8) | params[1];
267         fd->y_size = (params[2] << 8) | params[3];
268         fd->z_range = params[4];
269         fd->area_range = params[5];
270         fd->maxcontacts = params[7];
271         fd->origin = params[8];
272         fd->res = (params[13] << 8) | params[14];
273         if (!fd->res)
274                 fd->res = WTP_RES;
275
276         return ret;
277 }
278
279 static int hidpp_touchpad_set_raw_report_state(struct hidpp_device *hidpp_dev)
280 {
281         struct wtp_data *fd = hidpp_dev->driver_data;
282         struct hidpp_report response;
283         int ret;
284
285         /* Params:
286                 0x01 - enable raw
287                 0x02 - 16bit Z, no area
288                 0x04 - enhanced sensitivity
289                 0x08 - width, height instead of area
290                 0x10 - send raw + gestures (degrades smoothness)
291                 remaining bits - reserved */
292         u8 params = 0x5;
293
294         ret = hidpp_send_fap_command_sync(hidpp_dev, fd->mt_feature_index,
295                 CMD_TOUCHPAD_SET_RAW_REPORT_STATE, &params, 1, &response);
296
297         if (ret)
298                 return -ret;
299
300         return ret;
301 }
302
303 static int wtp_input_mapping(struct hid_device *hdev, struct hid_input *hi,
304                 struct hid_field *field, struct hid_usage *usage,
305                 unsigned long **bit, int *max)
306 {
307         struct hidpp_device *hidpp_dev = hid_get_drvdata(hdev);
308         struct wtp_data *fd = (struct wtp_data *)hidpp_dev->driver_data;
309         struct input_dev *input = hi->input;
310         int res_mm;
311
312         dbg_hid("%s:\n", __func__);
313
314         if ((usage->hid & HID_USAGE_PAGE) != HID_UP_BUTTON)
315                 return -1;
316
317         fd->input = hi->input;
318
319         __set_bit(BTN_TOUCH, input->keybit);
320         __set_bit(BTN_TOOL_FINGER, input->keybit);
321         __set_bit(BTN_TOOL_DOUBLETAP, input->keybit);
322         __set_bit(BTN_TOOL_TRIPLETAP, input->keybit);
323         __set_bit(BTN_TOOL_QUADTAP, input->keybit);
324         __set_bit(BTN_TOOL_QUINTTAP, input->keybit);
325
326         __set_bit(EV_ABS, input->evbit);
327
328         input_mt_init_slots(input, SLOT_COUNT);
329
330         input_set_capability(input, EV_KEY, BTN_TOUCH);
331
332         input_set_abs_params(input, ABS_MT_PRESSURE, 0, 255, 0, 0);
333         input_set_abs_params(input, ABS_MT_POSITION_X, 0, fd->x_size, 0, 0);
334         input_set_abs_params(input, ABS_MT_POSITION_Y, 0, fd->y_size, 0, 0);
335         input_set_abs_params(input, ABS_X, 0, fd->x_size, 0, 0);
336         input_set_abs_params(input, ABS_Y, 0, fd->y_size, 0, 0);
337
338         res_mm = DPI_TO_DPMM(fd->res);
339
340         input_abs_set_res(input, ABS_MT_POSITION_X, res_mm);
341         input_abs_set_res(input, ABS_MT_POSITION_Y, res_mm);
342         input_abs_set_res(input, ABS_X, res_mm);
343         input_abs_set_res(input, ABS_Y, res_mm);
344
345         return 0;
346 }
347
348 static void wtp_connect_change(struct hidpp_device *hidpp_dev, bool connected)
349 {
350         dbg_hid("%s: connected:%d\n", __func__, connected);
351         if (connected && hidpp_dev->initialized)
352                 hidpp_touchpad_set_raw_report_state(hidpp_dev);
353 }
354
355 static int wtp_device_init(struct hidpp_device *hidpp_dev)
356 {
357         int ret;
358
359         dbg_hid("%s\n", __func__);
360
361         ret = hidpp_touchpad_set_raw_report_state(hidpp_dev);
362
363         if (ret) {
364                 hid_err(hidpp_dev->hid_dev, "unable to set to raw report mode. "
365                         "The device may not be in range.\n");
366                 return ret;
367         }
368
369         ret = hidpp_touchpad_get_raw_info(hidpp_dev);
370         return ret;
371 }
372
373 static int wtp_probe(struct hid_device *hdev, const struct hid_device_id *id)
374 {
375         struct wtp_data *fd = NULL;
376         struct hidpp_device *hidpp_device = NULL;
377         int ret;
378         struct hidpp_report response;
379
380         dbg_hid("%s\n", __func__);
381
382         hidpp_device = kzalloc(sizeof(struct hidpp_device), GFP_KERNEL);
383         if (!hidpp_device) {
384                 hid_err(hdev, "cannot allocate hidpp_device\n");
385                 ret = -ENOMEM;
386                 goto hidpp_alloc_failed;
387         }
388
389         fd = kzalloc(sizeof(struct wtp_data), GFP_KERNEL);
390         if (!fd) {
391                 hid_err(hdev, "cannot allocate wtp Touch data\n");
392                 ret = -ENOMEM;
393                 goto fd_alloc_failed;
394         }
395         fd->next_tracking_id = 1;
396
397         hidpp_device->driver_data = (void *)fd;
398         hid_set_drvdata(hdev, hidpp_device);
399
400         hidpp_device->connect_change = wtp_connect_change;
401
402         ret = hid_parse(hdev);
403         if (ret) {
404                 ret = -ENODEV;
405                 goto failed;
406         }
407
408         ret = hidpp_init(hidpp_device, hdev);
409         if (ret) {
410                 ret = -ENODEV;
411                 goto failed;
412         }
413
414         hid_device_io_start(hdev);
415
416         /* Get hid++ version number */
417         ret = hidpp_send_hidpp2_sync(hidpp_device, REPORT_ID_HIDPP_SHORT,
418                                         0, 1,
419                                         SOFTWARE_ID,
420                                         NULL, 0, &response);
421         if (ret) {
422                 dbg_hid("send root cmd returned: %d", ret);
423                 ret = -ENODEV;
424                 goto failed;
425         }
426
427         dbg_hid("HID++ version: %d.%d\n", response.rap.params[0],
428                 response.rap.params[1]);
429
430         /* TODO(adlr): Consider requiring a specific/minimum HID++ version. */
431
432         ret = hidpp_get_hidpp2_feature_index(hidpp_device,
433                                                 SOFTWARE_ID,
434                                                 WTP_RAW_XY_FEAT_ID,
435                                                 &fd->mt_feature_index);
436         if (ret) {
437                 dbg_hid("Get raw_xy feature idx failed: %d", ret);
438                 ret = -ENODEV;
439                 goto failed;
440         }
441
442         wtp_device_init(hidpp_device);
443
444         hid_device_io_stop(hdev);
445
446         hidpp_device->raw_event = hidpp_touchpad_raw_xy_event;
447
448         ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
449         if (ret) {
450                 ret = -ENODEV;
451                 goto failed;
452         }
453
454         return 0;
455
456 failed:
457         hid_set_drvdata(hdev, NULL);
458         kfree(fd);
459 fd_alloc_failed:
460         kfree(hidpp_device);
461 hidpp_alloc_failed:
462         return ret;
463 }
464
465 static void wtp_remove(struct hid_device *hdev)
466 {
467         struct hidpp_device *hidpp_dev = hid_get_drvdata(hdev);
468         struct wtp_data *fd = hidpp_dev->driver_data;
469         dbg_hid("%s\n", __func__);
470         hid_hw_stop(hdev);
471         hidpp_remove(hidpp_dev);
472         kfree(fd);
473         kfree(hidpp_dev);
474         hid_set_drvdata(hdev, NULL);
475 }
476
477 static const struct hid_device_id wtp_devices[] = {
478         {HID_DEVICE(BUS_DJ, USB_VENDOR_ID_LOGITECH, UNIFYING_DEVICE_ID_WIRELESS_TOUCHPAD) },
479         {HID_DEVICE(BUS_DJ, USB_VENDOR_ID_LOGITECH, UNIFYING_DEVICE_ID_WIRELESS_TOUCHPAD_T650) },
480         { }
481 };
482 MODULE_DEVICE_TABLE(hid, wtp_devices);
483
484 static struct hid_driver wtp_driver = {
485         .name = "wtp-touch",
486         .id_table = wtp_devices,
487         .probe = wtp_probe,
488         .remove = wtp_remove,
489         .input_mapping = wtp_input_mapping,
490         .raw_event = hidpp_raw_event,
491 };
492
493 static int __init wtp_init(void)
494 {
495         return hid_register_driver(&wtp_driver);
496 }
497
498 static void __exit wtp_exit(void)
499 {
500         hid_unregister_driver(&wtp_driver);
501 }
502
503 module_init(wtp_init);
504 module_exit(wtp_exit);