* [PATCH] Wacom Graphire Bluetooth driver
@ 2009-03-16 23:55 ` Bastien Nocera
0 siblings, 0 replies; 20+ messages in thread
From: Bastien Nocera @ 2009-03-16 23:55 UTC (permalink / raw)
To: linux-input
Cc: mjg, Peter Hutterer, zap-ez6wqqBRKvoox3rIn2DAYQ,
BlueZ development
>From 3495e3be72d1df6132d5f5d978d2def3e4d57fc3 Mon Sep 17 00:00:00 2001
From: Bastien Nocera <hadess-0MeiytkfxGOsTnJN9+BGXg@public.gmane.org>
Date: Mon, 16 Mar 2009 23:36:54 +0000
Subject: [PATCH] Wacom Graphire Bluetooth driver
Signed-off-by: Bastien Nocera <hadess-0MeiytkfxGOsTnJN9+BGXg@public.gmane.org>
Based on the work by Andrew Zabolotny, an HID driver for the Bluetooth
Wacom tablet. This is required as it uses a slightly different
protocols from what's currently support by the drivers/input/wacom*
driver, and those only support USB.
A user-space patch is required to activate mode 2 of the Wacom tablet,
as hidp does not support hid_output_raw_report.
---
drivers/hid/Kconfig | 7 ++
drivers/hid/Makefile | 1 +
drivers/hid/hid-core.c | 1 +
drivers/hid/hid-ids.h | 1 +
drivers/hid/hid-wacom.c | 272 +++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 282 insertions(+), 0 deletions(-)
create mode 100644 drivers/hid/hid-wacom.c
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index e85c8fe..f3244e3 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -261,6 +261,13 @@ config THRUSTMASTER_FF
Say Y here if you have a THRUSTMASTER FireStore Dual Power 2 or
a THRUSTMASTER Ferrari GT Rumble Force or Force Feedback Wheel.
+config HID_WACOM
+ tristate "Wacom Bluetooth devices support" if EMBEDDED
+ depends on BT_HIDP
+ default !EMBEDDED
+ ---help---
+ Support for Wacom Graphire Bluetooth tablet.
+
config ZEROPLUS_FF
tristate "Zeroplus based game controller support"
depends on USB_HID
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index fbd021f..410b302 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -41,6 +41,7 @@ obj-$(CONFIG_GREENASIA_FF) += hid-gaff.o
obj-$(CONFIG_THRUSTMASTER_FF) += hid-tmff.o
obj-$(CONFIG_HID_TOPSEED) += hid-topseed.o
obj-$(CONFIG_ZEROPLUS_FF) += hid-zpff.o
+obj-$(CONFIG_HID_WACOM) += hid-wacom.o
obj-$(CONFIG_USB_HID) += usbhid/
obj-$(CONFIG_USB_MOUSE) += usbhid/
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 1cc9674..d134f5d 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1305,6 +1305,7 @@ static const struct hid_device_id hid_blacklist[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb651) },
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb654) },
{ HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED, USB_DEVICE_ID_TOPSEED_CYBERLINK) },
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) },
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 8851197..e8f96c2 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -400,6 +400,7 @@
#define USB_DEVICE_ID_VERNIER_LCSPEC 0x0006
#define USB_VENDOR_ID_WACOM 0x056a
+#define USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH 0x81
#define USB_VENDOR_ID_WISEGROUP 0x0925
#define USB_DEVICE_ID_1_PHIDGETSERVO_20 0x8101
diff --git a/drivers/hid/hid-wacom.c b/drivers/hid/hid-wacom.c
new file mode 100644
index 0000000..8f9783f
--- /dev/null
+++ b/drivers/hid/hid-wacom.c
@@ -0,0 +1,272 @@
+/*
+ * Bluetooth Wacom Tablet support
+ *
+ * Copyright (c) 1999 Andreas Gal
+ * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech-AlSwsSmVLrQ@public.gmane.org>
+ * Copyright (c) 2005 Michael Haboustak <mike--vDbLwGUA7lNWk0Htik3J/w@public.gmane.org> for Concept2, Inc
+ * Copyright (c) 2006-2007 Jiri Kosina
+ * Copyright (c) 2007 Paul Walmsley
+ * Copyright (c) 2008 Jiri Slaby <jirislaby-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
+ * Copyright (c) 2006 Andrew Zabolotny <zap-ez6wqqBRKvoox3rIn2DAYQ@public.gmane.org>
+ * Copyright (c) 2009 Bastien Nocera <hadess-0MeiytkfxGOsTnJN9+BGXg@public.gmane.org>
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+struct wacom_data {
+ __u16 tool;
+ unsigned char butstate;
+};
+
+static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report,
+ u8 *raw_data, int size)
+{
+ struct wacom_data *wdata = hid_get_drvdata(hdev);
+ struct hid_input *hidinput;
+ struct input_dev *input;
+ unsigned char *data = (unsigned char *) raw_data;
+ int tool, x, y, rw, need_sync;
+
+ if (!(hdev->claimed & HID_CLAIMED_INPUT))
+ return 0;
+
+ tool = 0;
+ need_sync = 0;
+ hidinput = list_entry(hdev->inputs.next, struct hid_input, list);
+ input = hidinput->input;
+
+ /* Check if this is a tablet report */
+ if (data[0] != 0x03)
+ return 0;
+
+ /* Get X & Y positions */
+ x = le16_to_cpu(*(__le16 *) &data[2]);
+ y = le16_to_cpu(*(__le16 *) &data[4]);
+
+ /* Get current tool identifier */
+ if (data[1] & 0x90) { /* If pen is in the in/active area */
+ switch ((data[1] >> 5) & 3) {
+ case 0: /* Pen */
+ tool = BTN_TOOL_PEN;
+ break;
+
+ case 1: /* Rubber */
+ tool = BTN_TOOL_RUBBER;
+ break;
+
+ case 2: /* Mouse with wheel */
+ case 3: /* Mouse without wheel */
+ tool = BTN_TOOL_MOUSE;
+ break;
+ }
+
+ /* Reset tool if out of active tablet area */
+ if (!(data[1] & 0x10))
+ tool = 0;
+ }
+
+ /* If tool changed, notify input subsystem */
+ if (wdata->tool != tool) {
+ if (wdata->tool) {
+ /* Completely reset old tool state */
+ if (wdata->tool == BTN_TOOL_MOUSE) {
+ input_report_key(input, BTN_LEFT, 0);
+ input_report_key(input, BTN_RIGHT, 0);
+ input_report_key(input, BTN_MIDDLE, 0);
+ input_report_abs(input, ABS_DISTANCE,
+ input->absmax[ABS_DISTANCE]);
+ } else {
+ input_report_key(input, BTN_TOUCH, 0);
+ input_report_key(input, BTN_STYLUS, 0);
+ input_report_key(input, BTN_STYLUS2, 0);
+ input_report_abs(input, ABS_PRESSURE, 0);
+ }
+ input_sync(input);
+ input_report_key(input, wdata->tool, 0);
+ input_sync(input);
+ }
+ wdata->tool = tool;
+ if (tool) {
+ input_report_key(input, tool, 1);
+ need_sync = 1;
+ }
+ }
+
+ if (tool) {
+ input_report_abs(input, ABS_X, x);
+ input_report_abs(input, ABS_Y, y);
+ need_sync = 1;
+
+ switch ((data[1] >> 5) & 3) {
+ case 2: /* Mouse with wheel */
+ input_report_key(input, BTN_MIDDLE, data[1] & 0x04);
+ rw = (data[6] & 0x01) ? -1 :
+ (data[6] & 0x02) ? 1 : 0;
+ input_report_rel(input, REL_WHEEL, rw);
+ /* fall through */
+
+ case 3: /* Mouse without wheel */
+ input_report_key(input, BTN_LEFT, data[1] & 0x01);
+ input_report_key(input, BTN_RIGHT, data[1] & 0x02);
+ /* Compute distance between mouse and tablet */
+ rw = 44 - (data[6] >> 2);
+ if (rw < 0)
+ rw = 0;
+ else if (rw > 31)
+ rw = 31;
+ input_report_abs(input, ABS_DISTANCE, rw);
+ break;
+
+ default:
+ input_report_abs(input, ABS_PRESSURE,
+ data[6] | (((__u16) (data[1] & 0x08)) << 5));
+ input_report_key(input, BTN_TOUCH, data[1] & 0x01);
+ input_report_key(input, BTN_STYLUS, data[1] & 0x02);
+ input_report_key(input, BTN_STYLUS2, data[1] & 0x04);
+ break;
+ }
+ }
+
+ if (need_sync) {
+ input_sync(input);
+ need_sync = 0;
+ }
+
+ /* Report the state of the two buttons at the top of the tablet
+ * as two extra fingerpad keys (buttons 4 & 5). */
+ rw = data[7] & 0x03;
+ if (rw != wdata->butstate) {
+ wdata->butstate = rw;
+ input_report_key(input, BTN_0, rw & 0x02);
+ input_report_key(input, BTN_1, rw & 0x01);
+ need_sync = 1;
+ }
+
+ if (need_sync) {
+ input_event(input, EV_MSC, MSC_SERIAL, 0xf0);
+ input_sync(input);
+ }
+
+ return 1;
+}
+
+static int wacom_probe(struct hid_device *hdev,
+ const struct hid_device_id *id)
+{
+ struct hid_input *hidinput;
+ struct input_dev *input;
+ struct wacom_data *wdata;
+ int ret;
+
+ wdata = kzalloc(sizeof(*wdata), GFP_KERNEL);
+ if (wdata == NULL) {
+ dev_err(&hdev->dev, "can't alloc wacom descriptor\n");
+ return -ENOMEM;
+ }
+
+ hid_set_drvdata(hdev, wdata);
+
+ ret = hid_parse(hdev);
+ if (ret) {
+ dev_err(&hdev->dev, "parse failed\n");
+ goto err_free;
+ }
+
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+ if (ret) {
+ dev_err(&hdev->dev, "hw start failed\n");
+ goto err_free;
+ }
+
+ hidinput = list_entry(hdev->inputs.next, struct hid_input, list);
+ input = hidinput->input;
+
+ /* Basics */
+ input->evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_REL);
+ input->absbit[0] |= BIT(ABS_X) | BIT(ABS_Y) |
+ BIT(ABS_PRESSURE) | BIT(ABS_DISTANCE);
+ input->relbit[0] |= BIT(REL_WHEEL);
+ set_bit(BTN_TOOL_PEN, input->keybit);
+ set_bit(BTN_TOUCH, input->keybit);
+ set_bit(BTN_STYLUS, input->keybit);
+ set_bit(BTN_STYLUS2, input->keybit);
+ set_bit(BTN_LEFT, input->keybit);
+ set_bit(BTN_RIGHT, input->keybit);
+ set_bit(BTN_MIDDLE, input->keybit);
+
+ /* Pad */
+ input->evbit[0] |= BIT(EV_MSC);
+ input->mscbit[0] |= BIT(MSC_SERIAL);
+
+ /* Distance, rubber and mouse */
+ input->absbit[0] |= BIT(ABS_DISTANCE);
+ set_bit(BTN_TOOL_RUBBER, input->keybit);
+ set_bit(BTN_TOOL_MOUSE, input->keybit);
+
+ input->absmax[ABS_PRESSURE] = 511;
+ input->absmax[ABS_DISTANCE] = 32;
+
+ input->absmax[ABS_X] = 16704;
+ input->absmax[ABS_Y] = 12064;
+ input->absfuzz[ABS_X] = 4;
+ input->absfuzz[ABS_Y] = 4;
+
+ return 0;
+err_free:
+ kfree(wdata);
+ return ret;
+}
+
+static void wacom_remove(struct hid_device *hdev)
+{
+ hid_hw_stop(hdev);
+ kfree(hid_get_drvdata(hdev));
+}
+
+static const struct hid_device_id wacom_devices[] = {
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) },
+
+ { }
+};
+MODULE_DEVICE_TABLE(hid, wacom_devices);
+
+static struct hid_driver wacom_driver = {
+ .name = "wacom",
+ .id_table = wacom_devices,
+ .probe = wacom_probe,
+ .remove = wacom_remove,
+ .raw_event = wacom_raw_event,
+};
+
+static int wacom_init(void)
+{
+ int ret;
+
+ ret = hid_register_driver(&wacom_driver);
+ if (ret)
+ printk(KERN_ERR "can't register wacom driver\n");
+ printk(KERN_ERR "wacom driver registered\n");
+ return ret;
+}
+
+static void wacom_exit(void)
+{
+ hid_unregister_driver(&wacom_driver);
+}
+
+module_init(wacom_init);
+module_exit(wacom_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(wacom);
--
1.6.2
^ permalink raw reply related [flat|nested] 20+ messages in thread* Re: [PATCH] Wacom Graphire Bluetooth driver (updated with a few fixes)
2009-03-16 23:55 ` Bastien Nocera
@ 2009-03-18 0:11 ` Bastien Nocera
-1 siblings, 0 replies; 20+ messages in thread
From: Bastien Nocera @ 2009-03-18 0:11 UTC (permalink / raw)
To: linux-input; +Cc: mjg, Peter Hutterer, zap, BlueZ development
>>From 99074a7cf9622837af84d330e07bdb46307c254f Mon Sep 17 00:00:00 2001
From: Bastien Nocera <hadess@hadess.net>
Date: Mon, 16 Mar 2009 23:36:54 +0000
Subject: [PATCH] Wacom Graphire Bluetooth driver
Signed-off-by: Bastien Nocera <hadess@hadess.net>
Based on the work by Andrew Zabolotny, an HID driver for the Bluetooth
Wacom tablet. This is required as it uses a slightly different
protocols from what's currently support by the drivers/input/wacom*
driver, and those only support USB.
A user-space patch is required to activate mode 2 of the Wacom tablet,
as hidp does not support hid_output_raw_report.
---
drivers/hid/Kconfig | 7 ++
drivers/hid/Makefile | 1 +
drivers/hid/hid-core.c | 1 +
drivers/hid/hid-ids.h | 1 +
drivers/hid/hid-wacom.c | 260 +++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 270 insertions(+), 0 deletions(-)
create mode 100644 drivers/hid/hid-wacom.c
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index e85c8fe..f3244e3 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -261,6 +261,13 @@ config THRUSTMASTER_FF
Say Y here if you have a THRUSTMASTER FireStore Dual Power 2 or
a THRUSTMASTER Ferrari GT Rumble Force or Force Feedback Wheel.
+config HID_WACOM
+ tristate "Wacom Bluetooth devices support" if EMBEDDED
+ depends on BT_HIDP
+ default !EMBEDDED
+ ---help---
+ Support for Wacom Graphire Bluetooth tablet.
+
config ZEROPLUS_FF
tristate "Zeroplus based game controller support"
depends on USB_HID
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index fbd021f..410b302 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -41,6 +41,7 @@ obj-$(CONFIG_GREENASIA_FF) += hid-gaff.o
obj-$(CONFIG_THRUSTMASTER_FF) += hid-tmff.o
obj-$(CONFIG_HID_TOPSEED) += hid-topseed.o
obj-$(CONFIG_ZEROPLUS_FF) += hid-zpff.o
+obj-$(CONFIG_HID_WACOM) += hid-wacom.o
obj-$(CONFIG_USB_HID) += usbhid/
obj-$(CONFIG_USB_MOUSE) += usbhid/
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 1cc9674..d134f5d 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1305,6 +1305,7 @@ static const struct hid_device_id hid_blacklist[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb651) },
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb654) },
{ HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED, USB_DEVICE_ID_TOPSEED_CYBERLINK) },
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) },
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 8851197..e8f96c2 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -400,6 +400,7 @@
#define USB_DEVICE_ID_VERNIER_LCSPEC 0x0006
#define USB_VENDOR_ID_WACOM 0x056a
+#define USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH 0x81
#define USB_VENDOR_ID_WISEGROUP 0x0925
#define USB_DEVICE_ID_1_PHIDGETSERVO_20 0x8101
diff --git a/drivers/hid/hid-wacom.c b/drivers/hid/hid-wacom.c
new file mode 100644
index 0000000..67c8c3a
--- /dev/null
+++ b/drivers/hid/hid-wacom.c
@@ -0,0 +1,260 @@
+/*
+ * Bluetooth Wacom Tablet support
+ *
+ * Copyright (c) 1999 Andreas Gal
+ * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ * Copyright (c) 2006-2007 Jiri Kosina
+ * Copyright (c) 2007 Paul Walmsley
+ * Copyright (c) 2008 Jiri Slaby <jirislaby@gmail.com>
+ * Copyright (c) 2006 Andrew Zabolotny <zap@homelink.ru>
+ * Copyright (c) 2009 Bastien Nocera <hadess@hadess.net>
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+struct wacom_data {
+ __u16 tool;
+ unsigned char butstate;
+};
+
+static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report,
+ u8 *raw_data, int size)
+{
+ struct wacom_data *wdata = hid_get_drvdata(hdev);
+ struct hid_input *hidinput;
+ struct input_dev *input;
+ unsigned char *data = (unsigned char *) raw_data;
+ int tool, x, y, rw;
+
+ if (!(hdev->claimed & HID_CLAIMED_INPUT))
+ return 0;
+
+ tool = 0;
+ hidinput = list_entry(hdev->inputs.next, struct hid_input, list);
+ input = hidinput->input;
+
+ /* Check if this is a tablet report */
+ if (data[0] != 0x03)
+ return 0;
+
+ /* Get X & Y positions */
+ x = le16_to_cpu(*(__le16 *) &data[2]);
+ y = le16_to_cpu(*(__le16 *) &data[4]);
+
+ /* Get current tool identifier */
+ if (data[1] & 0x90) { /* If pen is in the in/active area */
+ switch ((data[1] >> 5) & 3) {
+ case 0: /* Pen */
+ tool = BTN_TOOL_PEN;
+ break;
+
+ case 1: /* Rubber */
+ tool = BTN_TOOL_RUBBER;
+ break;
+
+ case 2: /* Mouse with wheel */
+ case 3: /* Mouse without wheel */
+ tool = BTN_TOOL_MOUSE;
+ break;
+ }
+
+ /* Reset tool if out of active tablet area */
+ if (!(data[1] & 0x10))
+ tool = 0;
+ }
+
+ /* If tool changed, notify input subsystem */
+ if (wdata->tool != tool) {
+ if (wdata->tool) {
+ /* Completely reset old tool state */
+ if (wdata->tool == BTN_TOOL_MOUSE) {
+ input_report_key(input, BTN_LEFT, 0);
+ input_report_key(input, BTN_RIGHT, 0);
+ input_report_key(input, BTN_MIDDLE, 0);
+ input_report_abs(input, ABS_DISTANCE,
+ input->absmax[ABS_DISTANCE]);
+ } else {
+ input_report_key(input, BTN_TOUCH, 0);
+ input_report_key(input, BTN_STYLUS, 0);
+ input_report_key(input, BTN_STYLUS2, 0);
+ input_report_abs(input, ABS_PRESSURE, 0);
+ }
+ input_report_key(input, wdata->tool, 0);
+ input_sync(input);
+ }
+ wdata->tool = tool;
+ if (tool)
+ input_report_key(input, tool, 1);
+ }
+
+ if (tool) {
+ input_report_abs(input, ABS_X, x);
+ input_report_abs(input, ABS_Y, y);
+
+ switch ((data[1] >> 5) & 3) {
+ case 2: /* Mouse with wheel */
+ input_report_key(input, BTN_MIDDLE, data[1] & 0x04);
+ rw = (data[6] & 0x01) ? -1 :
+ (data[6] & 0x02) ? 1 : 0;
+ input_report_rel(input, REL_WHEEL, rw);
+ /* fall through */
+
+ case 3: /* Mouse without wheel */
+ input_report_key(input, BTN_LEFT, data[1] & 0x01);
+ input_report_key(input, BTN_RIGHT, data[1] & 0x02);
+ /* Compute distance between mouse and tablet */
+ rw = 44 - (data[6] >> 2);
+ if (rw < 0)
+ rw = 0;
+ else if (rw > 31)
+ rw = 31;
+ input_report_abs(input, ABS_DISTANCE, rw);
+ break;
+
+ default:
+ input_report_abs(input, ABS_PRESSURE,
+ data[6] | (((__u16) (data[1] & 0x08)) << 5));
+ input_report_key(input, BTN_TOUCH, data[1] & 0x01);
+ input_report_key(input, BTN_STYLUS, data[1] & 0x02);
+ input_report_key(input, BTN_STYLUS2, (tool == BTN_TOOL_PEN) && data[1] & 0x04);
+ break;
+ }
+
+ input_sync(input);
+ }
+
+ /* Report the state of the two buttons at the top of the tablet
+ * as two extra fingerpad keys (buttons 4 & 5). */
+ rw = data[7] & 0x03;
+ if (rw != wdata->butstate) {
+ wdata->butstate = rw;
+ input_report_key(input, BTN_0, rw & 0x02);
+ input_report_key(input, BTN_1, rw & 0x01);
+ input_event(input, EV_MSC, MSC_SERIAL, 0xf0);
+ input_sync(input);
+ }
+
+ return 1;
+}
+
+static int wacom_probe(struct hid_device *hdev,
+ const struct hid_device_id *id)
+{
+ struct hid_input *hidinput;
+ struct input_dev *input;
+ struct wacom_data *wdata;
+ int ret;
+
+ wdata = kzalloc(sizeof(*wdata), GFP_KERNEL);
+ if (wdata == NULL) {
+ dev_err(&hdev->dev, "can't alloc wacom descriptor\n");
+ return -ENOMEM;
+ }
+
+ hid_set_drvdata(hdev, wdata);
+
+ ret = hid_parse(hdev);
+ if (ret) {
+ dev_err(&hdev->dev, "parse failed\n");
+ goto err_free;
+ }
+
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+ if (ret) {
+ dev_err(&hdev->dev, "hw start failed\n");
+ goto err_free;
+ }
+
+ hidinput = list_entry(hdev->inputs.next, struct hid_input, list);
+ input = hidinput->input;
+
+ /* Basics */
+ input->evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_REL);
+ input->absbit[0] |= BIT(ABS_X) | BIT(ABS_Y) |
+ BIT(ABS_PRESSURE) | BIT(ABS_DISTANCE);
+ input->relbit[0] |= BIT(REL_WHEEL);
+ set_bit(BTN_TOOL_PEN, input->keybit);
+ set_bit(BTN_TOUCH, input->keybit);
+ set_bit(BTN_STYLUS, input->keybit);
+ set_bit(BTN_STYLUS2, input->keybit);
+ set_bit(BTN_LEFT, input->keybit);
+ set_bit(BTN_RIGHT, input->keybit);
+ set_bit(BTN_MIDDLE, input->keybit);
+
+ /* Pad */
+ input->evbit[0] |= BIT(EV_MSC);
+ input->mscbit[0] |= BIT(MSC_SERIAL);
+
+ /* Distance, rubber and mouse */
+ input->absbit[0] |= BIT(ABS_DISTANCE);
+ set_bit(BTN_TOOL_RUBBER, input->keybit);
+ set_bit(BTN_TOOL_MOUSE, input->keybit);
+
+ input->absmax[ABS_PRESSURE] = 511;
+ input->absmax[ABS_DISTANCE] = 32;
+
+ input->absmax[ABS_X] = 16704;
+ input->absmax[ABS_Y] = 12064;
+ input->absfuzz[ABS_X] = 4;
+ input->absfuzz[ABS_Y] = 4;
+
+ return 0;
+err_free:
+ kfree(wdata);
+ return ret;
+}
+
+static void wacom_remove(struct hid_device *hdev)
+{
+ hid_hw_stop(hdev);
+ kfree(hid_get_drvdata(hdev));
+}
+
+static const struct hid_device_id wacom_devices[] = {
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) },
+
+ { }
+};
+MODULE_DEVICE_TABLE(hid, wacom_devices);
+
+static struct hid_driver wacom_driver = {
+ .name = "wacom",
+ .id_table = wacom_devices,
+ .probe = wacom_probe,
+ .remove = wacom_remove,
+ .raw_event = wacom_raw_event,
+};
+
+static int wacom_init(void)
+{
+ int ret;
+
+ ret = hid_register_driver(&wacom_driver);
+ if (ret)
+ printk(KERN_ERR "can't register wacom driver\n");
+ printk(KERN_ERR "wacom driver registered\n");
+ return ret;
+}
+
+static void wacom_exit(void)
+{
+ hid_unregister_driver(&wacom_driver);
+}
+
+module_init(wacom_init);
+module_exit(wacom_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(wacom);
--
1.6.2
^ permalink raw reply related [flat|nested] 20+ messages in thread* Re: [PATCH] Wacom Graphire Bluetooth driver (updated with a few fixes)
@ 2009-03-18 0:11 ` Bastien Nocera
0 siblings, 0 replies; 20+ messages in thread
From: Bastien Nocera @ 2009-03-18 0:11 UTC (permalink / raw)
To: linux-input; +Cc: mjg, Peter Hutterer, zap, BlueZ development
>From 99074a7cf9622837af84d330e07bdb46307c254f Mon Sep 17 00:00:00 2001
From: Bastien Nocera <hadess@hadess.net>
Date: Mon, 16 Mar 2009 23:36:54 +0000
Subject: [PATCH] Wacom Graphire Bluetooth driver
Signed-off-by: Bastien Nocera <hadess@hadess.net>
Based on the work by Andrew Zabolotny, an HID driver for the Bluetooth
Wacom tablet. This is required as it uses a slightly different
protocols from what's currently support by the drivers/input/wacom*
driver, and those only support USB.
A user-space patch is required to activate mode 2 of the Wacom tablet,
as hidp does not support hid_output_raw_report.
---
drivers/hid/Kconfig | 7 ++
drivers/hid/Makefile | 1 +
drivers/hid/hid-core.c | 1 +
drivers/hid/hid-ids.h | 1 +
drivers/hid/hid-wacom.c | 260 +++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 270 insertions(+), 0 deletions(-)
create mode 100644 drivers/hid/hid-wacom.c
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index e85c8fe..f3244e3 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -261,6 +261,13 @@ config THRUSTMASTER_FF
Say Y here if you have a THRUSTMASTER FireStore Dual Power 2 or
a THRUSTMASTER Ferrari GT Rumble Force or Force Feedback Wheel.
+config HID_WACOM
+ tristate "Wacom Bluetooth devices support" if EMBEDDED
+ depends on BT_HIDP
+ default !EMBEDDED
+ ---help---
+ Support for Wacom Graphire Bluetooth tablet.
+
config ZEROPLUS_FF
tristate "Zeroplus based game controller support"
depends on USB_HID
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index fbd021f..410b302 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -41,6 +41,7 @@ obj-$(CONFIG_GREENASIA_FF) += hid-gaff.o
obj-$(CONFIG_THRUSTMASTER_FF) += hid-tmff.o
obj-$(CONFIG_HID_TOPSEED) += hid-topseed.o
obj-$(CONFIG_ZEROPLUS_FF) += hid-zpff.o
+obj-$(CONFIG_HID_WACOM) += hid-wacom.o
obj-$(CONFIG_USB_HID) += usbhid/
obj-$(CONFIG_USB_MOUSE) += usbhid/
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 1cc9674..d134f5d 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1305,6 +1305,7 @@ static const struct hid_device_id hid_blacklist[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb651) },
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb654) },
{ HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED, USB_DEVICE_ID_TOPSEED_CYBERLINK) },
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) },
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 8851197..e8f96c2 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -400,6 +400,7 @@
#define USB_DEVICE_ID_VERNIER_LCSPEC 0x0006
#define USB_VENDOR_ID_WACOM 0x056a
+#define USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH 0x81
#define USB_VENDOR_ID_WISEGROUP 0x0925
#define USB_DEVICE_ID_1_PHIDGETSERVO_20 0x8101
diff --git a/drivers/hid/hid-wacom.c b/drivers/hid/hid-wacom.c
new file mode 100644
index 0000000..67c8c3a
--- /dev/null
+++ b/drivers/hid/hid-wacom.c
@@ -0,0 +1,260 @@
+/*
+ * Bluetooth Wacom Tablet support
+ *
+ * Copyright (c) 1999 Andreas Gal
+ * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ * Copyright (c) 2006-2007 Jiri Kosina
+ * Copyright (c) 2007 Paul Walmsley
+ * Copyright (c) 2008 Jiri Slaby <jirislaby@gmail.com>
+ * Copyright (c) 2006 Andrew Zabolotny <zap@homelink.ru>
+ * Copyright (c) 2009 Bastien Nocera <hadess@hadess.net>
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+struct wacom_data {
+ __u16 tool;
+ unsigned char butstate;
+};
+
+static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report,
+ u8 *raw_data, int size)
+{
+ struct wacom_data *wdata = hid_get_drvdata(hdev);
+ struct hid_input *hidinput;
+ struct input_dev *input;
+ unsigned char *data = (unsigned char *) raw_data;
+ int tool, x, y, rw;
+
+ if (!(hdev->claimed & HID_CLAIMED_INPUT))
+ return 0;
+
+ tool = 0;
+ hidinput = list_entry(hdev->inputs.next, struct hid_input, list);
+ input = hidinput->input;
+
+ /* Check if this is a tablet report */
+ if (data[0] != 0x03)
+ return 0;
+
+ /* Get X & Y positions */
+ x = le16_to_cpu(*(__le16 *) &data[2]);
+ y = le16_to_cpu(*(__le16 *) &data[4]);
+
+ /* Get current tool identifier */
+ if (data[1] & 0x90) { /* If pen is in the in/active area */
+ switch ((data[1] >> 5) & 3) {
+ case 0: /* Pen */
+ tool = BTN_TOOL_PEN;
+ break;
+
+ case 1: /* Rubber */
+ tool = BTN_TOOL_RUBBER;
+ break;
+
+ case 2: /* Mouse with wheel */
+ case 3: /* Mouse without wheel */
+ tool = BTN_TOOL_MOUSE;
+ break;
+ }
+
+ /* Reset tool if out of active tablet area */
+ if (!(data[1] & 0x10))
+ tool = 0;
+ }
+
+ /* If tool changed, notify input subsystem */
+ if (wdata->tool != tool) {
+ if (wdata->tool) {
+ /* Completely reset old tool state */
+ if (wdata->tool == BTN_TOOL_MOUSE) {
+ input_report_key(input, BTN_LEFT, 0);
+ input_report_key(input, BTN_RIGHT, 0);
+ input_report_key(input, BTN_MIDDLE, 0);
+ input_report_abs(input, ABS_DISTANCE,
+ input->absmax[ABS_DISTANCE]);
+ } else {
+ input_report_key(input, BTN_TOUCH, 0);
+ input_report_key(input, BTN_STYLUS, 0);
+ input_report_key(input, BTN_STYLUS2, 0);
+ input_report_abs(input, ABS_PRESSURE, 0);
+ }
+ input_report_key(input, wdata->tool, 0);
+ input_sync(input);
+ }
+ wdata->tool = tool;
+ if (tool)
+ input_report_key(input, tool, 1);
+ }
+
+ if (tool) {
+ input_report_abs(input, ABS_X, x);
+ input_report_abs(input, ABS_Y, y);
+
+ switch ((data[1] >> 5) & 3) {
+ case 2: /* Mouse with wheel */
+ input_report_key(input, BTN_MIDDLE, data[1] & 0x04);
+ rw = (data[6] & 0x01) ? -1 :
+ (data[6] & 0x02) ? 1 : 0;
+ input_report_rel(input, REL_WHEEL, rw);
+ /* fall through */
+
+ case 3: /* Mouse without wheel */
+ input_report_key(input, BTN_LEFT, data[1] & 0x01);
+ input_report_key(input, BTN_RIGHT, data[1] & 0x02);
+ /* Compute distance between mouse and tablet */
+ rw = 44 - (data[6] >> 2);
+ if (rw < 0)
+ rw = 0;
+ else if (rw > 31)
+ rw = 31;
+ input_report_abs(input, ABS_DISTANCE, rw);
+ break;
+
+ default:
+ input_report_abs(input, ABS_PRESSURE,
+ data[6] | (((__u16) (data[1] & 0x08)) << 5));
+ input_report_key(input, BTN_TOUCH, data[1] & 0x01);
+ input_report_key(input, BTN_STYLUS, data[1] & 0x02);
+ input_report_key(input, BTN_STYLUS2, (tool == BTN_TOOL_PEN) && data[1] & 0x04);
+ break;
+ }
+
+ input_sync(input);
+ }
+
+ /* Report the state of the two buttons at the top of the tablet
+ * as two extra fingerpad keys (buttons 4 & 5). */
+ rw = data[7] & 0x03;
+ if (rw != wdata->butstate) {
+ wdata->butstate = rw;
+ input_report_key(input, BTN_0, rw & 0x02);
+ input_report_key(input, BTN_1, rw & 0x01);
+ input_event(input, EV_MSC, MSC_SERIAL, 0xf0);
+ input_sync(input);
+ }
+
+ return 1;
+}
+
+static int wacom_probe(struct hid_device *hdev,
+ const struct hid_device_id *id)
+{
+ struct hid_input *hidinput;
+ struct input_dev *input;
+ struct wacom_data *wdata;
+ int ret;
+
+ wdata = kzalloc(sizeof(*wdata), GFP_KERNEL);
+ if (wdata == NULL) {
+ dev_err(&hdev->dev, "can't alloc wacom descriptor\n");
+ return -ENOMEM;
+ }
+
+ hid_set_drvdata(hdev, wdata);
+
+ ret = hid_parse(hdev);
+ if (ret) {
+ dev_err(&hdev->dev, "parse failed\n");
+ goto err_free;
+ }
+
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+ if (ret) {
+ dev_err(&hdev->dev, "hw start failed\n");
+ goto err_free;
+ }
+
+ hidinput = list_entry(hdev->inputs.next, struct hid_input, list);
+ input = hidinput->input;
+
+ /* Basics */
+ input->evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_REL);
+ input->absbit[0] |= BIT(ABS_X) | BIT(ABS_Y) |
+ BIT(ABS_PRESSURE) | BIT(ABS_DISTANCE);
+ input->relbit[0] |= BIT(REL_WHEEL);
+ set_bit(BTN_TOOL_PEN, input->keybit);
+ set_bit(BTN_TOUCH, input->keybit);
+ set_bit(BTN_STYLUS, input->keybit);
+ set_bit(BTN_STYLUS2, input->keybit);
+ set_bit(BTN_LEFT, input->keybit);
+ set_bit(BTN_RIGHT, input->keybit);
+ set_bit(BTN_MIDDLE, input->keybit);
+
+ /* Pad */
+ input->evbit[0] |= BIT(EV_MSC);
+ input->mscbit[0] |= BIT(MSC_SERIAL);
+
+ /* Distance, rubber and mouse */
+ input->absbit[0] |= BIT(ABS_DISTANCE);
+ set_bit(BTN_TOOL_RUBBER, input->keybit);
+ set_bit(BTN_TOOL_MOUSE, input->keybit);
+
+ input->absmax[ABS_PRESSURE] = 511;
+ input->absmax[ABS_DISTANCE] = 32;
+
+ input->absmax[ABS_X] = 16704;
+ input->absmax[ABS_Y] = 12064;
+ input->absfuzz[ABS_X] = 4;
+ input->absfuzz[ABS_Y] = 4;
+
+ return 0;
+err_free:
+ kfree(wdata);
+ return ret;
+}
+
+static void wacom_remove(struct hid_device *hdev)
+{
+ hid_hw_stop(hdev);
+ kfree(hid_get_drvdata(hdev));
+}
+
+static const struct hid_device_id wacom_devices[] = {
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) },
+
+ { }
+};
+MODULE_DEVICE_TABLE(hid, wacom_devices);
+
+static struct hid_driver wacom_driver = {
+ .name = "wacom",
+ .id_table = wacom_devices,
+ .probe = wacom_probe,
+ .remove = wacom_remove,
+ .raw_event = wacom_raw_event,
+};
+
+static int wacom_init(void)
+{
+ int ret;
+
+ ret = hid_register_driver(&wacom_driver);
+ if (ret)
+ printk(KERN_ERR "can't register wacom driver\n");
+ printk(KERN_ERR "wacom driver registered\n");
+ return ret;
+}
+
+static void wacom_exit(void)
+{
+ hid_unregister_driver(&wacom_driver);
+}
+
+module_init(wacom_init);
+module_exit(wacom_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(wacom);
--
1.6.2
^ permalink raw reply related [flat|nested] 20+ messages in thread* Re: [PATCH] Wacom Graphire Bluetooth driver (updated with a few fixes)
2009-03-18 0:11 ` Bastien Nocera
(?)
@ 2009-03-18 21:28 ` Andrew Zabolotny
2009-03-18 22:47 ` Bastien Nocera
-1 siblings, 1 reply; 20+ messages in thread
From: Andrew Zabolotny @ 2009-03-18 21:28 UTC (permalink / raw)
To: Bastien Nocera; +Cc: linux-input, mjg, Peter Hutterer, BlueZ development
[-- Attachment #1: Type: text/plain, Size: 715 bytes --]
From Wed, 18 Mar 2009 00:11:52 +0000
Bastien Nocera <hadess@hadess.net> wrote:
> Based on the work by Andrew Zabolotny, an HID driver for the Bluetooth
> Wacom tablet.
Great to see my old work was finally useful :) I tried in the past to
contact the bluetooth stack author to submit my patch, but got no answer
and gave up.
Also I like the fact that you have dropped my wicked out-of-active-area
pseudo-buttons support. Such kind of things should be implemented, if
needed, in the x11 driver (but the driver would need a way to report
out-of-active area stylus presses).
What's that "mode 2 patch" you're talking about? Should it be applied
to hidd, and is it available somewhere?
--
Andrew
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] Wacom Graphire Bluetooth driver (updated with a few fixes)
2009-03-18 21:28 ` Andrew Zabolotny
@ 2009-03-18 22:47 ` Bastien Nocera
2009-03-28 19:35 ` Andrew Zabolotny
0 siblings, 1 reply; 20+ messages in thread
From: Bastien Nocera @ 2009-03-18 22:47 UTC (permalink / raw)
To: Andrew Zabolotny; +Cc: linux-input, mjg, Peter Hutterer, BlueZ development
On Thu, 2009-03-19 at 00:28 +0300, Andrew Zabolotny wrote:
> From Wed, 18 Mar 2009 00:11:52 +0000
> Bastien Nocera <hadess@hadess.net> wrote:
>
> > Based on the work by Andrew Zabolotny, an HID driver for the Bluetooth
> > Wacom tablet.
> Great to see my old work was finally useful :) I tried in the past to
> contact the bluetooth stack author to submit my patch, but got no answer
> and gave up.
I think that the main problem was because, at that time, there was no
such thing as the HID sub-system to avoid having to reimplement things
twice for Bluetooth and USB devices.
And adding support for a specific device in the hidp driver isn't the
best way to do this. Nowadays the driver for joysticks and keyboards are
the same whether Bluetooth or USB.
> Also I like the fact that you have dropped my wicked out-of-active-area
> pseudo-buttons support. Such kind of things should be implemented, if
> needed, in the x11 driver (but the driver would need a way to report
> out-of-active area stylus presses).
I removed it because the other drivers didn't implement it. If it were
to be implemented, the USB drivers would need to support it as well, so
that the interface is agreed upon.
Better start with something small, and get it merged, then discuss
extensions.
> What's that "mode 2 patch" you're talking about? Should it be applied
> to hidd, and is it available somewhere?
It's at:
http://cvs.fedoraproject.org/viewvc/rpms/bluez/devel/bluez-activate-wacom-mode2.patch?view=markup
And it's a patch to input plugin for bluetoothd, not hidd. hidd is the
BlueZ 3.x daemon, we've been at BlueZ 4.x for a while.
The bluetoothd patch is already in Fedora rawhide, and the kernel patch
will get there once we've released Fedora 11 Beta.
Cheers
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] Wacom Graphire Bluetooth driver (updated with a few fixes)
2009-03-18 22:47 ` Bastien Nocera
@ 2009-03-28 19:35 ` Andrew Zabolotny
0 siblings, 0 replies; 20+ messages in thread
From: Andrew Zabolotny @ 2009-03-28 19:35 UTC (permalink / raw)
To: Bastien Nocera, linux-input
[-- Attachment #1: Type: text/plain, Size: 1328 bytes --]
From Wed, 18 Mar 2009 22:47:28 +0000
Bastien Nocera <hadess@hadess.net> wrote:
> I think that the main problem was because, at that time, there was no
> such thing as the HID sub-system to avoid having to reimplement things
> twice for Bluetooth and USB devices.
Yes, that was the main problem and I hoped to discuss it with the
bluetooth stack developers... The solution, as I was seeing it, is to
make the bluetooth stack implement a "bluetooth bus": this would allow
to emit udev events when devices are connected/disconnected, thus using
the normal udev module autoloading stuff.
However, I see that the bluetooth stuff chose another path, by using a
user-space daemon. I'm very far from bluetooth developement to
understand why this choice was made, however I'm pretty sure there were
serious arguments in favour of that.
> And it's a patch to input plugin for bluetoothd, not hidd. hidd is the
> BlueZ 3.x daemon, we've been at BlueZ 4.x for a while.
Aha, it's the stuff for low-level tablet protocol initialization. Why
separating it from the driver itself? It's kind of tricky having
hardware initialization in a user-space daemon, and working with
hardware in the driver itself. Isn't there an analogue of the
hidp_send_ctrl_message() call for the new hid driver architecture?
--
Andrew
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] Wacom Graphire Bluetooth driver
@ 2009-03-31 22:35 ` Bastien Nocera
0 siblings, 0 replies; 20+ messages in thread
From: Bastien Nocera @ 2009-03-31 22:35 UTC (permalink / raw)
To: linux-input; +Cc: mjg, Peter Hutterer, zap, BlueZ development
On Mon, 2009-03-16 at 23:55 +0000, Bastien Nocera wrote:
> >From 3495e3be72d1df6132d5f5d978d2def3e4d57fc3 Mon Sep 17 00:00:00 2001
> From: Bastien Nocera <hadess@hadess.net>
> Date: Mon, 16 Mar 2009 23:36:54 +0000
> Subject: [PATCH] Wacom Graphire Bluetooth driver
Any news on the patch? Matthew kindly added it to the Fedora 11 kernel:
http://cvs.fedoraproject.org/viewvc/rpms/kernel/F-11/linux-2.6-input-wacom-bluetooth.patch?view=log
Cheers
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] Wacom Graphire Bluetooth driver (updated with a few fixes)
2009-03-16 23:55 ` Bastien Nocera
` (2 preceding siblings ...)
(?)
@ 2009-05-06 15:14 ` Bastien Nocera
2009-05-11 15:20 ` Jiri Kosina
-1 siblings, 1 reply; 20+ messages in thread
From: Bastien Nocera @ 2009-05-06 15:14 UTC (permalink / raw)
To: linux-input; +Cc: Jiri Kosina
>From 99074a7cf9622837af84d330e07bdb46307c254f Mon Sep 17 00:00:00 2001
From: Bastien Nocera <hadess@hadess.net>
Date: Mon, 16 Mar 2009 23:36:54 +0000
Subject: [PATCH] Wacom Graphire Bluetooth driver
Signed-off-by: Bastien Nocera <hadess@hadess.net>
Based on the work by Andrew Zabolotny, an HID driver for the Bluetooth
Wacom tablet. This is required as it uses a slightly different
protocols from what's currently support by the drivers/input/wacom*
driver, and those only support USB.
A user-space patch is required to activate mode 2 of the Wacom tablet,
as hidp does not support hid_output_raw_report.
---
drivers/hid/Kconfig | 7 ++
drivers/hid/Makefile | 1 +
drivers/hid/hid-core.c | 1 +
drivers/hid/hid-ids.h | 1 +
drivers/hid/hid-wacom.c | 260 +++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 270 insertions(+), 0 deletions(-)
create mode 100644 drivers/hid/hid-wacom.c
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index e85c8fe..f3244e3 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -261,6 +261,13 @@ config THRUSTMASTER_FF
Say Y here if you have a THRUSTMASTER FireStore Dual Power 2 or
a THRUSTMASTER Ferrari GT Rumble Force or Force Feedback Wheel.
+config HID_WACOM
+ tristate "Wacom Bluetooth devices support" if EMBEDDED
+ depends on BT_HIDP
+ default !EMBEDDED
+ ---help---
+ Support for Wacom Graphire Bluetooth tablet.
+
config ZEROPLUS_FF
tristate "Zeroplus based game controller support"
depends on USB_HID
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index fbd021f..410b302 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -41,6 +41,7 @@ obj-$(CONFIG_GREENASIA_FF) += hid-gaff.o
obj-$(CONFIG_THRUSTMASTER_FF) += hid-tmff.o
obj-$(CONFIG_HID_TOPSEED) += hid-topseed.o
obj-$(CONFIG_ZEROPLUS_FF) += hid-zpff.o
+obj-$(CONFIG_HID_WACOM) += hid-wacom.o
obj-$(CONFIG_USB_HID) += usbhid/
obj-$(CONFIG_USB_MOUSE) += usbhid/
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 1cc9674..d134f5d 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1305,6 +1305,7 @@ static const struct hid_device_id hid_blacklist[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb651) },
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb654) },
{ HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED, USB_DEVICE_ID_TOPSEED_CYBERLINK) },
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) },
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 8851197..e8f96c2 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -400,6 +400,7 @@
#define USB_DEVICE_ID_VERNIER_LCSPEC 0x0006
#define USB_VENDOR_ID_WACOM 0x056a
+#define USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH 0x81
#define USB_VENDOR_ID_WISEGROUP 0x0925
#define USB_DEVICE_ID_1_PHIDGETSERVO_20 0x8101
diff --git a/drivers/hid/hid-wacom.c b/drivers/hid/hid-wacom.c
new file mode 100644
index 0000000..67c8c3a
--- /dev/null
+++ b/drivers/hid/hid-wacom.c
@@ -0,0 +1,260 @@
+/*
+ * Bluetooth Wacom Tablet support
+ *
+ * Copyright (c) 1999 Andreas Gal
+ * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ * Copyright (c) 2006-2007 Jiri Kosina
+ * Copyright (c) 2007 Paul Walmsley
+ * Copyright (c) 2008 Jiri Slaby <jirislaby@gmail.com>
+ * Copyright (c) 2006 Andrew Zabolotny <zap@homelink.ru>
+ * Copyright (c) 2009 Bastien Nocera <hadess@hadess.net>
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+struct wacom_data {
+ __u16 tool;
+ unsigned char butstate;
+};
+
+static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report,
+ u8 *raw_data, int size)
+{
+ struct wacom_data *wdata = hid_get_drvdata(hdev);
+ struct hid_input *hidinput;
+ struct input_dev *input;
+ unsigned char *data = (unsigned char *) raw_data;
+ int tool, x, y, rw;
+
+ if (!(hdev->claimed & HID_CLAIMED_INPUT))
+ return 0;
+
+ tool = 0;
+ hidinput = list_entry(hdev->inputs.next, struct hid_input, list);
+ input = hidinput->input;
+
+ /* Check if this is a tablet report */
+ if (data[0] != 0x03)
+ return 0;
+
+ /* Get X & Y positions */
+ x = le16_to_cpu(*(__le16 *) &data[2]);
+ y = le16_to_cpu(*(__le16 *) &data[4]);
+
+ /* Get current tool identifier */
+ if (data[1] & 0x90) { /* If pen is in the in/active area */
+ switch ((data[1] >> 5) & 3) {
+ case 0: /* Pen */
+ tool = BTN_TOOL_PEN;
+ break;
+
+ case 1: /* Rubber */
+ tool = BTN_TOOL_RUBBER;
+ break;
+
+ case 2: /* Mouse with wheel */
+ case 3: /* Mouse without wheel */
+ tool = BTN_TOOL_MOUSE;
+ break;
+ }
+
+ /* Reset tool if out of active tablet area */
+ if (!(data[1] & 0x10))
+ tool = 0;
+ }
+
+ /* If tool changed, notify input subsystem */
+ if (wdata->tool != tool) {
+ if (wdata->tool) {
+ /* Completely reset old tool state */
+ if (wdata->tool == BTN_TOOL_MOUSE) {
+ input_report_key(input, BTN_LEFT, 0);
+ input_report_key(input, BTN_RIGHT, 0);
+ input_report_key(input, BTN_MIDDLE, 0);
+ input_report_abs(input, ABS_DISTANCE,
+ input->absmax[ABS_DISTANCE]);
+ } else {
+ input_report_key(input, BTN_TOUCH, 0);
+ input_report_key(input, BTN_STYLUS, 0);
+ input_report_key(input, BTN_STYLUS2, 0);
+ input_report_abs(input, ABS_PRESSURE, 0);
+ }
+ input_report_key(input, wdata->tool, 0);
+ input_sync(input);
+ }
+ wdata->tool = tool;
+ if (tool)
+ input_report_key(input, tool, 1);
+ }
+
+ if (tool) {
+ input_report_abs(input, ABS_X, x);
+ input_report_abs(input, ABS_Y, y);
+
+ switch ((data[1] >> 5) & 3) {
+ case 2: /* Mouse with wheel */
+ input_report_key(input, BTN_MIDDLE, data[1] & 0x04);
+ rw = (data[6] & 0x01) ? -1 :
+ (data[6] & 0x02) ? 1 : 0;
+ input_report_rel(input, REL_WHEEL, rw);
+ /* fall through */
+
+ case 3: /* Mouse without wheel */
+ input_report_key(input, BTN_LEFT, data[1] & 0x01);
+ input_report_key(input, BTN_RIGHT, data[1] & 0x02);
+ /* Compute distance between mouse and tablet */
+ rw = 44 - (data[6] >> 2);
+ if (rw < 0)
+ rw = 0;
+ else if (rw > 31)
+ rw = 31;
+ input_report_abs(input, ABS_DISTANCE, rw);
+ break;
+
+ default:
+ input_report_abs(input, ABS_PRESSURE,
+ data[6] | (((__u16) (data[1] & 0x08)) << 5));
+ input_report_key(input, BTN_TOUCH, data[1] & 0x01);
+ input_report_key(input, BTN_STYLUS, data[1] & 0x02);
+ input_report_key(input, BTN_STYLUS2, (tool == BTN_TOOL_PEN) && data[1] & 0x04);
+ break;
+ }
+
+ input_sync(input);
+ }
+
+ /* Report the state of the two buttons at the top of the tablet
+ * as two extra fingerpad keys (buttons 4 & 5). */
+ rw = data[7] & 0x03;
+ if (rw != wdata->butstate) {
+ wdata->butstate = rw;
+ input_report_key(input, BTN_0, rw & 0x02);
+ input_report_key(input, BTN_1, rw & 0x01);
+ input_event(input, EV_MSC, MSC_SERIAL, 0xf0);
+ input_sync(input);
+ }
+
+ return 1;
+}
+
+static int wacom_probe(struct hid_device *hdev,
+ const struct hid_device_id *id)
+{
+ struct hid_input *hidinput;
+ struct input_dev *input;
+ struct wacom_data *wdata;
+ int ret;
+
+ wdata = kzalloc(sizeof(*wdata), GFP_KERNEL);
+ if (wdata == NULL) {
+ dev_err(&hdev->dev, "can't alloc wacom descriptor\n");
+ return -ENOMEM;
+ }
+
+ hid_set_drvdata(hdev, wdata);
+
+ ret = hid_parse(hdev);
+ if (ret) {
+ dev_err(&hdev->dev, "parse failed\n");
+ goto err_free;
+ }
+
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+ if (ret) {
+ dev_err(&hdev->dev, "hw start failed\n");
+ goto err_free;
+ }
+
+ hidinput = list_entry(hdev->inputs.next, struct hid_input, list);
+ input = hidinput->input;
+
+ /* Basics */
+ input->evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_REL);
+ input->absbit[0] |= BIT(ABS_X) | BIT(ABS_Y) |
+ BIT(ABS_PRESSURE) | BIT(ABS_DISTANCE);
+ input->relbit[0] |= BIT(REL_WHEEL);
+ set_bit(BTN_TOOL_PEN, input->keybit);
+ set_bit(BTN_TOUCH, input->keybit);
+ set_bit(BTN_STYLUS, input->keybit);
+ set_bit(BTN_STYLUS2, input->keybit);
+ set_bit(BTN_LEFT, input->keybit);
+ set_bit(BTN_RIGHT, input->keybit);
+ set_bit(BTN_MIDDLE, input->keybit);
+
+ /* Pad */
+ input->evbit[0] |= BIT(EV_MSC);
+ input->mscbit[0] |= BIT(MSC_SERIAL);
+
+ /* Distance, rubber and mouse */
+ input->absbit[0] |= BIT(ABS_DISTANCE);
+ set_bit(BTN_TOOL_RUBBER, input->keybit);
+ set_bit(BTN_TOOL_MOUSE, input->keybit);
+
+ input->absmax[ABS_PRESSURE] = 511;
+ input->absmax[ABS_DISTANCE] = 32;
+
+ input->absmax[ABS_X] = 16704;
+ input->absmax[ABS_Y] = 12064;
+ input->absfuzz[ABS_X] = 4;
+ input->absfuzz[ABS_Y] = 4;
+
+ return 0;
+err_free:
+ kfree(wdata);
+ return ret;
+}
+
+static void wacom_remove(struct hid_device *hdev)
+{
+ hid_hw_stop(hdev);
+ kfree(hid_get_drvdata(hdev));
+}
+
+static const struct hid_device_id wacom_devices[] = {
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) },
+
+ { }
+};
+MODULE_DEVICE_TABLE(hid, wacom_devices);
+
+static struct hid_driver wacom_driver = {
+ .name = "wacom",
+ .id_table = wacom_devices,
+ .probe = wacom_probe,
+ .remove = wacom_remove,
+ .raw_event = wacom_raw_event,
+};
+
+static int wacom_init(void)
+{
+ int ret;
+
+ ret = hid_register_driver(&wacom_driver);
+ if (ret)
+ printk(KERN_ERR "can't register wacom driver\n");
+ printk(KERN_ERR "wacom driver registered\n");
+ return ret;
+}
+
+static void wacom_exit(void)
+{
+ hid_unregister_driver(&wacom_driver);
+}
+
+module_init(wacom_init);
+module_exit(wacom_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(wacom);
--
1.6.2
^ permalink raw reply related [flat|nested] 20+ messages in thread* Re: [PATCH] Wacom Graphire Bluetooth driver (updated with a few fixes)
2009-05-06 15:14 ` [PATCH] Wacom Graphire Bluetooth driver (updated with a few fixes) Bastien Nocera
@ 2009-05-11 15:20 ` Jiri Kosina
2009-05-11 16:12 ` Bastien Nocera
0 siblings, 1 reply; 20+ messages in thread
From: Jiri Kosina @ 2009-05-11 15:20 UTC (permalink / raw)
To: Bastien Nocera; +Cc: linux-input
On Wed, 6 May 2009, Bastien Nocera wrote:
> Signed-off-by: Bastien Nocera <hadess@hadess.net>
>
> Based on the work by Andrew Zabolotny, an HID driver for the Bluetooth
> Wacom tablet. This is required as it uses a slightly different
> protocols from what's currently support by the drivers/input/wacom*
> driver, and those only support USB.
Hi Bastien,
thanks for the driver.
> +HID_COMPAT_LOAD_DRIVER(wacom);
We don't need this one anymore, the HID_COMPAT stuff has gone away
completely already.
Otherwise, it looks good. So if you agree, I will remove the COMPAT stuff
and queue it in my tree.
Thanks,
--
Jiri Kosina
SUSE Labs
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] Wacom Graphire Bluetooth driver (updated with a few fixes)
2009-05-11 15:20 ` Jiri Kosina
@ 2009-05-11 16:12 ` Bastien Nocera
0 siblings, 0 replies; 20+ messages in thread
From: Bastien Nocera @ 2009-05-11 16:12 UTC (permalink / raw)
To: Jiri Kosina; +Cc: linux-input
On Mon, 2009-05-11 at 17:20 +0200, Jiri Kosina wrote:
> On Wed, 6 May 2009, Bastien Nocera wrote:
>
> > Signed-off-by: Bastien Nocera <hadess@hadess.net>
> >
> > Based on the work by Andrew Zabolotny, an HID driver for the Bluetooth
> > Wacom tablet. This is required as it uses a slightly different
> > protocols from what's currently support by the drivers/input/wacom*
> > driver, and those only support USB.
>
> Hi Bastien,
>
> thanks for the driver.
>
> > +HID_COMPAT_LOAD_DRIVER(wacom);
>
> We don't need this one anymore, the HID_COMPAT stuff has gone away
> completely already.
>
> Otherwise, it looks good. So if you agree, I will remove the COMPAT stuff
> and queue it in my tree.
Fine by me. Thanks!
^ permalink raw reply [flat|nested] 20+ messages in thread