cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

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);