x86/build: convert function graph '-Os' error to warning
[linux/fpc-iii.git] / drivers / hid / hid-udraw-ps3.c
blob88ea390c10ad4a04bc8be43f3af848539538e7f5
1 /*
2 * HID driver for THQ PS3 uDraw tablet
4 * Copyright (C) 2016 Red Hat Inc. All Rights Reserved
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.
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.
16 #include <linux/device.h>
17 #include <linux/hid.h>
18 #include <linux/module.h>
19 #include "hid-ids.h"
21 MODULE_AUTHOR("Bastien Nocera <hadess@hadess.net>");
22 MODULE_DESCRIPTION("PS3 uDraw tablet driver");
23 MODULE_LICENSE("GPL");
26 * Protocol information from:
27 * http://brandonw.net/udraw/
28 * and the source code of:
29 * https://vvvv.org/contribution/udraw-hid
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
40 enum {
41 TOUCH_NONE,
42 TOUCH_PEN,
43 TOUCH_FINGER,
44 TOUCH_TWOFINGER
47 enum {
48 AXIS_X,
49 AXIS_Y,
50 AXIS_Z
54 * Accelerometer min/max values
55 * in order, X, Y and Z
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 }
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)
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;
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.
89 * We'll make do without it, and try to report the first touch
90 * as reliably as possible.
92 int last_one_finger_x;
93 int last_one_finger_y;
94 int last_two_finger_x;
95 int last_two_finger_y;
98 static int clamp_accel(int axis, int offset)
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;
109 static int udraw_raw_event(struct hid_device *hdev, struct hid_report *report,
110 u8 *data, int len)
112 struct udraw *udraw = hid_get_drvdata(hdev);
113 int touch;
114 int x, y, z;
116 if (len != 27)
117 return 0;
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;
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));
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));
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;
172 input_report_abs(udraw->joy_input_dev, ABS_X, x);
173 input_report_abs(udraw->joy_input_dev, ABS_Y, y);
175 input_sync(udraw->joy_input_dev);
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];
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) {
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.
198 * See the udraw struct definition for why this was
199 * implemented this way.
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;
206 x = udraw->last_one_finger_x;
207 y = udraw->last_one_finger_y;
208 } else {
210 * Offset the 2-finger coords using the
211 * saved data from the first finger
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);
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);
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);
235 input_sync(udraw->touch_input_dev);
237 /* pen */
238 if (touch == TOUCH_PEN) {
239 int level;
241 level = clamp(data[13] - PRESSURE_OFFSET,
242 0, MAX_PRESSURE);
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);
254 input_sync(udraw->pen_input_dev);
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);
268 /* let hidraw and hiddev handle the report */
269 return 0;
272 static int udraw_open(struct input_dev *dev)
274 struct udraw *udraw = input_get_drvdata(dev);
276 return hid_hw_open(udraw->hdev);
279 static void udraw_close(struct input_dev *dev)
281 struct udraw *udraw = input_get_drvdata(dev);
283 hid_hw_close(udraw->hdev);
286 static struct input_dev *allocate_and_setup(struct hid_device *hdev,
287 const char *name)
289 struct input_dev *input_dev;
291 input_dev = devm_input_allocate_device(&hdev->dev);
292 if (!input_dev)
293 return NULL;
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));
307 return input_dev;
310 static bool udraw_setup_touch(struct udraw *udraw,
311 struct hid_device *hdev)
313 struct input_dev *input_dev;
315 input_dev = allocate_and_setup(hdev, DEVICE_NAME " Touchpad");
316 if (!input_dev)
317 return false;
319 input_dev->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY);
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);
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);
330 set_bit(INPUT_PROP_POINTER, input_dev->propbit);
332 udraw->touch_input_dev = input_dev;
334 return true;
337 static bool udraw_setup_pen(struct udraw *udraw,
338 struct hid_device *hdev)
340 struct input_dev *input_dev;
342 input_dev = allocate_and_setup(hdev, DEVICE_NAME " Pen");
343 if (!input_dev)
344 return false;
346 input_dev->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY);
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);
355 set_bit(BTN_TOUCH, input_dev->keybit);
356 set_bit(BTN_TOOL_PEN, input_dev->keybit);
358 set_bit(INPUT_PROP_POINTER, input_dev->propbit);
360 udraw->pen_input_dev = input_dev;
362 return true;
365 static bool udraw_setup_accel(struct udraw *udraw,
366 struct hid_device *hdev)
368 struct input_dev *input_dev;
370 input_dev = allocate_and_setup(hdev, DEVICE_NAME " Accelerometer");
371 if (!input_dev)
372 return false;
374 input_dev->evbit[0] = BIT(EV_ABS);
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);
381 set_bit(INPUT_PROP_ACCELEROMETER, input_dev->propbit);
383 udraw->accel_input_dev = input_dev;
385 return true;
388 static bool udraw_setup_joypad(struct udraw *udraw,
389 struct hid_device *hdev)
391 struct input_dev *input_dev;
393 input_dev = allocate_and_setup(hdev, DEVICE_NAME " Joypad");
394 if (!input_dev)
395 return false;
397 input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
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);
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);
410 udraw->joy_input_dev = input_dev;
412 return true;
415 static int udraw_probe(struct hid_device *hdev, const struct hid_device_id *id)
417 struct udraw *udraw;
418 int ret;
420 udraw = devm_kzalloc(&hdev->dev, sizeof(struct udraw), GFP_KERNEL);
421 if (!udraw)
422 return -ENOMEM;
424 udraw->hdev = hdev;
425 udraw->last_two_finger_x = -1;
426 udraw->last_two_finger_y = -1;
428 hid_set_drvdata(hdev, udraw);
430 ret = hid_parse(hdev);
431 if (ret) {
432 hid_err(hdev, "parse failed\n");
433 return ret;
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;
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;
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;
459 return 0;
462 static const struct hid_device_id udraw_devices[] = {
463 { HID_USB_DEVICE(USB_VENDOR_ID_THQ, USB_DEVICE_ID_THQ_PS3_UDRAW) },
466 MODULE_DEVICE_TABLE(hid, udraw_devices);
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,
474 module_hid_driver(udraw_driver);