Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * HID driver for THQ PS3 uDraw tablet
0004  *
0005  * Copyright (C) 2016 Red Hat Inc. All Rights Reserved
0006  */
0007 
0008 #include <linux/device.h>
0009 #include <linux/hid.h>
0010 #include <linux/module.h>
0011 #include "hid-ids.h"
0012 
0013 MODULE_AUTHOR("Bastien Nocera <hadess@hadess.net>");
0014 MODULE_DESCRIPTION("PS3 uDraw tablet driver");
0015 MODULE_LICENSE("GPL");
0016 
0017 /*
0018  * Protocol information from:
0019  * https://brandonw.net/udraw/
0020  * and the source code of:
0021  * https://vvvv.org/contribution/udraw-hid
0022  */
0023 
0024 /*
0025  * The device is setup with multiple input devices:
0026  * - the touch area which works as a touchpad
0027  * - the tablet area which works as a touchpad/drawing tablet
0028  * - a joypad with a d-pad, and 7 buttons
0029  * - an accelerometer device
0030  */
0031 
0032 enum {
0033     TOUCH_NONE,
0034     TOUCH_PEN,
0035     TOUCH_FINGER,
0036     TOUCH_TWOFINGER
0037 };
0038 
0039 enum {
0040     AXIS_X,
0041     AXIS_Y,
0042     AXIS_Z
0043 };
0044 
0045 /*
0046  * Accelerometer min/max values
0047  * in order, X, Y and Z
0048  */
0049 static struct {
0050     int min;
0051     int max;
0052 } accel_limits[] = {
0053     [AXIS_X] = { 490, 534 },
0054     [AXIS_Y] = { 490, 534 },
0055     [AXIS_Z] = { 492, 536 }
0056 };
0057 
0058 #define DEVICE_NAME "THQ uDraw Game Tablet for PS3"
0059 /* resolution in pixels */
0060 #define RES_X 1920
0061 #define RES_Y 1080
0062 /* size in mm */
0063 #define WIDTH  160
0064 #define HEIGHT 90
0065 #define PRESSURE_OFFSET 113
0066 #define MAX_PRESSURE (255 - PRESSURE_OFFSET)
0067 
0068 struct udraw {
0069     struct input_dev *joy_input_dev;
0070     struct input_dev *touch_input_dev;
0071     struct input_dev *pen_input_dev;
0072     struct input_dev *accel_input_dev;
0073     struct hid_device *hdev;
0074 
0075     /*
0076      * The device's two-finger support is pretty unreliable, as
0077      * the device could report a single touch when the two fingers
0078      * are too close together, and the distance between fingers, even
0079      * though reported is not in the same unit as the touches.
0080      *
0081      * We'll make do without it, and try to report the first touch
0082      * as reliably as possible.
0083      */
0084     int last_one_finger_x;
0085     int last_one_finger_y;
0086     int last_two_finger_x;
0087     int last_two_finger_y;
0088 };
0089 
0090 static int clamp_accel(int axis, int offset)
0091 {
0092     axis = clamp(axis,
0093             accel_limits[offset].min,
0094             accel_limits[offset].max);
0095     axis = (axis - accel_limits[offset].min) /
0096             ((accel_limits[offset].max -
0097               accel_limits[offset].min) * 0xFF);
0098     return axis;
0099 }
0100 
0101 static int udraw_raw_event(struct hid_device *hdev, struct hid_report *report,
0102      u8 *data, int len)
0103 {
0104     struct udraw *udraw = hid_get_drvdata(hdev);
0105     int touch;
0106     int x, y, z;
0107 
0108     if (len != 27)
0109         return 0;
0110 
0111     if (data[11] == 0x00)
0112         touch = TOUCH_NONE;
0113     else if (data[11] == 0x40)
0114         touch = TOUCH_PEN;
0115     else if (data[11] == 0x80)
0116         touch = TOUCH_FINGER;
0117     else
0118         touch = TOUCH_TWOFINGER;
0119 
0120     /* joypad */
0121     input_report_key(udraw->joy_input_dev, BTN_WEST, data[0] & 1);
0122     input_report_key(udraw->joy_input_dev, BTN_SOUTH, !!(data[0] & 2));
0123     input_report_key(udraw->joy_input_dev, BTN_EAST, !!(data[0] & 4));
0124     input_report_key(udraw->joy_input_dev, BTN_NORTH, !!(data[0] & 8));
0125 
0126     input_report_key(udraw->joy_input_dev, BTN_SELECT, !!(data[1] & 1));
0127     input_report_key(udraw->joy_input_dev, BTN_START, !!(data[1] & 2));
0128     input_report_key(udraw->joy_input_dev, BTN_MODE, !!(data[1] & 16));
0129 
0130     x = y = 0;
0131     switch (data[2]) {
0132     case 0x0:
0133         y = -127;
0134         break;
0135     case 0x1:
0136         y = -127;
0137         x = 127;
0138         break;
0139     case 0x2:
0140         x = 127;
0141         break;
0142     case 0x3:
0143         y = 127;
0144         x = 127;
0145         break;
0146     case 0x4:
0147         y = 127;
0148         break;
0149     case 0x5:
0150         y = 127;
0151         x = -127;
0152         break;
0153     case 0x6:
0154         x = -127;
0155         break;
0156     case 0x7:
0157         y = -127;
0158         x = -127;
0159         break;
0160     default:
0161         break;
0162     }
0163 
0164     input_report_abs(udraw->joy_input_dev, ABS_X, x);
0165     input_report_abs(udraw->joy_input_dev, ABS_Y, y);
0166 
0167     input_sync(udraw->joy_input_dev);
0168 
0169     /* For pen and touchpad */
0170     x = y = 0;
0171     if (touch != TOUCH_NONE) {
0172         if (data[15] != 0x0F)
0173             x = data[15] * 256 + data[17];
0174         if (data[16] != 0x0F)
0175             y = data[16] * 256 + data[18];
0176     }
0177 
0178     if (touch == TOUCH_FINGER) {
0179         /* Save the last one-finger touch */
0180         udraw->last_one_finger_x = x;
0181         udraw->last_one_finger_y = y;
0182         udraw->last_two_finger_x = -1;
0183         udraw->last_two_finger_y = -1;
0184     } else if (touch == TOUCH_TWOFINGER) {
0185         /*
0186          * We have a problem because x/y is the one for the
0187          * second finger but we want the first finger given
0188          * to user-space otherwise it'll look as if it jumped.
0189          *
0190          * See the udraw struct definition for why this was
0191          * implemented this way.
0192          */
0193         if (udraw->last_two_finger_x == -1) {
0194             /* Save the position of the 2nd finger */
0195             udraw->last_two_finger_x = x;
0196             udraw->last_two_finger_y = y;
0197 
0198             x = udraw->last_one_finger_x;
0199             y = udraw->last_one_finger_y;
0200         } else {
0201             /*
0202              * Offset the 2-finger coords using the
0203              * saved data from the first finger
0204              */
0205             x = x - (udraw->last_two_finger_x
0206                 - udraw->last_one_finger_x);
0207             y = y - (udraw->last_two_finger_y
0208                 - udraw->last_one_finger_y);
0209         }
0210     }
0211 
0212     /* touchpad */
0213     if (touch == TOUCH_FINGER || touch == TOUCH_TWOFINGER) {
0214         input_report_key(udraw->touch_input_dev, BTN_TOUCH, 1);
0215         input_report_key(udraw->touch_input_dev, BTN_TOOL_FINGER,
0216                 touch == TOUCH_FINGER);
0217         input_report_key(udraw->touch_input_dev, BTN_TOOL_DOUBLETAP,
0218                 touch == TOUCH_TWOFINGER);
0219 
0220         input_report_abs(udraw->touch_input_dev, ABS_X, x);
0221         input_report_abs(udraw->touch_input_dev, ABS_Y, y);
0222     } else {
0223         input_report_key(udraw->touch_input_dev, BTN_TOUCH, 0);
0224         input_report_key(udraw->touch_input_dev, BTN_TOOL_FINGER, 0);
0225         input_report_key(udraw->touch_input_dev, BTN_TOOL_DOUBLETAP, 0);
0226     }
0227     input_sync(udraw->touch_input_dev);
0228 
0229     /* pen */
0230     if (touch == TOUCH_PEN) {
0231         int level;
0232 
0233         level = clamp(data[13] - PRESSURE_OFFSET,
0234                 0, MAX_PRESSURE);
0235 
0236         input_report_key(udraw->pen_input_dev, BTN_TOUCH, (level != 0));
0237         input_report_key(udraw->pen_input_dev, BTN_TOOL_PEN, 1);
0238         input_report_abs(udraw->pen_input_dev, ABS_PRESSURE, level);
0239         input_report_abs(udraw->pen_input_dev, ABS_X, x);
0240         input_report_abs(udraw->pen_input_dev, ABS_Y, y);
0241     } else {
0242         input_report_key(udraw->pen_input_dev, BTN_TOUCH, 0);
0243         input_report_key(udraw->pen_input_dev, BTN_TOOL_PEN, 0);
0244         input_report_abs(udraw->pen_input_dev, ABS_PRESSURE, 0);
0245     }
0246     input_sync(udraw->pen_input_dev);
0247 
0248     /* accel */
0249     x = (data[19] + (data[20] << 8));
0250     x = clamp_accel(x, AXIS_X);
0251     y = (data[21] + (data[22] << 8));
0252     y = clamp_accel(y, AXIS_Y);
0253     z = (data[23] + (data[24] << 8));
0254     z = clamp_accel(z, AXIS_Z);
0255     input_report_abs(udraw->accel_input_dev, ABS_X, x);
0256     input_report_abs(udraw->accel_input_dev, ABS_Y, y);
0257     input_report_abs(udraw->accel_input_dev, ABS_Z, z);
0258     input_sync(udraw->accel_input_dev);
0259 
0260     /* let hidraw and hiddev handle the report */
0261     return 0;
0262 }
0263 
0264 static int udraw_open(struct input_dev *dev)
0265 {
0266     struct udraw *udraw = input_get_drvdata(dev);
0267 
0268     return hid_hw_open(udraw->hdev);
0269 }
0270 
0271 static void udraw_close(struct input_dev *dev)
0272 {
0273     struct udraw *udraw = input_get_drvdata(dev);
0274 
0275     hid_hw_close(udraw->hdev);
0276 }
0277 
0278 static struct input_dev *allocate_and_setup(struct hid_device *hdev,
0279         const char *name)
0280 {
0281     struct input_dev *input_dev;
0282 
0283     input_dev = devm_input_allocate_device(&hdev->dev);
0284     if (!input_dev)
0285         return NULL;
0286 
0287     input_dev->name = name;
0288     input_dev->phys = hdev->phys;
0289     input_dev->dev.parent = &hdev->dev;
0290     input_dev->open = udraw_open;
0291     input_dev->close = udraw_close;
0292     input_dev->uniq = hdev->uniq;
0293     input_dev->id.bustype = hdev->bus;
0294     input_dev->id.vendor  = hdev->vendor;
0295     input_dev->id.product = hdev->product;
0296     input_dev->id.version = hdev->version;
0297     input_set_drvdata(input_dev, hid_get_drvdata(hdev));
0298 
0299     return input_dev;
0300 }
0301 
0302 static bool udraw_setup_touch(struct udraw *udraw,
0303         struct hid_device *hdev)
0304 {
0305     struct input_dev *input_dev;
0306 
0307     input_dev = allocate_and_setup(hdev, DEVICE_NAME " Touchpad");
0308     if (!input_dev)
0309         return false;
0310 
0311     input_dev->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY);
0312 
0313     input_set_abs_params(input_dev, ABS_X, 0, RES_X, 1, 0);
0314     input_abs_set_res(input_dev, ABS_X, RES_X / WIDTH);
0315     input_set_abs_params(input_dev, ABS_Y, 0, RES_Y, 1, 0);
0316     input_abs_set_res(input_dev, ABS_Y, RES_Y / HEIGHT);
0317 
0318     set_bit(BTN_TOUCH, input_dev->keybit);
0319     set_bit(BTN_TOOL_FINGER, input_dev->keybit);
0320     set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
0321 
0322     set_bit(INPUT_PROP_POINTER, input_dev->propbit);
0323 
0324     udraw->touch_input_dev = input_dev;
0325 
0326     return true;
0327 }
0328 
0329 static bool udraw_setup_pen(struct udraw *udraw,
0330         struct hid_device *hdev)
0331 {
0332     struct input_dev *input_dev;
0333 
0334     input_dev = allocate_and_setup(hdev, DEVICE_NAME " Pen");
0335     if (!input_dev)
0336         return false;
0337 
0338     input_dev->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY);
0339 
0340     input_set_abs_params(input_dev, ABS_X, 0, RES_X, 1, 0);
0341     input_abs_set_res(input_dev, ABS_X, RES_X / WIDTH);
0342     input_set_abs_params(input_dev, ABS_Y, 0, RES_Y, 1, 0);
0343     input_abs_set_res(input_dev, ABS_Y, RES_Y / HEIGHT);
0344     input_set_abs_params(input_dev, ABS_PRESSURE,
0345             0, MAX_PRESSURE, 0, 0);
0346 
0347     set_bit(BTN_TOUCH, input_dev->keybit);
0348     set_bit(BTN_TOOL_PEN, input_dev->keybit);
0349 
0350     set_bit(INPUT_PROP_POINTER, input_dev->propbit);
0351 
0352     udraw->pen_input_dev = input_dev;
0353 
0354     return true;
0355 }
0356 
0357 static bool udraw_setup_accel(struct udraw *udraw,
0358         struct hid_device *hdev)
0359 {
0360     struct input_dev *input_dev;
0361 
0362     input_dev = allocate_and_setup(hdev, DEVICE_NAME " Accelerometer");
0363     if (!input_dev)
0364         return false;
0365 
0366     input_dev->evbit[0] = BIT(EV_ABS);
0367 
0368     /* 1G accel is reported as ~256, so clamp to 2G */
0369     input_set_abs_params(input_dev, ABS_X, -512, 512, 0, 0);
0370     input_set_abs_params(input_dev, ABS_Y, -512, 512, 0, 0);
0371     input_set_abs_params(input_dev, ABS_Z, -512, 512, 0, 0);
0372 
0373     set_bit(INPUT_PROP_ACCELEROMETER, input_dev->propbit);
0374 
0375     udraw->accel_input_dev = input_dev;
0376 
0377     return true;
0378 }
0379 
0380 static bool udraw_setup_joypad(struct udraw *udraw,
0381         struct hid_device *hdev)
0382 {
0383     struct input_dev *input_dev;
0384 
0385     input_dev = allocate_and_setup(hdev, DEVICE_NAME " Joypad");
0386     if (!input_dev)
0387         return false;
0388 
0389     input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
0390 
0391     set_bit(BTN_SOUTH, input_dev->keybit);
0392     set_bit(BTN_NORTH, input_dev->keybit);
0393     set_bit(BTN_EAST, input_dev->keybit);
0394     set_bit(BTN_WEST, input_dev->keybit);
0395     set_bit(BTN_SELECT, input_dev->keybit);
0396     set_bit(BTN_START, input_dev->keybit);
0397     set_bit(BTN_MODE, input_dev->keybit);
0398 
0399     input_set_abs_params(input_dev, ABS_X, -127, 127, 0, 0);
0400     input_set_abs_params(input_dev, ABS_Y, -127, 127, 0, 0);
0401 
0402     udraw->joy_input_dev = input_dev;
0403 
0404     return true;
0405 }
0406 
0407 static int udraw_probe(struct hid_device *hdev, const struct hid_device_id *id)
0408 {
0409     struct udraw *udraw;
0410     int ret;
0411 
0412     udraw = devm_kzalloc(&hdev->dev, sizeof(struct udraw), GFP_KERNEL);
0413     if (!udraw)
0414         return -ENOMEM;
0415 
0416     udraw->hdev = hdev;
0417     udraw->last_two_finger_x = -1;
0418     udraw->last_two_finger_y = -1;
0419 
0420     hid_set_drvdata(hdev, udraw);
0421 
0422     ret = hid_parse(hdev);
0423     if (ret) {
0424         hid_err(hdev, "parse failed\n");
0425         return ret;
0426     }
0427 
0428     if (!udraw_setup_joypad(udraw, hdev) ||
0429         !udraw_setup_touch(udraw, hdev) ||
0430         !udraw_setup_pen(udraw, hdev) ||
0431         !udraw_setup_accel(udraw, hdev)) {
0432         hid_err(hdev, "could not allocate interfaces\n");
0433         return -ENOMEM;
0434     }
0435 
0436     ret = input_register_device(udraw->joy_input_dev) ||
0437         input_register_device(udraw->touch_input_dev) ||
0438         input_register_device(udraw->pen_input_dev) ||
0439         input_register_device(udraw->accel_input_dev);
0440     if (ret) {
0441         hid_err(hdev, "failed to register interfaces\n");
0442         return ret;
0443     }
0444 
0445     ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW | HID_CONNECT_DRIVER);
0446     if (ret) {
0447         hid_err(hdev, "hw start failed\n");
0448         return ret;
0449     }
0450 
0451     return 0;
0452 }
0453 
0454 static const struct hid_device_id udraw_devices[] = {
0455     { HID_USB_DEVICE(USB_VENDOR_ID_THQ, USB_DEVICE_ID_THQ_PS3_UDRAW) },
0456     { }
0457 };
0458 MODULE_DEVICE_TABLE(hid, udraw_devices);
0459 
0460 static struct hid_driver udraw_driver = {
0461     .name = "hid-udraw",
0462     .id_table = udraw_devices,
0463     .raw_event = udraw_raw_event,
0464     .probe = udraw_probe,
0465 };
0466 module_hid_driver(udraw_driver);