HID: udraw: Add support for the uDraw tablet for PS3
RFC PATCH 1/1 HID: udraw: Add support for the uDraw tablet for PS3
This adds support for the THQ uDraw tablet for the PS3, as 4 separate device nodes, so that user-space can easily consume events coming from the hardware.
---
I didn't compile it in-tree yet, only out-of-tree, and I'm still investigating support for LEDs, battery and better two-finger tap support.
Comments welcome
MAINTAINERS | 6 +
drivers/hid/Kconfig | 7 +
drivers/hid/Makefile | 1 +
drivers/hid/hid-core.c | 1 +
drivers/hid/hid-ids.h | 3 +
drivers/hid/hid-udraw.c | 434
++++++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 452 insertions(+)
create mode 100644 drivers/hid/hid-udraw.c
MAINTAINERS +0 -0
@@ -11835,6 +11835,12 @@ S: Maintained
F: Documentation/filesystems/udf.txt
F: fs/udf/
+UDRAW TABLET
+M: Bastien Nocera <[email protected]>
+L: [email protected]
+S: Maintained
+F: drivers/hid/hid-udraw.c
+
UFS FILESYSTEM
M: Evgeniy Dushistov <[email protected]>
S: Maintained
drivers/hid/Kconfig +0 -0
@@ -856,6 +856,13 @@ config THRUSTMASTER_FF
a THRUSTMASTER Dual Trigger 3-in-1 or a THRUSTMASTER Ferrari GT
Rumble Force or Force Feedback Wheel.
+config HID_UDRAW
+ tristate "THQ PS3 uDraw tablet"
+ depends on HID
+ ---help---
+ Say Y here if you want to use the THQ uDraw gaming tablet
for
+ the PS3.
+
config HID_WACOM
tristate "Wacom Intuos/Graphire tablet support (USB)" depends on HID
drivers/hid/Makefile +0 -0
@@ -96,6 +96,7 @@ obj-$(CONFIG_HID_TIVO) += hid-tivo.o
obj-$(CONFIG_HID_TOPSEED) += hid-topseed.o
obj-$(CONFIG_HID_TWINHAN) += hid-twinhan.o
obj-$(CONFIG_HID_UCLOGIC) += hid-uclogic.o
+obj-$(CONFIG_HID_UDRAW) += hid-udraw.o
obj-$(CONFIG_HID_LED) += hid-led.o
obj-$(CONFIG_HID_XINMO) += hid-xinmo.o
obj-$(CONFIG_HID_ZEROPLUS) += hid-zpff.o
drivers/hid/hid-core.c +0 -0
@@ -2083,6 +2083,7 @@ static const struct hid_device_id
hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,USB_DEVICE_ID_UCLOGIC_TABLET_WP1062) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_THQ,USB_DEVICE_ID_THQ_PS3_UDRAW) },
{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP,USB_DEVICE_ID_SMARTJOY_PLUS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP,USB_DEVICE_ID_SUPER_JOY_BOX_3) },
{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP,USB_DEVICE_ID_DUAL_USB_JOYPAD) },
drivers/hid/hid-ids.h +0 -0
@@ -952,6 +952,9 @@
#define USB_VENDOR_ID_THINGM 0x27b8
#define USB_DEVICE_ID_BLINK1 0x01ed
+#define USB_VENDOR_ID_THQ 0x20d6
+#define USB_DEVICE_ID_THQ_PS3_UDRAW 0xcb17
+
#define USB_VENDOR_ID_THRUSTMASTER 0x044f
#define USB_VENDOR_ID_TIVO 0x150a
drivers/hid/hid-udraw.c new file +7 -0
@@ -0,0 +1,434 @@ +/* +* HID driver for THQ PS3 uDraw tablet +* +* Copyright (C) 2016 Red Hat Inc. All Rights Reserved +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation,
and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+#include "hid-ids.h"
+
+MODULE_AUTHOR("Bastien Nocera <[email protected]>"); +MODULE_DESCRIPTION("PS3 uDraw tablet driver"); +MODULE_LICENSE("GPL");
+
+/*
+ * Protocol information from:
+ * http://brandonw.net/udraw/
+ * and the source code of:
+ * https://vvvv.org/contribution/udraw-hid
+ */
+
+/*
+ * The device is setup with multiple input devices to make it easier
+ * to handle in user-space:
+ * - the touch area which works as a touchpad
+ * - the tablet area which works as a touchpad/drawing tablet
+ * - a joypad with a d-pad, and 7 buttons
+ * - an optional, disabled by default, accelerometer device
+ */
+
+static const unsigned short udraw_joy_key_table[] = {
+ BTN_SOUTH,
+ BTN_NORTH,
+ BTN_EAST,
+ BTN_WEST,
+ BTN_SELECT,
+ BTN_START,
+ BTN_MODE
+};
+
+enum {
+ TOUCH_NONE,
+ TOUCH_PEN,
+ TOUCH_FINGER,
+ TOUCH_FINGERS
+};
+
+/* Accelerometer min/max values
+ * in order, X, Y and Z
+ */
+struct {
+ int min;
+ int max;
+} accel_limits[] = {
+ { 0x1EA, 0x216 },
+ { 0x1EA, 0x216 },
+ { 0x1EC, 0x218 }
+};
+
+#define DEVICE_NAME "THQ uDraw Game Tablet for PS3"
+/* resolution in pixels */
+#define RES_X 1920
+#define RES_Y 1080
+/* size in mm */
+#define WIDTH 160
+#define HEIGHT 90
+#define PRESSURE_OFFSET 0x71
+#define MAX_PRESSURE (0xFF - PRESSURE_OFFSET)
+
+struct udraw {
+ struct input_dev *joy_input_dev;
+ struct input_dev *touch_input_dev;
+ struct input_dev *pen_input_dev;
+ struct input_dev *accel_input_dev;
+ struct hid_device *hdev;
+};
+
+static int clamp_accel(int axis, int offset)
+{
+ axis = clamp(axis,
+ accel_limits[offset].min,
+ accel_limits[offset].max);
+ axis = (axis - accel_limits[offset].min) /
+ ((accel_limits[offset].max -
+ accel_limits[offset].min) * 0xFF);
+ return axis;
+}
+
+static int udraw_raw_event(struct hid_device *hdev, struct hid_report *report,
+ u8 *data, int len)
+{
+ struct udraw *udraw = hid_get_drvdata(hdev);
+ int touch;
+ int x, y, z;
+
+ if (len != 0x1B)
+ return 0;
+
+ if (data[11] == 0x00)
+ touch = TOUCH_NONE;
+ else if (data[11] == 0x40)
+ touch = TOUCH_PEN;
+ else if (data[11] == 0x80)
+ touch = TOUCH_FINGER;
+ else
+ touch = TOUCH_FINGERS;
+
+ /* joypad */
+ input_report_key(udraw->joy_input_dev, BTN_WEST, data[0] & 1);
+ input_report_key(udraw->joy_input_dev, BTN_SOUTH, data[0] &
2);
+ input_report_key(udraw->joy_input_dev, BTN_EAST, data[0] & 4);
+ input_report_key(udraw->joy_input_dev, BTN_NORTH, data[0] &
8);
+
+ input_report_key(udraw->joy_input_dev, BTN_SELECT, data[1] &
1);
+ input_report_key(udraw->joy_input_dev, BTN_START, data[1] &
2);
+ input_report_key(udraw->joy_input_dev, BTN_MODE, data[1] &
16);
+
+ x = y = 0;
+ switch (data[2]) {
+ case 0x0:
+ y = -127;
+ break;
+ case 0x1:
+ y = -127;
+ x = 127;
+ break;
+ case 0x2:
+ x = 127;
+ break;
+ case 0x3:
+ y = 127;
+ x = 127;
+ break;
+ case 0x4:
+ y = 127;
+ break;
+ case 0x5:
+ y = 127;
+ x = -127;
+ break;
+ case 0x6:
+ x = -127;
+ break;
+ case 0x7:
+ y = -127;
+ x = -127;
+ break;
+ default:
+ break;
+ }
+
+ input_report_abs(udraw->joy_input_dev, ABS_X, x);
+ input_report_abs(udraw->joy_input_dev, ABS_Y, y);
+
+ input_sync(udraw->joy_input_dev);
+
+ /* For pen and touchpad */
+ x = y = 0;
+ if (touch != TOUCH_NONE) {
+ if (data[15] != 0x0F)
+ x = data[15] * 256 + data[17];
+ if (data[16] != 0x0F)
+ y = data[16] * 256 + data[18];
+ }
+
+ /* touchpad */
+ if (touch == TOUCH_FINGER || touch == TOUCH_FINGERS) {
+ input_report_key(udraw->touch_input_dev, BTN_TOUCH,
1);
+ input_report_key(udraw->touch_input_dev,BTN_TOOL_FINGER,
+ touch == TOUCH_FINGER);
+ input_report_key(udraw->touch_input_dev,BTN_TOOL_DOUBLETAP,
+ touch == TOUCH_FINGERS);
+
+ input_report_abs(udraw->touch_input_dev, ABS_X, x);
+ input_report_abs(udraw->touch_input_dev, ABS_Y, y);
+ } else {
+ input_report_key(udraw->touch_input_dev, BTN_TOUCH,
0);
+ input_report_key(udraw->touch_input_dev,BTN_TOOL_FINGER, 0);
+ input_report_key(udraw->touch_input_dev,BTN_TOOL_DOUBLETAP, 0);
+ }
+ input_sync(udraw->touch_input_dev);
+
+ /* pen */
+ if (touch == TOUCH_PEN) {
+ int level;
+
+ level = clamp(data[13] - PRESSURE_OFFSET,
+ 0, MAX_PRESSURE);
+
+ input_report_key(udraw->pen_input_dev, BTN_TOUCH,
(level != 0));
+ input_report_key(udraw->pen_input_dev, BTN_TOOL_PEN,
1);
+ input_report_abs(udraw->pen_input_dev, ABS_PRESSURE,
level);
+ input_report_abs(udraw->pen_input_dev, ABS_X, x);
+ input_report_abs(udraw->pen_input_dev, ABS_Y, y);
+ } else {
+ input_report_key(udraw->pen_input_dev, BTN_TOUCH, 0);
+ input_report_abs(udraw->pen_input_dev, ABS_PRESSURE,
0);
+ input_report_key(udraw->pen_input_dev, BTN_TOOL_PEN,
0);
+ }
+ input_sync(udraw->pen_input_dev);
+
+ /* accel */
+ x = (data[19] + (data[20] << 8));
+ x = clamp_accel(x, 0);
+ y = (data[21] + (data[22] << 8));
+ y = clamp_accel(y, 1);
+ z = (data[23] + (data[24] << 8));
+ z = clamp_accel(z, 2);
+ input_report_abs(udraw->accel_input_dev, ABS_X, x);
+ input_report_abs(udraw->accel_input_dev, ABS_Y, y);
+ input_report_abs(udraw->accel_input_dev, ABS_Z, z);
+ input_sync(udraw->accel_input_dev);
+
+ /* let hidraw and hiddev handle the report */
+ return 0;
+}
+
+static int udraw_open(struct input_dev *dev)
+{
+ struct udraw *udraw = input_get_drvdata(dev);
+
+ return hid_hw_open(udraw->hdev);
+}
+
+static void udraw_close(struct input_dev *dev)
+{
+ struct udraw *udraw = input_get_drvdata(dev);
+
+ hid_hw_close(udraw->hdev);
+}
+
+static struct input_dev *allocate_and_setup(struct hid_device *hdev,
+ const char *name)
+{
+ struct input_dev *input_dev;
+
+ input_dev = devm_input_allocate_device(&hdev->dev);
+ if (!input_dev)
+ return NULL;
+
+ input_dev->name = name;
+ input_dev->phys = hdev->phys;
+ input_dev->dev.parent = &hdev->dev;
+ input_dev->open = udraw_open;
+ input_dev->close = udraw_close;
+ input_dev->uniq = hdev->uniq;
+ input_dev->id.bustype = hdev->bus;
+ input_dev->id.vendor = hdev->vendor;
+ input_dev->id.product = hdev->product;
+ input_dev->id.version = hdev->version;
+ input_set_drvdata(input_dev, hid_get_drvdata(hdev));
+
+ return input_dev;
+}
+
+static bool udraw_setup_touch(struct udraw *udraw,
+ struct hid_device *hdev)
+{
+ struct input_dev *input_dev;
+
+ input_dev = allocate_and_setup(hdev, DEVICE_NAME "
(touchpad)");
+ if (!input_dev)
+ return false;
+
+ input_dev->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY);
+
+ set_bit(ABS_X, input_dev->absbit);
+ input_set_abs_params(input_dev, ABS_X, 0, RES_X, 1, 0);
+ input_abs_set_res(input_dev, ABS_X, RES_X / WIDTH);
+ set_bit(ABS_Y, input_dev->absbit);
+ input_set_abs_params(input_dev, ABS_Y, 0, RES_Y, 1, 0);
+ input_abs_set_res(input_dev, ABS_Y, RES_Y / HEIGHT);
+
+ set_bit(BTN_TOUCH, input_dev->keybit);
+ set_bit(BTN_TOOL_FINGER, input_dev->keybit);
+ set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
+
+ set_bit(INPUT_PROP_POINTER, input_dev->propbit);
+
+ udraw->touch_input_dev = input_dev;
+
+ return true;
+}
+
+static bool udraw_setup_pen(struct udraw *udraw,
+ struct hid_device *hdev)
+{
+ struct input_dev *input_dev;
+
+ input_dev = allocate_and_setup(hdev, DEVICE_NAME " (pen)");
+ if (!input_dev)
+ return false;
+
+ input_dev->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY);
+
+ set_bit(ABS_X, input_dev->absbit);
+ input_set_abs_params(input_dev, ABS_X, 0, RES_X, 1, 0);
+ input_abs_set_res(input_dev, ABS_X, RES_X / WIDTH);
+ set_bit(ABS_Y, input_dev->absbit);
+ input_set_abs_params(input_dev, ABS_Y, 0, RES_Y, 1, 0);
+ input_abs_set_res(input_dev, ABS_Y, RES_Y / HEIGHT);
+ set_bit(ABS_PRESSURE, input_dev->absbit);
+ input_set_abs_params(input_dev, ABS_PRESSURE,
+ 0, MAX_PRESSURE, 0, 0);
+
+ set_bit(BTN_TOUCH, input_dev->keybit);
+ set_bit(BTN_TOOL_PEN, input_dev->keybit);
+
+ set_bit(INPUT_PROP_POINTER, input_dev->propbit);
+
+ udraw->pen_input_dev = input_dev;
+
+ return true;
+}
+
+static bool udraw_setup_accel(struct udraw *udraw,
+ struct hid_device *hdev)
+{
+ struct input_dev *input_dev;
+
+ input_dev = allocate_and_setup(hdev, DEVICE_NAME "
(accelerometer)");
+ if (!input_dev)
+ return false;
+
+ input_dev->evbit[0] = BIT(EV_ABS);
+
+ /* 1G accel is reported as ~256, so clamp to 2G */
+ set_bit(ABS_X, input_dev->absbit);
+ input_set_abs_params(input_dev, ABS_X, -512, 512, 0, 0);
+ set_bit(ABS_Y, input_dev->absbit);
+ input_set_abs_params(input_dev, ABS_Y, -512, 512, 0, 0);
+ set_bit(ABS_Z, input_dev->absbit);
+ input_set_abs_params(input_dev, ABS_Z, -512, 512, 0, 0);
+
+ set_bit(INPUT_PROP_ACCELEROMETER, input_dev->propbit);
+
+ udraw->accel_input_dev = input_dev;
+
+ return true;
+}
+
+static bool udraw_setup_joypad(struct udraw *udraw,
+ struct hid_device *hdev)
+{
+ struct input_dev *input_dev;
+ int i;
+
+ input_dev = allocate_and_setup(hdev, DEVICE_NAME " (joypad)");
+ if (!input_dev)
+ return false;
+
+ input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+
+ set_bit(ABS_X, input_dev->absbit);
+ input_set_abs_params(input_dev, ABS_X, -127, 127, 0, 0);
+ set_bit(ABS_Y, input_dev->absbit);
+ input_set_abs_params(input_dev, ABS_Y, -127, 127, 0, 0);
+
+ for (i = 0; i < ARRAY_SIZE(udraw_joy_key_table); i++)
+ set_bit(udraw_joy_key_table[i], input_dev->keybit);
+
+ udraw->joy_input_dev = input_dev;
+
+ return true;
+}
+
+static int udraw_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+ struct udraw *udraw;
+ int ret;
+
+ udraw = devm_kzalloc(&hdev->dev, sizeof(struct udraw),GFP_KERNEL);
+ if (!udraw)
+ return -ENOMEM;
+
+ udraw->hdev = hdev;
+
+ hid_set_drvdata(hdev, udraw);
+
+ ret = hid_parse(hdev);
+ if (ret) {
+ hid_err(hdev, "parse failed\n");
+ return ret;
+ }
+
+ if (!udraw_setup_joypad(udraw, hdev) ||
+ !udraw_setup_touch(udraw, hdev) ||
+ !udraw_setup_pen(udraw, hdev) ||
+ !udraw_setup_accel(udraw, hdev)) {
+ hid_err(hdev, "could not allocate interfaces\n");
+ return -ENOMEM;
+ }
+
+ ret = input_register_device(udraw->joy_input_dev) ||
+ input_register_device(udraw->touch_input_dev) ||
+ input_register_device(udraw->pen_input_dev) ||
+ input_register_device(udraw->accel_input_dev);
+ if (ret) {
+ hid_err(hdev, "failed to register interfaces\n");
+ return ret;
+ }
+
+ ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW |HID_CONNECT_DRIVER);
+ if (ret) {
+ hid_err(hdev, "hw start failed\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct hid_device_id udraw_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_THQ,USB_DEVICE_ID_THQ_PS3_UDRAW) },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, udraw_devices);
+
+static struct hid_driver udraw_driver = {
+ .name = "hid-udraw",
+ .id_table = udraw_devices,
+ .raw_event = udraw_raw_event,
+ .probe = udraw_probe,
+};
+module_hid_driver(udraw_driver);
--
2.7.4
Quoted 25 lines · Bastien Nocera
This adds support for the THQ uDraw tablet for the PS3, as 4 separate device nodes, so that user-space can easily consume events coming from the hardware.
Tested-by Bastien Nocera <[email protected]>Signed-off-by Bastien Nocera <[email protected]>---
I didn't compile it in-tree yet, only out-of-tree, and I'm still investigating support for LEDs, battery and better two-finger tap support.
Comments welcome
MAINTAINERS | 6 +
drivers/hid/Kconfig | 7 +
drivers/hid/Makefile | 1 +
drivers/hid/hid-core.c | 1 +
drivers/hid/hid-ids.h | 3 +
drivers/hid/hid-udraw.c | 434
++++++++++++++++++++++++++++++++++++++++++++++++6 files changed, 452 insertions(+)create mode 100644
drivers/hid/hid-udraw.c
[...]
Quoted 52 lines
drivers/hid/hid-udraw.c new file +7
-0@@ -0,0 +1,434 @@ +/* +* HID driver for THQ PS3 uDraw tablet +* +* Copyright (C) 2016 Red Hat Inc. All Rights Reserved +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */drivers/hid/hid-udraw.c new file +31
-0+ +#include <linux/device.h> +#include <linux/hid.h> +#include <linux/module.h> +#include "hid-ids.h" + +MODULE_AUTHOR ("Bastien Nocera <[email protected]>" ); +MODULE_DESCRIPTION ("PS3 uDraw tablet driver" ); +MODULE_LICENSE ("GPL" ); + +/* +* Protocol information from: +* http://brandonw.net/udraw/ +* and the source code of: +* https://vvvv.org/contribution/udraw-hid +*/ + +/* +* The device is setup with multiple input devices to make it easier +* to handle in user-space: +* - the touch area which works as a touchpad +* - the tablet area which works as a touchpad/drawing tablet +* - a joypad with a d-pad, and 7 buttons +* - an optional, disabled by default, accelerometer device +*/ + +static const unsigned short udraw_joy_key_table[] = { +BTN_SOUTH , +BTN_NORTH , +BTN_EAST , +BTN_WEST ,
drivers/hid/hid-udraw.c
Quoted 10 lines
drivers/hid/hid-udraw.c new file +10
-0+BTN_SELECT , +BTN_START , +BTN_MODE +}; + +enum { +TOUCH_NONE , +TOUCH_PEN , +TOUCH_FINGER , + TOUCH_FINGERS
FINGER and FINGERS is easy to confuse on a quick read, better rename to MULTIFINGER or TWOFINGER, depending what you can detect.
Quoted 170 lines
drivers/hid/hid-udraw.c new file +44
-0+}; + +/* Accelerometer min/max values +* in order, X, Y and Z +*/ +struct { +int min; +int max; +} accel_limits[] = { + {0x1EA ,0x216 }, + {0x1EA ,0x216 }, + {0x1EC ,0x218 } +}; + +#define DEVICE_NAME "THQ uDraw Game Tablet for PS3" +/* resolution in pixels */ +#define RES_X 1920 +#define RES_Y 1080 +/* size in mm */ +#define WIDTH 160 +#define HEIGHT 90 +#define PRESSURE_OFFSET 0x71 +#define MAX_PRESSURE (0xFF - PRESSURE_OFFSET) + +struct udraw { +struct input_dev *joy_input_dev; +struct input_dev *touch_input_dev; +struct input_dev *pen_input_dev; +struct input_dev *accel_input_dev; +struct hid_device *hdev; +}; + +static int clamp_accel (int axis,int offset) +{ + axis =clamp (axis, + accel_limits[offset].min, + accel_limits[offset].max); + axis = (axis - accel_limits[offset].min) / + ((accel_limits[offset].max - + accel_limits[offset].min) * 0xFF); +return axis; +} + +static int udraw_raw_event(struct hid_device *hdev, struct hid_report*report,
drivers/hid/hid-udraw.c new file +21
-0+ u8 *data, int len) +{ +struct udraw *udraw =hid_get_drvdata (hdev); +int touch; +int x, y, z; + +if (len !=0x1B ) +return 0 ; + +if (data[11 ] ==0x00 ) + touch =TOUCH_NONE ; +else if (data[11 ] ==0x40 ) + touch =TOUCH_PEN ; +else if (data[11 ] ==0x80 ) + touch =TOUCH_FINGER ; +else + touch =TOUCH_FINGERS ; + +/* joypad */ +input_report_key (udraw->joy_input_dev,BTN_WEST , data[0 ] &1 ); + input_report_key(udraw->joy_input_dev, BTN_SOUTH, data[0] &2);
drivers/hid/hid-udraw.c new file +2
-0+input_report_key (udraw->joy_input_dev,BTN_EAST , data[0 ] &4 ); + input_report_key(udraw->joy_input_dev, BTN_NORTH, data[0] &8);
drivers/hid/hid-udraw.c new file +2
-0+ + input_report_key(udraw->joy_input_dev, BTN_SELECT, data[1] &1);
drivers/hid/hid-udraw.c new file +1
-0+ input_report_key(udraw->joy_input_dev, BTN_START, data[1] &2);
drivers/hid/hid-udraw.c new file +1
-0+ input_report_key(udraw->joy_input_dev, BTN_MODE, data[1] &16);
drivers/hid/hid-udraw.c new file +52
-0+ + x = y =0 ; +switch (data[2 ]) { +case 0x0 : + y =-127 ; +break ; +case 0x1 : + y =-127 ; + x =127 ; +break ; +case 0x2 : + x =127 ; +break ; +case 0x3 : + y =127 ; + x =127 ; +break ; +case 0x4 : + y =127 ; +break ; +case 0x5 : + y =127 ; + x =-127 ; +break ; +case 0x6 : + x =-127 ; +break ; +case 0x7 : + y =-127 ; + x =-127 ; +break ; +default : +break ; + } + +input_report_abs (udraw->joy_input_dev,ABS_X , x); +input_report_abs (udraw->joy_input_dev,ABS_Y , y); + +input_sync (udraw->joy_input_dev); + +/* For pen and touchpad */ + x = y =0 ; +if (touch !=TOUCH_NONE ) { +if (data[15 ] !=0x0F ) + x = data[15 ] *256 + data[17 ]; +if (data[16 ] !=0x0F ) + y = data[16 ] *256 + data[18 ]; + } + +/* touchpad */ +if (touch ==TOUCH_FINGER || touch ==TOUCH_FINGERS ) { + input_report_key(udraw->touch_input_dev, BTN_TOUCH,1);
drivers/hid/hid-udraw.c new file +1
-0+ input_report_key(udraw->touch_input_dev,
BTN_TOOL_FINGER,drivers/hid/hid-udraw.c new file +2
-0+ touch == TOUCH_FINGER); + input_report_key(udraw->touch_input_dev,
BTN_TOOL_DOUBLETAP,drivers/hid/hid-udraw.c new file +6
-0+ touch == TOUCH_FINGERS); + +input_report_abs (udraw->touch_input_dev,ABS_X , x); +input_report_abs (udraw->touch_input_dev,ABS_Y , y); + }else { + input_report_key(udraw->touch_input_dev, BTN_TOUCH,0);
drivers/hid/hid-udraw.c new file +1
-0+ input_report_key(udraw->touch_input_dev,
BTN_TOOL_FINGER, 0);drivers/hid/hid-udraw.c new file +1
-0+ input_report_key(udraw->touch_input_dev,
BTN_TOOL_DOUBLETAP, 0);drivers/hid/hid-udraw.c new file +11
-0+ } +input_sync (udraw->touch_input_dev); + +/* pen */ +if (touch ==TOUCH_PEN ) { +int level; + + level =clamp (data[13 ] -PRESSURE_OFFSET , +0 ,MAX_PRESSURE ); + + input_report_key(udraw->pen_input_dev, BTN_TOUCH,(level != 0));
drivers/hid/hid-udraw.c new file +1
-0+ input_report_key(udraw->pen_input_dev, BTN_TOOL_PEN,1);
drivers/hid/hid-udraw.c new file +1
-0+ input_report_abs(udraw->pen_input_dev, ABS_PRESSURE,level);
drivers/hid/hid-udraw.c new file +5
-0+input_report_abs (udraw->pen_input_dev,ABS_X , x); +input_report_abs (udraw->pen_input_dev,ABS_Y , y); + }else { +input_report_key (udraw->pen_input_dev,BTN_TOUCH ,0 ); + input_report_abs(udraw->pen_input_dev, ABS_PRESSURE,0);
drivers/hid/hid-udraw.c new file +1
-0+ input_report_key(udraw->pen_input_dev, BTN_TOOL_PEN,0);
drivers/hid/hid-udraw.c
Quoted 2 lines
drivers/hid/hid-udraw.c new file +2
-0+ } +input_sync (udraw->pen_input_dev);
do me a favour and group the reports by type. it makes no difference to this driver but event recordings are much easier to read this way.
so all EV_ABS first, then EV_KEY (or the other way round, don't care).
drivers/hid/hid-udraw.c
Quoted 8 lines
drivers/hid/hid-udraw.c new file +8
-0+ +/* accel */ + x = (data[19 ] + (data[20 ] <<8 )); + x =clamp_accel (x,0 ); + y = (data[21 ] + (data[22 ] <<8 )); + y =clamp_accel (y,1 ); + z = (data[23 ] + (data[24 ] <<8 )); + z =clamp_accel (z,2 );
this may not be kernel style, but any reason you can't use an enum here instead of 0, 1, 2? clamp_accel(x, ACCEL_AXIS_X) would be more obvious to read.
Quoted 53 lines
drivers/hid/hid-udraw.c new file +53
-0+input_report_abs (udraw->accel_input_dev,ABS_X , x); +input_report_abs (udraw->accel_input_dev,ABS_Y , y); +input_report_abs (udraw->accel_input_dev,ABS_Z , z); +input_sync (udraw->accel_input_dev); + +/* let hidraw and hiddev handle the report */ +return 0 ; +} + +static int udraw_open (struct input_dev *dev) +{ +struct udraw *udraw =input_get_drvdata (dev); + +return hid_hw_open (udraw->hdev); +} + +static void udraw_close (struct input_dev *dev) +{ +struct udraw *udraw =input_get_drvdata (dev); + +hid_hw_close (udraw->hdev); +} + +static struct input_dev *allocate_and_setup (struct hid_device *hdev, +const char *name) +{ +struct input_dev *input_dev; + + input_dev =devm_input_allocate_device (&hdev->dev); +if (!input_dev) +return NULL ; + + input_dev->name = name; + input_dev->phys = hdev->phys; + input_dev->dev.parent = &hdev->dev; + input_dev->open = udraw_open; + input_dev->close = udraw_close; + input_dev->uniq = hdev->uniq; + input_dev->id.bustype = hdev->bus; + input_dev->id.vendor = hdev->vendor; + input_dev->id.product = hdev->product; + input_dev->id.version = hdev->version; +input_set_drvdata (input_dev,hid_get_drvdata (hdev)); + +return input_dev; +} + +static bool udraw_setup_touch(struct udraw *udraw, + struct hid_device *hdev) +{ + struct input_dev *input_dev; + + input_dev = allocate_and_setup(hdev, DEVICE_NAME "
Quoted 1 line
(touchpad)");
no need to use () here. wacom device names are "foo Pen", "foo Finger", etc. would be nice to continue that naming scheme.
Quoted 19 lines
drivers/hid/hid-udraw.c new file +19
-0+if (!input_dev) +return false; + + input_dev->evbit[0 ] =BIT (EV_ABS ) |BIT (EV_KEY ); + +set_bit (ABS_X , input_dev->absbit); +input_set_abs_params (input_dev,ABS_X ,0 ,RES_X ,1 ,0 ); +input_abs_set_res (input_dev,ABS_X ,RES_X /WIDTH ); +set_bit (ABS_Y , input_dev->absbit); +input_set_abs_params (input_dev,ABS_Y ,0 ,RES_Y ,1 ,0 ); +input_abs_set_res (input_dev,ABS_Y ,RES_Y /HEIGHT ); + +set_bit (BTN_TOUCH , input_dev->keybit); +set_bit (BTN_TOOL_FINGER , input_dev->keybit); +set_bit (BTN_TOOL_DOUBLETAP , input_dev->keybit); + +set_bit (INPUT_PROP_POINTER , input_dev->propbit); + + udraw->touch_input_dev = input_dev;
drivers/hid/hid-udraw.c
Quoted 10 lines
drivers/hid/hid-udraw.c new file +10
-0+ +return true; +} + +static bool udraw_setup_pen (struct udraw *udraw, +struct hid_device *hdev) +{ +struct input_dev *input_dev; + + input_dev =allocate_and_setup (hdev,DEVICE_NAME " (pen)" );
see above for naming scheme
Quoted 31 lines
drivers/hid/hid-udraw.c new file +31
-0+if (!input_dev) +return false; + + input_dev->evbit[0 ] =BIT (EV_ABS ) |BIT (EV_KEY ); + +set_bit (ABS_X , input_dev->absbit); +input_set_abs_params (input_dev,ABS_X ,0 ,RES_X ,1 ,0 ); +input_abs_set_res (input_dev,ABS_X ,RES_X /WIDTH ); +set_bit (ABS_Y , input_dev->absbit); +input_set_abs_params (input_dev,ABS_Y ,0 ,RES_Y ,1 ,0 ); +input_abs_set_res (input_dev,ABS_Y ,RES_Y /HEIGHT ); +set_bit (ABS_PRESSURE , input_dev->absbit); +input_set_abs_params (input_dev,ABS_PRESSURE , +0 ,MAX_PRESSURE ,0 ,0 ); + +set_bit (BTN_TOUCH , input_dev->keybit); +set_bit (BTN_TOOL_PEN , input_dev->keybit); + +set_bit (INPUT_PROP_POINTER , input_dev->propbit); + + udraw->pen_input_dev = input_dev; + +return true; +} + +static bool udraw_setup_accel(struct udraw *udraw, + struct hid_device *hdev) +{ + struct input_dev *input_dev; + + input_dev = allocate_and_setup(hdev, DEVICE_NAME "
Quoted 1 line
(accelerometer)");
see above for naming scheme
Quoted 17 lines
drivers/hid/hid-udraw.c new file +17
-0+if (!input_dev) +return false; + + input_dev->evbit[0 ] =BIT (EV_ABS ); + +/* 1G accel is reported as ~256, so clamp to 2G */ +set_bit (ABS_X , input_dev->absbit); +input_set_abs_params (input_dev,ABS_X ,-512 ,512 ,0 ,0 ); +set_bit (ABS_Y , input_dev->absbit); +input_set_abs_params (input_dev,ABS_Y ,-512 ,512 ,0 ,0 ); +set_bit (ABS_Z , input_dev->absbit); +input_set_abs_params (input_dev,ABS_Z ,-512 ,512 ,0 ,0 ); + +set_bit (INPUT_PROP_ACCELEROMETER , input_dev->propbit); + + udraw->accel_input_dev = input_dev; +
drivers/hid/hid-udraw.c
Quoted 10 lines
drivers/hid/hid-udraw.c new file +10
-0+return true; +} + +static bool udraw_setup_joypad (struct udraw *udraw, +struct hid_device *hdev) +{ +struct input_dev *input_dev; +int i; + + input_dev =allocate_and_setup (hdev,DEVICE_NAME " (joypad)" );
see above for naming scheme
drivers/hid/hid-udraw.c
Quoted 12 lines
drivers/hid/hid-udraw.c new file +12
-0+if (!input_dev) +return false; + + input_dev->evbit[0 ] =BIT (EV_KEY ) |BIT (EV_ABS ); + +set_bit (ABS_X , input_dev->absbit); +input_set_abs_params (input_dev,ABS_X ,-127 ,127 ,0 ,0 ); +set_bit (ABS_Y , input_dev->absbit); +input_set_abs_params (input_dev,ABS_Y ,-127 ,127 ,0 ,0 ); + +for (i =0 ; i <ARRAY_SIZE (udraw_joy_key_table); i++) +set_bit (udraw_joy_key_table[i], input_dev->keybit);
Personal opinion here: for the few buttons you have, the loop over an array doesn't really get you much benefit over just having 7 set_bit() calls. just hardcoding all set_bit calls (or moving joy_key_table to here) is that you have all the init bits in one place for quick analysis.
but I'm not going to argue this point too hard.
Cheers,
Peter
Quoted 75 lines
drivers/hid/hid-udraw.c new file +7
-0+ + udraw->joy_input_dev = input_dev; + +return true; +} + +static int udraw_probe(struct hid_device *hdev, const struct
hid_device_id*id)drivers/hid/hid-udraw.c new file +5
-0+{ +struct udraw *udraw; +int ret; + + udraw = devm_kzalloc(&hdev->dev, sizeof(struct udraw),
GFP_KERNEL);drivers/hid/hid-udraw.c new file +31
-0+if (!udraw) +return -ENOMEM ; + + udraw->hdev = hdev; + +hid_set_drvdata (hdev, udraw); + + ret =hid_parse (hdev); +if (ret) { +hid_err (hdev,"parse failed\n" ); +return ret; + } + +if (!udraw_setup_joypad (udraw, hdev) || + !udraw_setup_touch(udraw, hdev) || + !udraw_setup_pen(udraw, hdev) || + !udraw_setup_accel(udraw, hdev)) { +hid_err (hdev,"could not allocate interfaces\n" ); +return -ENOMEM ; + } + + ret =input_register_device (udraw->joy_input_dev) || +input_register_device (udraw->touch_input_dev) || +input_register_device (udraw->pen_input_dev) || +input_register_device (udraw->accel_input_dev); +if (ret) { +hid_err (hdev,"failed to register interfaces\n" ); +return ret; + } + + ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW |
HID_CONNECT_DRIVER);drivers/hid/hid-udraw.c new file +10
-0+if (ret) { +hid_err (hdev,"hw start failed\n" ); +return ret; + } + +return 0 ; +} + +static const struct hid_device_id udraw_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_THQ,
USB_DEVICE_ID_THQ_PS3_UDRAW) },drivers/hid/hid-udraw.c new file +11
-0+ { } +}; +MODULE_DEVICE_TABLE (hid, udraw_devices); + +static struct hid_driver udraw_driver = { + .name ="hid-udraw" , + .id_table = udraw_devices, + .raw_event = udraw_raw_event, + .probe = udraw_probe, +}; +module_hid_driver (udraw_driver);--
2.7.4
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 92 lines · Peter Hutterer
Quoted 26 lines · Bastien Nocera
This adds support for the THQ uDraw tablet for the PS3, as 4 separate device nodes, so that user-space can easily consume events coming from the hardware.
Tested-by Bastien Nocera <[email protected]>Signed-off-by Bastien Nocera <[email protected]>---
I didn't compile it in-tree yet, only out-of-tree, and I'm still investigating support for LEDs, battery and better two-finger tap support.
Comments welcome
MAINTAINERS | 6 +
drivers/hid/Kconfig | 7 +
drivers/hid/Makefile | 1 +
drivers/hid/hid-core.c | 1 +
drivers/hid/hid-ids.h | 3 +
drivers/hid/hid-udraw.c | 434
++++++++++++++++++++++++++++++++++++++++++++++++6 files changed, 452 insertions(+)create mode 100644
drivers/hid/hid-udraw.c[...]
Quoted 62 lines
drivers/hid/hid-udraw.c new file +6
-0@@ -0,0 +1,434 @@ +/* +* HID driver for THQ PS3 uDraw tablet +* +* Copyright (C) 2016 Red Hat Inc. All Rights Reserved +* +* This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation,
and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */drivers/hid/hid-udraw.c new file +19
-0+ +#include <linux/device.h> +#include <linux/hid.h> +#include <linux/module.h> +#include "hid-ids.h" + +MODULE_AUTHOR ("Bastien Nocera <[email protected]>" ); +MODULE_DESCRIPTION ("PS3 uDraw tablet driver" ); +MODULE_LICENSE ("GPL" ); + +/* +* Protocol information from: +* http://brandonw.net/udraw/ +* and the source code of: +* https://vvvv.org/contribution/udraw-hid +*/ + +/* +* The device is setup with multiple input devices to make it easier
+ * to handle in user-space:
+ * - the touch area which works as a touchpad
+ * - the tablet area which works as a touchpad/drawing tablet
+ * - a joypad with a d-pad, and 7 buttons
+ * - an optional, disabled by default, accelerometer device
+ */drivers/hid/hid-udraw.c new file +12
-0+ +static const unsigned short udraw_joy_key_table[] = { +BTN_SOUTH , +BTN_NORTH , +BTN_EAST , +BTN_WEST , +BTN_SELECT , +BTN_START , +BTN_MODE +}; + +enum {
Quoted 8 lines
drivers/hid/hid-udraw.c
Quoted 4 lines
drivers/hid/hid-udraw.c new file +4
-0+TOUCH_NONE , +TOUCH_PEN , +TOUCH_FINGER , +TOUCH_FINGERS FINGER and FINGERS is easy to confuse on a quick read, better rename to
MULTIFINGER or TWOFINGER, depending what you can detect.
Done.
Quoted 187 lines
Quoted 187 lines
drivers/hid/hid-udraw.c new file +44
-0+}; + +/* Accelerometer min/max values +* in order, X, Y and Z +*/ +struct { +int min; +int max; +} accel_limits[] = { + {0x1EA ,0x216 }, + {0x1EA ,0x216 }, + {0x1EC ,0x218 } +}; + +#define DEVICE_NAME "THQ uDraw Game Tablet for PS3" +/* resolution in pixels */ +#define RES_X 1920 +#define RES_Y 1080 +/* size in mm */ +#define WIDTH 160 +#define HEIGHT 90 +#define PRESSURE_OFFSET 0x71 +#define MAX_PRESSURE (0xFF - PRESSURE_OFFSET) + +struct udraw { +struct input_dev *joy_input_dev; +struct input_dev *touch_input_dev; +struct input_dev *pen_input_dev; +struct input_dev *accel_input_dev; +struct hid_device *hdev; +}; + +static int clamp_accel (int axis,int offset) +{ + axis =clamp (axis, + accel_limits[offset].min, + accel_limits[offset].max); + axis = (axis - accel_limits[offset].min) / + ((accel_limits[offset].max - + accel_limits[offset].min) * 0xFF); +return axis; +} + +static int udraw_raw_event(struct hid_device *hdev, struct
hid_report
*report,drivers/hid/hid-udraw.c new file +20
-0+ u8 *data, int len) +{ +struct udraw *udraw =hid_get_drvdata (hdev); +int touch; +int x, y, z; + +if (len !=0x1B ) +return 0 ; + +if (data[11 ] ==0x00 ) + touch =TOUCH_NONE ; +else if (data[11 ] ==0x40 ) + touch =TOUCH_PEN ; +else if (data[11 ] ==0x80 ) + touch =TOUCH_FINGER ; +else + touch =TOUCH_FINGERS ; + +/* joypad */ + input_report_key(udraw->joy_input_dev, BTN_WEST, data[0] &1);
drivers/hid/hid-udraw.c new file +1
-0+ input_report_key(udraw->joy_input_dev, BTN_SOUTH, data[0]&
2);drivers/hid/hid-udraw.c new file +1
-0+ input_report_key(udraw->joy_input_dev, BTN_EAST, data[0] &4);
drivers/hid/hid-udraw.c new file +1
-0+ input_report_key(udraw->joy_input_dev, BTN_NORTH, data[0]&
8);drivers/hid/hid-udraw.c new file +2
-0+ + input_report_key(udraw->joy_input_dev, BTN_SELECT, data[1]&
1);drivers/hid/hid-udraw.c new file +1
-0+ input_report_key(udraw->joy_input_dev, BTN_START, data[1]&
2);drivers/hid/hid-udraw.c new file +1
-0+ input_report_key(udraw->joy_input_dev, BTN_MODE, data[1] &16);
drivers/hid/hid-udraw.c new file +52
-0+ + x = y =0 ; +switch (data[2 ]) { +case 0x0 : + y =-127 ; +break ; +case 0x1 : + y =-127 ; + x =127 ; +break ; +case 0x2 : + x =127 ; +break ; +case 0x3 : + y =127 ; + x =127 ; +break ; +case 0x4 : + y =127 ; +break ; +case 0x5 : + y =127 ; + x =-127 ; +break ; +case 0x6 : + x =-127 ; +break ; +case 0x7 : + y =-127 ; + x =-127 ; +break ; +default : +break ; + } + +input_report_abs (udraw->joy_input_dev,ABS_X , x); +input_report_abs (udraw->joy_input_dev,ABS_Y , y); + +input_sync (udraw->joy_input_dev); + +/* For pen and touchpad */ + x = y =0 ; +if (touch !=TOUCH_NONE ) { +if (data[15 ] !=0x0F ) + x = data[15 ] *256 + data[17 ]; +if (data[16 ] !=0x0F ) + y = data[16 ] *256 + data[18 ]; + } + +/* touchpad */ +if (touch ==TOUCH_FINGER || touch ==TOUCH_FINGERS ) { + input_report_key(udraw->touch_input_dev,
BTN_TOUCH,
1);drivers/hid/hid-udraw.c new file +1
-0+ input_report_key(udraw->touch_input_dev,
BTN_TOOL_FINGER,drivers/hid/hid-udraw.c new file +2
-0+ touch == TOUCH_FINGER); + input_report_key(udraw->touch_input_dev,
BTN_TOOL_DOUBLETAP,drivers/hid/hid-udraw.c new file +3
-0+ touch == TOUCH_FINGERS); + + input_report_abs(udraw->touch_input_dev, ABS_X,x);
drivers/hid/hid-udraw.c new file +1
-0+ input_report_abs(udraw->touch_input_dev, ABS_Y,y);
drivers/hid/hid-udraw.c new file +2
-0+ }else { + input_report_key(udraw->touch_input_dev,
BTN_TOUCH,
0);drivers/hid/hid-udraw.c new file +1
-0+ input_report_key(udraw->touch_input_dev,
BTN_TOOL_FINGER, 0);drivers/hid/hid-udraw.c new file +1
-0+ input_report_key(udraw->touch_input_dev,
BTN_TOOL_DOUBLETAP, 0);drivers/hid/hid-udraw.c new file +11
-0+ } +input_sync (udraw->touch_input_dev); + +/* pen */ +if (touch ==TOUCH_PEN ) { +int level; + + level =clamp (data[13 ] -PRESSURE_OFFSET , +0 ,MAX_PRESSURE ); + + input_report_key(udraw->pen_input_dev, BTN_TOUCH,(level != 0));
drivers/hid/hid-udraw.c new file +1
-0+ input_report_key(udraw->pen_input_dev,
BTN_TOOL_PEN,
1);drivers/hid/hid-udraw.c new file +1
-0+ input_report_abs(udraw->pen_input_dev,
ABS_PRESSURE,
level);drivers/hid/hid-udraw.c new file +4
-0+input_report_abs (udraw->pen_input_dev,ABS_X , x); +input_report_abs (udraw->pen_input_dev,ABS_Y , y); + }else { + input_report_key(udraw->pen_input_dev, BTN_TOUCH,0);
drivers/hid/hid-udraw.c new file +1
-0+ input_report_abs(udraw->pen_input_dev,
ABS_PRESSURE,
0);drivers/hid/hid-udraw.c new file +1
-0+ input_report_key(udraw->pen_input_dev,
BTN_TOOL_PEN,
0);
Quoted 8 lines
drivers/hid/hid-udraw.c
Quoted 2 lines
drivers/hid/hid-udraw.c new file +2
-0+ } +input_sync (udraw->pen_input_dev);do me a favour and group the reports by type. it makes no difference to this
driver but event recordings are much easier to read this way. so allEV_ABSfirst, thenEV_KEY(or the other way round, don't care).
I put the EV_KEYs first, then EV_ABS. That was the only place where I did this...
Quoted 15 lines
drivers/hid/hid-udraw.c
Quoted 9 lines
drivers/hid/hid-udraw.c new file +8
-0+ +/* accel */ + x = (data[19 ] + (data[20 ] <<8 )); + x =clamp_accel (x,0 ); + y = (data[21 ] + (data[22 ] <<8 )); + y =clamp_accel (y,1 ); + z = (data[23 ] + (data[24 ] <<8 )); + z =clamp_accel (z,2 );this may not be kernel style, but any reason you can't use an enum here
instead of 0, 1, 2?clamp_accel(x, ACCEL_AXIS_X)would be more obvious to
read.
Done.
Quoted 52 lines
Quoted 52 lines
drivers/hid/hid-udraw.c new file +24
-0+input_report_abs (udraw->accel_input_dev,ABS_X , x); +input_report_abs (udraw->accel_input_dev,ABS_Y , y); +input_report_abs (udraw->accel_input_dev,ABS_Z , z); +input_sync (udraw->accel_input_dev); + +/* let hidraw and hiddev handle the report */ +return 0 ; +} + +static int udraw_open (struct input_dev *dev) +{ +struct udraw *udraw =input_get_drvdata (dev); + +return hid_hw_open (udraw->hdev); +} + +static void udraw_close (struct input_dev *dev) +{ +struct udraw *udraw =input_get_drvdata (dev); + +hid_hw_close (udraw->hdev); +} + +static struct input_dev *allocate_and_setup(struct hid_device*hdev,
drivers/hid/hid-udraw.c new file +26
-0+ const char *name) +{ +struct input_dev *input_dev; + + input_dev =devm_input_allocate_device (&hdev->dev); +if (!input_dev) +return NULL ; + + input_dev->name = name; + input_dev->phys = hdev->phys; + input_dev->dev.parent = &hdev->dev; + input_dev->open = udraw_open; + input_dev->close = udraw_close; + input_dev->uniq = hdev->uniq; + input_dev->id.bustype = hdev->bus; + input_dev->id.vendor = hdev->vendor; + input_dev->id.product = hdev->product; + input_dev->id.version = hdev->version; +input_set_drvdata (input_dev,hid_get_drvdata (hdev)); + +return input_dev; +} + +static bool udraw_setup_touch (struct udraw *udraw, +struct hid_device *hdev) +{
Quoted 8 lines
Quoted 4 lines
drivers/hid/hid-udraw.c new file +3
-0+struct input_dev *input_dev; + + input_dev = allocate_and_setup(hdev, DEVICE_NAME "(touchpad)");
no need to use () here. wacom device names are "foo Pen", "foo Finger", etc.
would be nice to continue that naming scheme.
Renamed.
Quoted 25 lines
Quoted 25 lines
drivers/hid/hid-udraw.c new file +24
-0+if (!input_dev) +return false; + + input_dev->evbit[0 ] =BIT (EV_ABS ) |BIT (EV_KEY ); + +set_bit (ABS_X , input_dev->absbit); +input_set_abs_params (input_dev,ABS_X ,0 ,RES_X ,1 ,0 ); +input_abs_set_res (input_dev,ABS_X ,RES_X /WIDTH ); +set_bit (ABS_Y , input_dev->absbit); +input_set_abs_params (input_dev,ABS_Y ,0 ,RES_Y ,1 ,0 ); +input_abs_set_res (input_dev,ABS_Y ,RES_Y /HEIGHT ); + +set_bit (BTN_TOUCH , input_dev->keybit); +set_bit (BTN_TOOL_FINGER , input_dev->keybit); +set_bit (BTN_TOOL_DOUBLETAP , input_dev->keybit); + +set_bit (INPUT_PROP_POINTER , input_dev->propbit); + + udraw->touch_input_dev = input_dev; + +return true; +} + +static bool udraw_setup_pen(struct udraw *udraw,
Quoted 8 lines
Quoted 6 lines
drivers/hid/hid-udraw.c new file +5
-0+ struct hid_device *hdev) +{ + struct input_dev *input_dev; + + input_dev = allocate_and_setup(hdev, DEVICE_NAME "(pen)");
see above for naming scheme
Done.
Quoted 27 lines
Quoted 27 lines
drivers/hid/hid-udraw.c new file +26
-0+if (!input_dev) +return false; + + input_dev->evbit[0 ] =BIT (EV_ABS ) |BIT (EV_KEY ); + +set_bit (ABS_X , input_dev->absbit); +input_set_abs_params (input_dev,ABS_X ,0 ,RES_X ,1 ,0 ); +input_abs_set_res (input_dev,ABS_X ,RES_X /WIDTH ); +set_bit (ABS_Y , input_dev->absbit); +input_set_abs_params (input_dev,ABS_Y ,0 ,RES_Y ,1 ,0 ); +input_abs_set_res (input_dev,ABS_Y ,RES_Y /HEIGHT ); +set_bit (ABS_PRESSURE , input_dev->absbit); +input_set_abs_params (input_dev,ABS_PRESSURE , +0 ,MAX_PRESSURE ,0 ,0 ); + +set_bit (BTN_TOUCH , input_dev->keybit); +set_bit (BTN_TOOL_PEN , input_dev->keybit); + +set_bit (INPUT_PROP_POINTER , input_dev->propbit); + + udraw->pen_input_dev = input_dev; + +return true; +} + +static bool udraw_setup_accel(struct udraw *udraw,
Quoted 8 lines
Quoted 6 lines
drivers/hid/hid-udraw.c new file +5
-0+ struct hid_device *hdev) +{ + struct input_dev *input_dev; + + input_dev = allocate_and_setup(hdev, DEVICE_NAME "(accelerometer)");
see above for naming scheme
Done.
Quoted 23 lines
Quoted 23 lines
drivers/hid/hid-udraw.c new file +22
-0+if (!input_dev) +return false; + + input_dev->evbit[0 ] =BIT (EV_ABS ); + +/* 1G accel is reported as ~256, so clamp to 2G */ +set_bit (ABS_X , input_dev->absbit); +input_set_abs_params (input_dev,ABS_X ,-512 ,512 ,0 ,0 ); +set_bit (ABS_Y , input_dev->absbit); +input_set_abs_params (input_dev,ABS_Y ,-512 ,512 ,0 ,0 ); +set_bit (ABS_Z , input_dev->absbit); +input_set_abs_params (input_dev,ABS_Z ,-512 ,512 ,0 ,0 ); + +set_bit (INPUT_PROP_ACCELEROMETER , input_dev->propbit); + + udraw->accel_input_dev = input_dev; + +return true; +} + +static bool udraw_setup_joypad (struct udraw *udraw, +struct hid_device *hdev)
Quoted 8 lines
Quoted 6 lines
drivers/hid/hid-udraw.c new file +5
-0+{ + struct input_dev *input_dev; + int i; + + input_dev = allocate_and_setup(hdev, DEVICE_NAME "(joypad)");
see above for naming scheme
Done.
Quoted 23 lines
Quoted 13 lines
drivers/hid/hid-udraw.c new file +12
-0+if (!input_dev) +return false; + + input_dev->evbit[0 ] =BIT (EV_KEY ) |BIT (EV_ABS ); + +set_bit (ABS_X , input_dev->absbit); +input_set_abs_params (input_dev,ABS_X ,-127 ,127 ,0 ,0 ); +set_bit (ABS_Y , input_dev->absbit); +input_set_abs_params (input_dev,ABS_Y ,-127 ,127 ,0 ,0 ); + +for (i =0 ; i <ARRAY_SIZE (udraw_joy_key_table); i++) + set_bit(udraw_joy_key_table[i], input_dev-Quoted 1 line
Quoted 1 line
keybit);
Personal opinion here: for the few buttons you have, the loop over an array
doesn't really get you much benefit over just having 7set_bit()calls. just
hardcoding allset_bitcalls (or movingjoy_key_tableto here) is that you
have all the init bits in one place for quick analysis.
Quoted 1 line
but I'm not going to argue this point too hard.
I moved all that to a flat list of calls.
All pushed to https://github.com/hadess/udraw until I get some more comments, or some parts of the protocol mysteriously appear ;)
Cheers
Quoted 85 lines
Cheers,
PeterQuoted 69 lines
drivers/hid/hid-udraw.c new file +7
-0+ + udraw->joy_input_dev = input_dev; + +return true; +} + +static int udraw_probe(struct hid_device *hdev, const struct
hid_device_id*id)drivers/hid/hid-udraw.c new file +5
-0+{ +struct udraw *udraw; +int ret; + + udraw = devm_kzalloc(&hdev->dev, sizeof(struct udraw),
GFP_KERNEL);drivers/hid/hid-udraw.c new file +31
-0+if (!udraw) +return -ENOMEM ; + + udraw->hdev = hdev; + +hid_set_drvdata (hdev, udraw); + + ret =hid_parse (hdev); +if (ret) { +hid_err (hdev,"parse failed\n" ); +return ret; + } + +if (!udraw_setup_joypad (udraw, hdev) || + !udraw_setup_touch(udraw, hdev) || + !udraw_setup_pen(udraw, hdev) || + !udraw_setup_accel(udraw, hdev)) { +hid_err (hdev,"could not allocate interfaces\n" ); +return -ENOMEM ; + } + + ret =input_register_device (udraw->joy_input_dev) || +input_register_device (udraw->touch_input_dev) || +input_register_device (udraw->pen_input_dev) || +input_register_device (udraw->accel_input_dev); +if (ret) { +hid_err (hdev,"failed to register interfaces\n" ); +return ret; + } + + ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW |
HID_CONNECT_DRIVER);drivers/hid/hid-udraw.c new file +10
-0+if (ret) { +hid_err (hdev,"hw start failed\n" ); +return ret; + } + +return 0 ; +} + +static const struct hid_device_id udraw_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_THQ,
USB_DEVICE_ID_THQ_PS3_UDRAW) },drivers/hid/hid-udraw.c new file +11
-0+ { } +}; +MODULE_DEVICE_TABLE (hid, udraw_devices); + +static struct hid_driver udraw_driver = { + .name ="hid-udraw" , + .id_table = udraw_devices, + .raw_event = udraw_raw_event, + .probe = udraw_probe, +}; +module_hid_driver (udraw_driver);Quoted 8 lines
--
2.7.4
--
To unsubscribe from this list: send the line "unsubscribe linux- input" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html--
To unsubscribe from this list: send the line "unsubscribe linux- input" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html