Dnia 2011-10-24, pon o godzinie 10:52 -0700, Ping Cheng pisze: > On Sun, Oct 23, 2011 at 5:17 AM, Przemo Firszt <prz...@firszt.eu> wrote: > > > > Next part of the I4 WL driver attached - this time pen button reporting. > > This is part of I4 WL support. We should merge it into the other patch.
Ping, Can you cofirm that your "Acked-by" stil holds (merged version)? I want to submit this to linux-input. -- Regards, Przemo Firszt
>From d1e3b48074ac2d06a6e00f93e9056b8ec0d8d534 Mon Sep 17 00:00:00 2001 From: Przemo Firszt <prz...@firszt.eu> Date: Mon, 24 Oct 2011 21:57:15 +0100 Subject: [PATCH] Initial driver for Wacom Intuos4 Wireless (Bluetooth) This is very basic driver for Wacom Intuos4 Wireless tablet. It supports only position, pressure and pen buttons. More features will be added in future. Signed-off-by: Przemo Firszt <prz...@firszt.eu> Acked-by: Ping Cheng <pingli...@gmail.com> --- drivers/hid/hid-core.c | 1 + drivers/hid/hid-ids.h | 1 + drivers/hid/hid-wacom.c | 398 ++++++++++++++++++++++++++++++----------------- 3 files changed, 259 insertions(+), 141 deletions(-) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 91adcc5..ede9711 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1540,6 +1540,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SUPER_DUAL_BOX_PRO) }, { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SUPER_JOY_BOX_5_PRO) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH) }, { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SLIM_TABLET_5_8_INCH) }, { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SLIM_TABLET_12_1_INCH) }, { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 1680e99..1726d67 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -675,6 +675,7 @@ #define USB_VENDOR_ID_WACOM 0x056a #define USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH 0x81 +#define USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH 0x00BD #define USB_VENDOR_ID_WALTOP 0x172f #define USB_DEVICE_ID_WALTOP_SLIM_TABLET_5_8_INCH 0x0032 diff --git a/drivers/hid/hid-wacom.c b/drivers/hid/hid-wacom.c index 17bb88f..2955eed 100644 --- a/drivers/hid/hid-wacom.c +++ b/drivers/hid/hid-wacom.c @@ -9,6 +9,7 @@ * Copyright (c) 2008 Jiri Slaby <jirisl...@gmail.com> * Copyright (c) 2006 Andrew Zabolotny <z...@homelink.ru> * Copyright (c) 2009 Bastien Nocera <had...@hadess.net> + * Copyright (c) 2011 Przemysław Firszt <prz...@firszt.eu> */ /* @@ -32,6 +33,7 @@ struct wacom_data { __u16 tool; + __u8 features; unsigned char butstate; unsigned char high_speed; #ifdef CONFIG_HID_WACOM_POWER_SUPPLY @@ -107,6 +109,19 @@ static int wacom_ac_get_property(struct power_supply *psy, } #endif +static void wacom_set_features(struct hid_device *hdev) +{ + int ret; + __u8 rep_data[2]; + + /*set high speed, tablet mode*/ + rep_data[0] = 0x03; + rep_data[1] = 0x20; + ret = hdev->hid_output_raw_report(hdev, rep_data, 2, + HID_FEATURE_REPORT); + return; +} + static void wacom_poke(struct hid_device *hdev, u8 speed) { struct wacom_data *wdata = hid_get_drvdata(hdev); @@ -177,6 +192,79 @@ static ssize_t wacom_store_speed(struct device *dev, static DEVICE_ATTR(speed, S_IRUGO | S_IWUSR | S_IWGRP, wacom_show_speed, wacom_store_speed); +static void wacom_i4_parse_pen_report(struct wacom_data *wdata, + struct input_dev *input, unsigned char *data) +{ + __u16 x, y, pressure; + __u32 id; + + switch (data[1]) { + case 0x80: /* Out of proximity report */ + wdata->tool = 0; + input_report_key(input, BTN_TOUCH, 0); + input_report_abs(input, ABS_PRESSURE, 0); + input_report_key(input, wdata->tool, 0); + input_sync(input); + break; + case 0xC2: /* Tool report */ + id = ((data[2] << 4) | (data[3] >> 4) | + ((data[7] & 0x0f) << 20) | + ((data[8] & 0xf0) << 12)) & 0xfffff; + + switch (id) { + case 0x802: + wdata->tool = BTN_TOOL_PEN; + break; + case 0x80A: + wdata->tool = BTN_TOOL_RUBBER; + break; + } + break; + default: /* Position/pressure report */ + x = data[2] << 9 | data[3] << 1 | ((data[9] & 0x02) >> 1); + y = data[4] << 9 | data[5] << 1 | (data[9] & 0x01); + pressure = (data[6] << 3) | ((data[7] & 0xC0) >> 5) + | (data[1] & 0x01); + + if (pressure > 1) + input_report_key(input, BTN_TOUCH, 1); + else + input_report_key(input, BTN_TOUCH, 0); + + input_report_key(input, BTN_STYLUS, data[1] & 0x02); + input_report_key(input, BTN_STYLUS2, data[1] & 0x04); + input_report_key(input, wdata->tool, 1); + input_report_abs(input, ABS_X, x); + input_report_abs(input, ABS_Y, y); + input_report_abs(input, ABS_PRESSURE, pressure); + input_sync(input); + break; + } + + return; +} + +static void wacom_i4_parse_report(struct hid_device *hdev, + struct wacom_data *wdata, + struct input_dev *input, unsigned char *data) +{ + switch (data[0]) { + case 0x00: /* Empty report */ + break; + case 0x02: /* Pen report */ + wacom_i4_parse_pen_report(wdata, input, data); + break; + case 0x03: /* Features Report */ + wdata->features = data[2]; + break; + case 0x0C: /* Button report */ + break; + default: + hid_err(hdev, "Unknown report: %d,%d\n", data[0], data[1]); + break; + } +} + static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report, u8 *raw_data, int size) { @@ -184,171 +272,155 @@ static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report, struct hid_input *hidinput; struct input_dev *input; unsigned char *data = (unsigned char *) raw_data; - int tool, x, y, rw; + int i, 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; + switch (hdev->product) { + case USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH: + tool = 0; + /* 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; + } - 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; } - /* 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, + /* 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_abs_get_max(input, 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); + } 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); } - input_report_key(input, wdata->tool, 0); + 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); } - 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); + /* 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_LEFT, rw & 0x02); + input_report_key(input, BTN_RIGHT, rw & 0x01); + input_event(input, EV_MSC, MSC_SERIAL, 0xf0); + input_sync(input); + } - 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); +#ifdef CONFIG_HID_WACOM_POWER_SUPPLY + /* Store current battery capacity */ + rw = (data[7] >> 2 & 0x07); + if (rw != wdata->battery_capacity) + wdata->battery_capacity = rw; +#endif + break; + case USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH: + i = 1; + + switch (data[0]) { + case 0x04: + wacom_i4_parse_report(hdev, wdata, input, data + i); + i += 10; /* 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); + case 0x03: + wacom_i4_parse_report(hdev, wdata, input, data + i); + i += 10; + wacom_i4_parse_report(hdev, wdata, input, data + i); 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; + hid_err(hdev, "Unknown report: %d,%d size:%d\n", + data[0], data[1], size); + return 0; } - - 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_report_key(input, BTN_TOOL_FINGER, 0xf0); - input_event(input, EV_MSC, MSC_SERIAL, 0xf0); - input_sync(input); + break; } - -#ifdef CONFIG_HID_WACOM_POWER_SUPPLY - /* Store current battery capacity */ - rw = (data[7] >> 2 & 0x07); - if (rw != wdata->battery_capacity) - wdata->battery_capacity = rw; -#endif return 1; } -static int wacom_input_mapped(struct hid_device *hdev, struct hid_input *hi, - struct hid_field *field, struct hid_usage *usage, unsigned long **bit, - int *max) -{ - struct input_dev *input = hi->input; - - __set_bit(INPUT_PROP_POINTER, input->propbit); - - /* Basics */ - input->evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_REL); - - __set_bit(REL_WHEEL, input->relbit); - - __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); - - __set_bit(MSC_SERIAL, input->mscbit); - - __set_bit(BTN_0, input->keybit); - __set_bit(BTN_1, input->keybit); - __set_bit(BTN_TOOL_FINGER, input->keybit); - - /* Distance, rubber and mouse */ - __set_bit(BTN_TOOL_RUBBER, input->keybit); - __set_bit(BTN_TOOL_MOUSE, input->keybit); - - input_set_abs_params(input, ABS_X, 0, 16704, 4, 0); - input_set_abs_params(input, ABS_Y, 0, 12064, 4, 0); - input_set_abs_params(input, ABS_PRESSURE, 0, 511, 0, 0); - input_set_abs_params(input, ABS_DISTANCE, 0, 32, 0, 0); - - return 0; -} - 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; @@ -410,6 +482,52 @@ static int wacom_probe(struct hid_device *hdev, goto err_ac; } #endif + hidinput = list_entry(hdev->inputs.next, struct hid_input, list); + input = hidinput->input; + + __set_bit(BTN_STYLUS, input->keybit); + __set_bit(BTN_STYLUS2, input->keybit); + __set_bit(BTN_TOOL_PEN, input->keybit); + __set_bit(BTN_TOOL_RUBBER, input->keybit); + __set_bit(BTN_TOUCH, input->keybit); + __set_bit(INPUT_PROP_POINTER, input->propbit); + + input->evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_REL); + + switch (hdev->product) { + case USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH: + /* Basics */ + __set_bit(REL_WHEEL, input->relbit); + __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); + + __set_bit(MSC_SERIAL, input->mscbit); + + __set_bit(BTN_0, input->keybit); + __set_bit(BTN_1, input->keybit); + __set_bit(BTN_TOOL_FINGER, input->keybit); + + /* Distance, rubber and mouse */ + __set_bit(BTN_TOOL_MOUSE, input->keybit); + + input_set_abs_params(input, ABS_X, 0, 16704, 4, 0); + input_set_abs_params(input, ABS_Y, 0, 12064, 4, 0); + input_set_abs_params(input, ABS_PRESSURE, 0, 511, 0, 0); + input_set_abs_params(input, ABS_DISTANCE, 0, 32, 0, 0); + break; + case USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH: + wdata->features = 0; + input_set_abs_params(input, ABS_X, 0, 40640, 4, 0); + input_set_abs_params(input, ABS_Y, 0, 25400, 4, 0); + input_set_abs_params(input, ABS_PRESSURE, 0, 2047, 0, 0); + wacom_set_features(hdev); + break; + } + return 0; #ifdef CONFIG_HID_WACOM_POWER_SUPPLY @@ -441,7 +559,7 @@ static void wacom_remove(struct hid_device *hdev) static const struct hid_device_id wacom_devices[] = { { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) }, - + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH) }, { } }; MODULE_DEVICE_TABLE(hid, wacom_devices); @@ -452,7 +570,6 @@ static struct hid_driver wacom_driver = { .probe = wacom_probe, .remove = wacom_remove, .raw_event = wacom_raw_event, - .input_mapped = wacom_input_mapped, }; static int __init wacom_init(void) @@ -473,4 +590,3 @@ static void __exit wacom_exit(void) module_init(wacom_init); module_exit(wacom_exit); MODULE_LICENSE("GPL"); - -- 1.7.6
------------------------------------------------------------------------------ Get your Android app more play: Bring it to the BlackBerry PlayBook in minutes. BlackBerry App World™ now supports Android™ Apps for the BlackBerry® PlayBook™. Discover just how easy and simple it is! http://p.sf.net/sfu/android-dev2dev
_______________________________________________ Linuxwacom-devel mailing list Linuxwacom-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxwacom-devel