blob: 88ea390c10ad4a04bc8be43f3af848539538e7f5 [file] [log] [blame]
Bastien Nocera0edffe62016-11-15 13:02:05 +01001/*
2 * HID driver for THQ PS3 uDraw tablet
3 *
4 * Copyright (C) 2016 Red Hat Inc. All Rights Reserved
5 *
6 * This software is licensed under the terms of the GNU General Public
7 * License version 2, as published by the Free Software Foundation, and
8 * may be copied, distributed, and modified under those terms.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16#include <linux/device.h>
17#include <linux/hid.h>
18#include <linux/module.h>
19#include "hid-ids.h"
20
21MODULE_AUTHOR("Bastien Nocera <hadess@hadess.net>");
22MODULE_DESCRIPTION("PS3 uDraw tablet driver");
23MODULE_LICENSE("GPL");
24
25/*
26 * Protocol information from:
27 * http://brandonw.net/udraw/
28 * and the source code of:
29 * https://vvvv.org/contribution/udraw-hid
30 */
31
32/*
33 * The device is setup with multiple input devices:
34 * - the touch area which works as a touchpad
35 * - the tablet area which works as a touchpad/drawing tablet
36 * - a joypad with a d-pad, and 7 buttons
37 * - an accelerometer device
38 */
39
40enum {
41 TOUCH_NONE,
42 TOUCH_PEN,
43 TOUCH_FINGER,
44 TOUCH_TWOFINGER
45};
46
47enum {
48 AXIS_X,
49 AXIS_Y,
50 AXIS_Z
51};
52
53/*
54 * Accelerometer min/max values
55 * in order, X, Y and Z
56 */
Jiri Kosina9c5dcd72016-11-15 14:23:17 +010057static struct {
Bastien Nocera0edffe62016-11-15 13:02:05 +010058 int min;
59 int max;
60} accel_limits[] = {
61 [AXIS_X] = { 490, 534 },
62 [AXIS_Y] = { 490, 534 },
63 [AXIS_Z] = { 492, 536 }
64};
65
66#define DEVICE_NAME "THQ uDraw Game Tablet for PS3"
67/* resolution in pixels */
68#define RES_X 1920
69#define RES_Y 1080
70/* size in mm */
71#define WIDTH 160
72#define HEIGHT 90
73#define PRESSURE_OFFSET 113
74#define MAX_PRESSURE (255 - PRESSURE_OFFSET)
75
76struct udraw {
77 struct input_dev *joy_input_dev;
78 struct input_dev *touch_input_dev;
79 struct input_dev *pen_input_dev;
80 struct input_dev *accel_input_dev;
81 struct hid_device *hdev;
82
83 /*
84 * The device's two-finger support is pretty unreliable, as
85 * the device could report a single touch when the two fingers
86 * are too close together, and the distance between fingers, even
87 * though reported is not in the same unit as the touches.
88 *
89 * We'll make do without it, and try to report the first touch
90 * as reliably as possible.
91 */
92 int last_one_finger_x;
93 int last_one_finger_y;
94 int last_two_finger_x;
95 int last_two_finger_y;
96};
97
98static int clamp_accel(int axis, int offset)
99{
100 axis = clamp(axis,
101 accel_limits[offset].min,
102 accel_limits[offset].max);
103 axis = (axis - accel_limits[offset].min) /
104 ((accel_limits[offset].max -
105 accel_limits[offset].min) * 0xFF);
106 return axis;
107}
108
109static int udraw_raw_event(struct hid_device *hdev, struct hid_report *report,
110 u8 *data, int len)
111{
112 struct udraw *udraw = hid_get_drvdata(hdev);
113 int touch;
114 int x, y, z;
115
116 if (len != 27)
117 return 0;
118
119 if (data[11] == 0x00)
120 touch = TOUCH_NONE;
121 else if (data[11] == 0x40)
122 touch = TOUCH_PEN;
123 else if (data[11] == 0x80)
124 touch = TOUCH_FINGER;
125 else
126 touch = TOUCH_TWOFINGER;
127
128 /* joypad */
129 input_report_key(udraw->joy_input_dev, BTN_WEST, data[0] & 1);
130 input_report_key(udraw->joy_input_dev, BTN_SOUTH, !!(data[0] & 2));
131 input_report_key(udraw->joy_input_dev, BTN_EAST, !!(data[0] & 4));
132 input_report_key(udraw->joy_input_dev, BTN_NORTH, !!(data[0] & 8));
133
134 input_report_key(udraw->joy_input_dev, BTN_SELECT, !!(data[1] & 1));
135 input_report_key(udraw->joy_input_dev, BTN_START, !!(data[1] & 2));
136 input_report_key(udraw->joy_input_dev, BTN_MODE, !!(data[1] & 16));
137
138 x = y = 0;
139 switch (data[2]) {
140 case 0x0:
141 y = -127;
142 break;
143 case 0x1:
144 y = -127;
145 x = 127;
146 break;
147 case 0x2:
148 x = 127;
149 break;
150 case 0x3:
151 y = 127;
152 x = 127;
153 break;
154 case 0x4:
155 y = 127;
156 break;
157 case 0x5:
158 y = 127;
159 x = -127;
160 break;
161 case 0x6:
162 x = -127;
163 break;
164 case 0x7:
165 y = -127;
166 x = -127;
167 break;
168 default:
169 break;
170 }
171
172 input_report_abs(udraw->joy_input_dev, ABS_X, x);
173 input_report_abs(udraw->joy_input_dev, ABS_Y, y);
174
175 input_sync(udraw->joy_input_dev);
176
177 /* For pen and touchpad */
178 x = y = 0;
179 if (touch != TOUCH_NONE) {
180 if (data[15] != 0x0F)
181 x = data[15] * 256 + data[17];
182 if (data[16] != 0x0F)
183 y = data[16] * 256 + data[18];
184 }
185
186 if (touch == TOUCH_FINGER) {
187 /* Save the last one-finger touch */
188 udraw->last_one_finger_x = x;
189 udraw->last_one_finger_y = y;
190 udraw->last_two_finger_x = -1;
191 udraw->last_two_finger_y = -1;
192 } else if (touch == TOUCH_TWOFINGER) {
193 /*
194 * We have a problem because x/y is the one for the
195 * second finger but we want the first finger given
196 * to user-space otherwise it'll look as if it jumped.
197 *
198 * See the udraw struct definition for why this was
199 * implemented this way.
200 */
201 if (udraw->last_two_finger_x == -1) {
202 /* Save the position of the 2nd finger */
203 udraw->last_two_finger_x = x;
204 udraw->last_two_finger_y = y;
205
206 x = udraw->last_one_finger_x;
207 y = udraw->last_one_finger_y;
208 } else {
209 /*
210 * Offset the 2-finger coords using the
211 * saved data from the first finger
212 */
213 x = x - (udraw->last_two_finger_x
214 - udraw->last_one_finger_x);
215 y = y - (udraw->last_two_finger_y
216 - udraw->last_one_finger_y);
217 }
218 }
219
220 /* touchpad */
221 if (touch == TOUCH_FINGER || touch == TOUCH_TWOFINGER) {
222 input_report_key(udraw->touch_input_dev, BTN_TOUCH, 1);
223 input_report_key(udraw->touch_input_dev, BTN_TOOL_FINGER,
224 touch == TOUCH_FINGER);
225 input_report_key(udraw->touch_input_dev, BTN_TOOL_DOUBLETAP,
226 touch == TOUCH_TWOFINGER);
227
228 input_report_abs(udraw->touch_input_dev, ABS_X, x);
229 input_report_abs(udraw->touch_input_dev, ABS_Y, y);
230 } else {
231 input_report_key(udraw->touch_input_dev, BTN_TOUCH, 0);
232 input_report_key(udraw->touch_input_dev, BTN_TOOL_FINGER, 0);
233 input_report_key(udraw->touch_input_dev, BTN_TOOL_DOUBLETAP, 0);
234 }
235 input_sync(udraw->touch_input_dev);
236
237 /* pen */
238 if (touch == TOUCH_PEN) {
239 int level;
240
241 level = clamp(data[13] - PRESSURE_OFFSET,
242 0, MAX_PRESSURE);
243
244 input_report_key(udraw->pen_input_dev, BTN_TOUCH, (level != 0));
245 input_report_key(udraw->pen_input_dev, BTN_TOOL_PEN, 1);
246 input_report_abs(udraw->pen_input_dev, ABS_PRESSURE, level);
247 input_report_abs(udraw->pen_input_dev, ABS_X, x);
248 input_report_abs(udraw->pen_input_dev, ABS_Y, y);
249 } else {
250 input_report_key(udraw->pen_input_dev, BTN_TOUCH, 0);
251 input_report_key(udraw->pen_input_dev, BTN_TOOL_PEN, 0);
252 input_report_abs(udraw->pen_input_dev, ABS_PRESSURE, 0);
253 }
254 input_sync(udraw->pen_input_dev);
255
256 /* accel */
257 x = (data[19] + (data[20] << 8));
258 x = clamp_accel(x, AXIS_X);
259 y = (data[21] + (data[22] << 8));
260 y = clamp_accel(y, AXIS_Y);
261 z = (data[23] + (data[24] << 8));
262 z = clamp_accel(z, AXIS_Z);
263 input_report_abs(udraw->accel_input_dev, ABS_X, x);
264 input_report_abs(udraw->accel_input_dev, ABS_Y, y);
265 input_report_abs(udraw->accel_input_dev, ABS_Z, z);
266 input_sync(udraw->accel_input_dev);
267
268 /* let hidraw and hiddev handle the report */
269 return 0;
270}
271
272static int udraw_open(struct input_dev *dev)
273{
274 struct udraw *udraw = input_get_drvdata(dev);
275
276 return hid_hw_open(udraw->hdev);
277}
278
279static void udraw_close(struct input_dev *dev)
280{
281 struct udraw *udraw = input_get_drvdata(dev);
282
283 hid_hw_close(udraw->hdev);
284}
285
286static struct input_dev *allocate_and_setup(struct hid_device *hdev,
287 const char *name)
288{
289 struct input_dev *input_dev;
290
291 input_dev = devm_input_allocate_device(&hdev->dev);
292 if (!input_dev)
293 return NULL;
294
295 input_dev->name = name;
296 input_dev->phys = hdev->phys;
297 input_dev->dev.parent = &hdev->dev;
298 input_dev->open = udraw_open;
299 input_dev->close = udraw_close;
300 input_dev->uniq = hdev->uniq;
301 input_dev->id.bustype = hdev->bus;
302 input_dev->id.vendor = hdev->vendor;
303 input_dev->id.product = hdev->product;
304 input_dev->id.version = hdev->version;
305 input_set_drvdata(input_dev, hid_get_drvdata(hdev));
306
307 return input_dev;
308}
309
310static bool udraw_setup_touch(struct udraw *udraw,
311 struct hid_device *hdev)
312{
313 struct input_dev *input_dev;
314
315 input_dev = allocate_and_setup(hdev, DEVICE_NAME " Touchpad");
316 if (!input_dev)
317 return false;
318
319 input_dev->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY);
320
321 input_set_abs_params(input_dev, ABS_X, 0, RES_X, 1, 0);
322 input_abs_set_res(input_dev, ABS_X, RES_X / WIDTH);
323 input_set_abs_params(input_dev, ABS_Y, 0, RES_Y, 1, 0);
324 input_abs_set_res(input_dev, ABS_Y, RES_Y / HEIGHT);
325
326 set_bit(BTN_TOUCH, input_dev->keybit);
327 set_bit(BTN_TOOL_FINGER, input_dev->keybit);
328 set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
329
330 set_bit(INPUT_PROP_POINTER, input_dev->propbit);
331
332 udraw->touch_input_dev = input_dev;
333
334 return true;
335}
336
337static bool udraw_setup_pen(struct udraw *udraw,
338 struct hid_device *hdev)
339{
340 struct input_dev *input_dev;
341
342 input_dev = allocate_and_setup(hdev, DEVICE_NAME " Pen");
343 if (!input_dev)
344 return false;
345
346 input_dev->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY);
347
348 input_set_abs_params(input_dev, ABS_X, 0, RES_X, 1, 0);
349 input_abs_set_res(input_dev, ABS_X, RES_X / WIDTH);
350 input_set_abs_params(input_dev, ABS_Y, 0, RES_Y, 1, 0);
351 input_abs_set_res(input_dev, ABS_Y, RES_Y / HEIGHT);
352 input_set_abs_params(input_dev, ABS_PRESSURE,
353 0, MAX_PRESSURE, 0, 0);
354
355 set_bit(BTN_TOUCH, input_dev->keybit);
356 set_bit(BTN_TOOL_PEN, input_dev->keybit);
357
358 set_bit(INPUT_PROP_POINTER, input_dev->propbit);
359
360 udraw->pen_input_dev = input_dev;
361
362 return true;
363}
364
365static bool udraw_setup_accel(struct udraw *udraw,
366 struct hid_device *hdev)
367{
368 struct input_dev *input_dev;
369
370 input_dev = allocate_and_setup(hdev, DEVICE_NAME " Accelerometer");
371 if (!input_dev)
372 return false;
373
374 input_dev->evbit[0] = BIT(EV_ABS);
375
376 /* 1G accel is reported as ~256, so clamp to 2G */
377 input_set_abs_params(input_dev, ABS_X, -512, 512, 0, 0);
378 input_set_abs_params(input_dev, ABS_Y, -512, 512, 0, 0);
379 input_set_abs_params(input_dev, ABS_Z, -512, 512, 0, 0);
380
381 set_bit(INPUT_PROP_ACCELEROMETER, input_dev->propbit);
382
383 udraw->accel_input_dev = input_dev;
384
385 return true;
386}
387
388static bool udraw_setup_joypad(struct udraw *udraw,
389 struct hid_device *hdev)
390{
391 struct input_dev *input_dev;
392
393 input_dev = allocate_and_setup(hdev, DEVICE_NAME " Joypad");
394 if (!input_dev)
395 return false;
396
397 input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
398
399 set_bit(BTN_SOUTH, input_dev->keybit);
400 set_bit(BTN_NORTH, input_dev->keybit);
401 set_bit(BTN_EAST, input_dev->keybit);
402 set_bit(BTN_WEST, input_dev->keybit);
403 set_bit(BTN_SELECT, input_dev->keybit);
404 set_bit(BTN_START, input_dev->keybit);
405 set_bit(BTN_MODE, input_dev->keybit);
406
407 input_set_abs_params(input_dev, ABS_X, -127, 127, 0, 0);
408 input_set_abs_params(input_dev, ABS_Y, -127, 127, 0, 0);
409
410 udraw->joy_input_dev = input_dev;
411
412 return true;
413}
414
415static int udraw_probe(struct hid_device *hdev, const struct hid_device_id *id)
416{
417 struct udraw *udraw;
418 int ret;
419
420 udraw = devm_kzalloc(&hdev->dev, sizeof(struct udraw), GFP_KERNEL);
421 if (!udraw)
422 return -ENOMEM;
423
424 udraw->hdev = hdev;
425 udraw->last_two_finger_x = -1;
426 udraw->last_two_finger_y = -1;
427
428 hid_set_drvdata(hdev, udraw);
429
430 ret = hid_parse(hdev);
431 if (ret) {
432 hid_err(hdev, "parse failed\n");
433 return ret;
434 }
435
436 if (!udraw_setup_joypad(udraw, hdev) ||
437 !udraw_setup_touch(udraw, hdev) ||
438 !udraw_setup_pen(udraw, hdev) ||
439 !udraw_setup_accel(udraw, hdev)) {
440 hid_err(hdev, "could not allocate interfaces\n");
441 return -ENOMEM;
442 }
443
444 ret = input_register_device(udraw->joy_input_dev) ||
445 input_register_device(udraw->touch_input_dev) ||
446 input_register_device(udraw->pen_input_dev) ||
447 input_register_device(udraw->accel_input_dev);
448 if (ret) {
449 hid_err(hdev, "failed to register interfaces\n");
450 return ret;
451 }
452
453 ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW | HID_CONNECT_DRIVER);
454 if (ret) {
455 hid_err(hdev, "hw start failed\n");
456 return ret;
457 }
458
459 return 0;
460}
461
462static const struct hid_device_id udraw_devices[] = {
463 { HID_USB_DEVICE(USB_VENDOR_ID_THQ, USB_DEVICE_ID_THQ_PS3_UDRAW) },
464 { }
465};
466MODULE_DEVICE_TABLE(hid, udraw_devices);
467
468static struct hid_driver udraw_driver = {
469 .name = "hid-udraw",
470 .id_table = udraw_devices,
471 .raw_event = udraw_raw_event,
472 .probe = udraw_probe,
473};
474module_hid_driver(udraw_driver);