root/drivers/hid/hid-udraw-ps3.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. clamp_accel
  2. udraw_raw_event
  3. udraw_open
  4. udraw_close
  5. allocate_and_setup
  6. udraw_setup_touch
  7. udraw_setup_pen
  8. udraw_setup_accel
  9. udraw_setup_joypad
  10. udraw_probe

   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 
  13 MODULE_AUTHOR("Bastien Nocera <hadess@hadess.net>");
  14 MODULE_DESCRIPTION("PS3 uDraw tablet driver");
  15 MODULE_LICENSE("GPL");
  16 
  17 /*
  18  * Protocol information from:
  19  * http://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 
  32 enum {
  33         TOUCH_NONE,
  34         TOUCH_PEN,
  35         TOUCH_FINGER,
  36         TOUCH_TWOFINGER
  37 };
  38 
  39 enum {
  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  */
  49 static 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 
  68 struct 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 
  90 static 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 
 101 static 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 
 264 static 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 
 271 static 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 
 278 static 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 
 302 static 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 
 329 static 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 
 357 static 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 
 380 static 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 
 407 static 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 
 454 static const struct hid_device_id udraw_devices[] = {
 455         { HID_USB_DEVICE(USB_VENDOR_ID_THQ, USB_DEVICE_ID_THQ_PS3_UDRAW) },
 456         { }
 457 };
 458 MODULE_DEVICE_TABLE(hid, udraw_devices);
 459 
 460 static 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 };
 466 module_hid_driver(udraw_driver);

/* [<][>][^][v][top][bottom][index][help] */