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