/*
* Version Information
*/
-#define DRIVER_VERSION "v1.30"
+#define DRIVER_VERSION "v1.40"
#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>"
#define DRIVER_DESC "USB Wacom Graphire and Wacom Intuos tablet driver"
#define DRIVER_LICENSE "GPL"
usb_sndctrlpipe(interface_to_usbdev(intf), 0),
USB_REQ_SET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
(type << 8) + id, intf->altsetting[0].desc.bInterfaceNumber,
- buf, size, HZ);
+ buf, size, 1000);
}
static void wacom_pl_irq(struct urb *urb, struct pt_regs *regs)
goto exit;
}
- if (data[0] != 2)
+ if (data[0] != 2) {
dbg("wacom_pl_irq: received unknown report #%d", data[0]);
+ goto exit;
+ }
prox = data[1] & 0x40;
if (data[0] != 2)
{
printk(KERN_INFO "wacom_ptu_irq: received unknown report #%d\n", data[0]);
+ goto exit;
}
input_regs(dev, regs);
input_report_key(dev, BTN_TOOL_PEN, data[1] & 0x20);
input_report_key(dev, BTN_TOUCH, data[1] & 0x01);
}
- input_report_abs(dev, ABS_X, data[3] << 8 | data[2]);
- input_report_abs(dev, ABS_Y, data[5] << 8 | data[4]);
- input_report_abs(dev, ABS_PRESSURE, (data[6]|data[7] << 8));
+ input_report_abs(dev, ABS_X, le16_to_cpu(*(__le16 *) &data[2]));
+ input_report_abs(dev, ABS_Y, le16_to_cpu(*(__le16 *) &data[4]));
+ input_report_abs(dev, ABS_PRESSURE, le16_to_cpu(*(__le16 *) &data[6]));
input_report_key(dev, BTN_STYLUS, data[1] & 0x02);
input_report_key(dev, BTN_STYLUS2, data[1] & 0x10);
goto exit;
}
+ if (data[0] != 2) {
+ printk(KERN_INFO "wacom_penpartner_irq: received unknown report #%d\n", data[0]);
+ goto exit;
+ }
+
input_regs(dev, regs);
input_report_key(dev, BTN_TOOL_PEN, 1);
- input_report_abs(dev, ABS_X, le16_to_cpu(get_unaligned((__le16 *) &data[1])));
- input_report_abs(dev, ABS_Y, le16_to_cpu(get_unaligned((__le16 *) &data[3])));
+ input_report_abs(dev, ABS_X, le16_to_cpu(*(__le16 *) &data[1]));
+ input_report_abs(dev, ABS_Y, le16_to_cpu(*(__le16 *) &data[3]));
input_report_abs(dev, ABS_PRESSURE, (signed char)data[6] + 127);
input_report_key(dev, BTN_TOUCH, ((signed char)data[6] > -80) && !(data[5] & 0x20));
input_report_key(dev, BTN_STYLUS, (data[5] & 0x40));
goto exit;
}
- /* check if we can handle the data */
- if (data[0] == 99)
- goto exit;
-
- if (data[0] != 2)
+ if (data[0] != 2) {
dbg("wacom_graphire_irq: received unknown report #%d", data[0]);
+ goto exit;
+ }
x = le16_to_cpu(*(__le16 *) &data[2]);
y = le16_to_cpu(*(__le16 *) &data[4]);
__FUNCTION__, retval);
}
-static void wacom_intuos_irq(struct urb *urb, struct pt_regs *regs)
+static int wacom_intuos_inout(struct urb *urb)
{
struct wacom *wacom = urb->context;
unsigned char *data = wacom->data;
struct input_dev *dev = &wacom->dev;
- unsigned int t;
int idx;
- int retval;
-
- switch (urb->status) {
- case 0:
- /* success */
- break;
- case -ECONNRESET:
- case -ENOENT:
- case -ESHUTDOWN:
- /* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
- return;
- default:
- dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
- goto exit;
- }
-
- if (data[0] != 2)
- dbg("wacom_intuos_irq: received unknown report #%d", data[0]);
-
- input_regs(dev, regs);
/* tool number */
idx = data[1] & 0x01;
- if ((data[1] & 0xfc) == 0xc0) { /* Enter report */
-
- wacom->serial[idx] = ((__u32)(data[3] & 0x0f) << 28) + /* serial number of the tool */
+ /* Enter report */
+ if ((data[1] & 0xfc) == 0xc0)
+ {
+ /* serial number of the tool */
+ wacom->serial[idx] = ((__u32)(data[3] & 0x0f) << 28) +
((__u32)data[4] << 20) + ((__u32)data[5] << 12) +
((__u32)data[6] << 4) + (data[7] >> 4);
switch (((__u32)data[2] << 4) | (data[3] >> 4)) {
- case 0x812:
- case 0x012: wacom->tool[idx] = BTN_TOOL_PENCIL; break; /* Inking pen */
- case 0x822:
+ case 0x812: /* Inking pen */
+ case 0x801: /* Intuos3 Inking pen */
+ case 0x012:
+ wacom->tool[idx] = BTN_TOOL_PENCIL;
+ break;
+ case 0x822: /* Pen */
case 0x842:
case 0x852:
- case 0x022: wacom->tool[idx] = BTN_TOOL_PEN; break; /* Pen */
- case 0x832:
- case 0x032: wacom->tool[idx] = BTN_TOOL_BRUSH; break; /* Stroke pen */
- case 0x007:
+ case 0x823: /* Intuos3 Grip Pen */
+ case 0x813: /* Intuos3 Classic Pen */
+ case 0x885: /* Intuos3 Marker Pen */
+ case 0x022:
+ wacom->tool[idx] = BTN_TOOL_PEN;
+ break;
+ case 0x832: /* Stroke pen */
+ case 0x032:
+ wacom->tool[idx] = BTN_TOOL_BRUSH;
+ break;
+ case 0x007: /* Mouse 4D and 2D */
case 0x09c:
- case 0x094: wacom->tool[idx] = BTN_TOOL_MOUSE; break; /* Mouse 4D and 2D */
- case 0x096: wacom->tool[idx] = BTN_TOOL_LENS; break; /* Lens cursor */
- case 0x82a:
+ case 0x094:
+ case 0x017: /* Intuos3 2D Mouse */
+ wacom->tool[idx] = BTN_TOOL_MOUSE;
+ break;
+ case 0x096: /* Lens cursor */
+ case 0x097: /* Intuos3 Lens cursor */
+ wacom->tool[idx] = BTN_TOOL_LENS;
+ break;
+ case 0x82a: /* Eraser */
case 0x85a:
case 0x91a:
case 0xd1a:
- case 0x0fa: wacom->tool[idx] = BTN_TOOL_RUBBER; break; /* Eraser */
+ case 0x0fa:
+ case 0x82b: /* Intuos3 Grip Pen Eraser */
+ case 0x81b: /* Intuos3 Classic Pen Eraser */
+ case 0x91b: /* Intuos3 Airbrush Eraser */
+ wacom->tool[idx] = BTN_TOOL_RUBBER;
+ break;
case 0xd12:
case 0x912:
- case 0x112: wacom->tool[idx] = BTN_TOOL_AIRBRUSH; break; /* Airbrush */
- default: wacom->tool[idx] = BTN_TOOL_PEN; break; /* Unknown tool */
+ case 0x112:
+ case 0x913: /* Intuos3 Airbrush */
+ wacom->tool[idx] = BTN_TOOL_AIRBRUSH;
+ break; /* Airbrush */
+ default: /* Unknown tool */
+ wacom->tool[idx] = BTN_TOOL_PEN;
}
-
input_report_key(dev, wacom->tool[idx], 1);
input_event(dev, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
input_sync(dev);
- goto exit;
+ return 1;
}
- if ((data[1] & 0xfe) == 0x80) { /* Exit report */
+ /* Exit report */
+ if ((data[1] & 0xfe) == 0x80) {
input_report_key(dev, wacom->tool[idx], 0);
input_event(dev, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
input_sync(dev);
- goto exit;
+ return 1;
}
- input_report_abs(dev, ABS_X, be16_to_cpu(*(__be16 *) &data[2]));
- input_report_abs(dev, ABS_Y, be16_to_cpu(*(__be16 *) &data[4]));
- input_report_abs(dev, ABS_DISTANCE, data[9]);
+ return 0;
+}
- if ((data[1] & 0xb8) == 0xa0) { /* general pen packet */
- input_report_abs(dev, ABS_PRESSURE, t = ((__u32)data[6] << 2) | ((data[7] >> 6) & 3));
- input_report_abs(dev, ABS_TILT_X, ((data[7] << 1) & 0x7e) | (data[8] >> 7));
+static void wacom_intuos_general(struct urb *urb)
+{
+ struct wacom *wacom = urb->context;
+ unsigned char *data = wacom->data;
+ struct input_dev *dev = &wacom->dev;
+ unsigned int t;
+
+ /* general pen packet */
+ if ((data[1] & 0xb8) == 0xa0)
+ {
+ t = ((__u32)data[6] << 2) | ((data[7] >> 6) & 3);
+ input_report_abs(dev, ABS_PRESSURE, t);
+ input_report_abs(dev, ABS_TILT_X,
+ ((data[7] << 1) & 0x7e) | (data[8] >> 7));
input_report_abs(dev, ABS_TILT_Y, data[8] & 0x7f);
input_report_key(dev, BTN_STYLUS, data[1] & 2);
input_report_key(dev, BTN_STYLUS2, data[1] & 4);
input_report_key(dev, BTN_TOUCH, t > 10);
}
- if ((data[1] & 0xbc) == 0xb4) { /* airbrush second packet */
- input_report_abs(dev, ABS_WHEEL, ((__u32)data[6] << 2) | ((data[7] >> 6) & 3));
- input_report_abs(dev, ABS_TILT_X, ((data[7] << 1) & 0x7e) | (data[8] >> 7));
+ /* airbrush second packet */
+ if ((data[1] & 0xbc) == 0xb4)
+ {
+ input_report_abs(dev, ABS_WHEEL,
+ ((__u32)data[6] << 2) | ((data[7] >> 6) & 3));
+ input_report_abs(dev, ABS_TILT_X,
+ ((data[7] << 1) & 0x7e) | (data[8] >> 7));
input_report_abs(dev, ABS_TILT_Y, data[8] & 0x7f);
}
+ return;
+}
+
+static void wacom_intuos_irq(struct urb *urb, struct pt_regs *regs)
+{
+ struct wacom *wacom = urb->context;
+ unsigned char *data = wacom->data;
+ struct input_dev *dev = &wacom->dev;
+ unsigned int t;
+ int idx;
+ int retval;
+
+ switch (urb->status) {
+ case 0:
+ /* success */
+ break;
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ /* this urb is terminated, clean up */
+ dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
+ return;
+ default:
+ dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
+ goto exit;
+ }
+
+ if (data[0] != 2 && data[0] != 5 && data[0] != 6) {
+ dbg("wacom_intuos_irq: received unknown report #%d", data[0]);
+ goto exit;
+ }
+
+ input_regs(dev, regs);
+
+ /* tool number */
+ idx = data[1] & 0x01;
+
+ /* process in/out prox events */
+ if (wacom_intuos_inout(urb)) goto exit;
+
+ input_report_abs(dev, ABS_X, be16_to_cpu(*(__be16 *) &data[2]));
+ input_report_abs(dev, ABS_Y, be16_to_cpu(*(__be16 *) &data[4]));
+ input_report_abs(dev, ABS_DISTANCE, data[9]);
+
+ /* process general packets */
+ wacom_intuos_general(urb);
if ((data[1] & 0xbc) == 0xa8 || (data[1] & 0xbe) == 0xb0) { /* 4D mouse or Lens cursor packets */
if (data[1] & 0x02) { /* Rotation packet */
- input_report_abs(dev, ABS_RZ, (data[7] & 0x20) ?
- ((__u32)data[6] << 3) | ((data[7] >> 5) & 7):
- (-(((__u32)data[6] << 3) | ((data[7] >> 5) & 7))) - 1);
+ t = ((__u32)data[6] << 3) | ((data[7] >> 5) & 7);
+ input_report_abs(dev, ABS_RZ, (data[7] & 0x20) ? ((t - 1) / 2) : -t / 2);
} else {
input_report_key(dev, BTN_SIDE, data[8] & 0x20);
input_report_key(dev, BTN_EXTRA, data[8] & 0x10);
- input_report_abs(dev, ABS_THROTTLE, -((data[8] & 0x08) ?
- ((__u32)data[6] << 2) | ((data[7] >> 6) & 3) :
- -((__u32)data[6] << 2) | ((data[7] >> 6) & 3)));
+ t = ((__u32)data[6] << 2) | ((data[7] >> 6) & 3);
+ input_report_abs(dev, ABS_THROTTLE, (data[8] & 0x08) ? -t : t);
} else {
if (wacom->tool[idx] == BTN_TOOL_MOUSE) { /* 2D mouse packets */
__FUNCTION__, retval);
}
+static void wacom_intuos3_irq(struct urb *urb, struct pt_regs *regs)
+{
+ struct wacom *wacom = urb->context;
+ unsigned char *data = wacom->data;
+ struct input_dev *dev = &wacom->dev;
+ unsigned int t;
+ int idx, retval;
+
+ switch (urb->status) {
+ case 0:
+ /* success */
+ break;
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ /* this urb is terminated, clean up */
+ dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
+ return;
+ default:
+ dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
+ goto exit;
+ }
+
+ /* check for valid report */
+ if (data[0] != 2 && data[0] != 5 && data[0] != 12)
+ {
+ printk(KERN_INFO "wacom_intuos3_irq: received unknown report #%d\n", data[0]);
+ goto exit;
+ }
+
+ input_regs(dev, regs);
+
+ /* tool index is always 0 here since there is no dual input tool */
+ idx = data[1] & 0x01;
+
+ /* pad packets. Works as a second tool and is always in prox */
+ if (data[0] == 12)
+ {
+ /* initiate the pad as a device */
+ if (wacom->tool[1] != BTN_TOOL_FINGER)
+ {
+ wacom->tool[1] = BTN_TOOL_FINGER;
+ input_report_key(dev, wacom->tool[1], 1);
+ }
+ input_report_key(dev, BTN_0, (data[5] & 0x01));
+ input_report_key(dev, BTN_1, (data[5] & 0x02));
+ input_report_key(dev, BTN_2, (data[5] & 0x04));
+ input_report_key(dev, BTN_3, (data[5] & 0x08));
+ input_report_key(dev, BTN_4, (data[6] & 0x01));
+ input_report_key(dev, BTN_5, (data[6] & 0x02));
+ input_report_key(dev, BTN_6, (data[6] & 0x04));
+ input_report_key(dev, BTN_7, (data[6] & 0x08));
+ input_report_abs(dev, ABS_RX, ((data[1] & 0x1f) << 8) | data[2]);
+ input_report_abs(dev, ABS_RY, ((data[3] & 0x1f) << 8) | data[4]);
+ input_event(dev, EV_MSC, MSC_SERIAL, 0xffffffff);
+ input_sync(dev);
+ goto exit;
+ }
+
+ /* process in/out prox events */
+ if (wacom_intuos_inout(urb)) goto exit;
+
+ input_report_abs(dev, ABS_X, ((__u32)data[2] << 9) | ((__u32)data[3] << 1) | ((data[9] >> 1) & 1));
+ input_report_abs(dev, ABS_Y, ((__u32)data[4] << 9) | ((__u32)data[5] << 1) | (data[9] & 1));
+ input_report_abs(dev, ABS_DISTANCE, ((data[9] >> 2) & 0x3f));
+
+ /* process general packets */
+ wacom_intuos_general(urb);
+
+ if ((data[1] & 0xbc) == 0xa8 || (data[1] & 0xbe) == 0xb0)
+ {
+ /* Marker pen rotation packet. Reported as wheel due to valuator limitation */
+ if (data[1] & 0x02)
+ {
+ t = ((__u32)data[6] << 3) | ((data[7] >> 5) & 7);
+ t = (data[7] & 0x20) ? ((t > 900) ? ((t-1) / 2 - 1350) :
+ ((t-1) / 2 + 450)) : (450 - t / 2) ;
+ input_report_abs(dev, ABS_WHEEL, t);
+ }
+
+ /* 2D mouse packets */
+ if (wacom->tool[idx] == BTN_TOOL_MOUSE)
+ {
+ input_report_key(dev, BTN_LEFT, data[8] & 0x04);
+ input_report_key(dev, BTN_MIDDLE, data[8] & 0x08);
+ input_report_key(dev, BTN_RIGHT, data[8] & 0x10);
+ input_report_key(dev, BTN_SIDE, data[8] & 0x40);
+ input_report_key(dev, BTN_EXTRA, data[8] & 0x20);
+ /* mouse wheel is positive when rolled backwards */
+ input_report_rel(dev, REL_WHEEL, ((__u32)((data[8] & 0x02) >> 1)
+ - (__u32)(data[8] & 0x01)));
+ }
+ }
+
+ input_report_key(dev, wacom->tool[idx], 1);
+ input_event(dev, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
+ input_sync(dev);
+
+exit:
+ retval = usb_submit_urb (urb, GFP_ATOMIC);
+ if (retval)
+ err ("%s - usb_submit_urb failed with result %d",
+ __FUNCTION__, retval);
+}
+
static struct wacom_features wacom_features[] = {
{ "Wacom Penpartner", 7, 5040, 3780, 255, 32, 0, wacom_penpartner_irq },
{ "Wacom Graphire", 8, 10206, 7422, 511, 32, 1, wacom_graphire_irq },
{ "Wacom Intuos2 12x18", 10, 45720, 31680, 1023, 15, 2, wacom_intuos_irq },
{ "Wacom Volito", 8, 5104, 3712, 511, 32, 1, wacom_graphire_irq },
{ "Wacom Cintiq Partner",8, 20480, 15360, 511, 32, 3, wacom_ptu_irq },
+ { "Wacom Intuos3 4x5", 10, 25400, 20320, 1023, 15, 4, wacom_intuos3_irq },
+ { "Wacom Intuos3 6x8", 10, 40640, 30480, 1023, 15, 4, wacom_intuos3_irq },
+ { "Wacom Intuos3 9x12", 10, 60960, 45720, 1023, 15, 4, wacom_intuos3_irq },
{ "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 15, 2, wacom_intuos_irq },
{ }
};
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x45) },
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x60) },
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x03) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB0) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB1) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB2) },
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x47) },
{ }
};
wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE) | BIT(BTN_STYLUS2);
break;
+ case 4: /* new functions for Intuos3 */
+ wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_FINGER);
+ wacom->dev.keybit[LONG(BTN_LEFT)] |= BIT(BTN_0) | BIT(BTN_1) | BIT(BTN_2) | BIT(BTN_3) | BIT(BTN_4) | BIT(BTN_5) | BIT(BTN_6) | BIT(BTN_7);
+ wacom->dev.absbit[0] |= BIT(ABS_RX) | BIT(ABS_RY);
+ /* fall through */
+
case 2:
wacom->dev.evbit[0] |= BIT(EV_MSC) | BIT(EV_REL);
wacom->dev.mscbit[0] |= BIT(MSC_SERIAL);
break;
case 3:
- wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_STYLUS2);
+ wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_STYLUS2) | BIT(BTN_TOOL_RUBBER);
break;
}
wacom->dev.absmax[ABS_TILT_Y] = 127;
wacom->dev.absmax[ABS_WHEEL] = 1023;
+ wacom->dev.absmax[ABS_RX] = 4097;
+ wacom->dev.absmax[ABS_RY] = 4097;
wacom->dev.absmin[ABS_RZ] = -900;
wacom->dev.absmax[ABS_RZ] = 899;
wacom->dev.absmin[ABS_THROTTLE] = -1023;
input_register_device(&wacom->dev);
+ /* ask the tablet to report tablet data */
+ usb_set_report(intf, 3, 2, rep_data, 2);
+ /* repeat once (not sure why the first call often fails) */
usb_set_report(intf, 3, 2, rep_data, 2);
- usb_set_report(intf, 3, 5, rep_data, 0);
- usb_set_report(intf, 3, 6, rep_data, 0);
printk(KERN_INFO "input: %s on %s\n", wacom->features->name, path);