xref: /openbmc/linux/drivers/hid/hid-udraw-ps3.c (revision 791d3ef2)
1 /*
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 
21 MODULE_AUTHOR("Bastien Nocera <hadess@hadess.net>");
22 MODULE_DESCRIPTION("PS3 uDraw tablet driver");
23 MODULE_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 
40 enum {
41 	TOUCH_NONE,
42 	TOUCH_PEN,
43 	TOUCH_FINGER,
44 	TOUCH_TWOFINGER
45 };
46 
47 enum {
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  */
57 static struct {
58 	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 
76 struct 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 
98 static 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 
109 static 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 
272 static 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 
279 static 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 
286 static 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 
310 static 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 
337 static 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 
365 static 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 
388 static 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 
415 static 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 
462 static const struct hid_device_id udraw_devices[] = {
463 	{ HID_USB_DEVICE(USB_VENDOR_ID_THQ, USB_DEVICE_ID_THQ_PS3_UDRAW) },
464 	{ }
465 };
466 MODULE_DEVICE_TABLE(hid, udraw_devices);
467 
468 static 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 };
474 module_hid_driver(udraw_driver);
475