Input: move USB tablets under drivers/input/tablet
authorDmitry Torokhov <dtor@insightbb.com>
Mon, 7 May 2007 20:16:29 +0000 (16:16 -0400)
committerDmitry Torokhov <dtor@insightbb.com>
Tue, 8 May 2007 05:41:29 +0000 (01:41 -0400)
This will allow concentrating all input devices in one place
in {menu|x|q}config.

Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Acked-by: Greg Kroah-Hartman <gregkh@suse.de>
23 files changed:
drivers/input/Kconfig
drivers/input/Makefile
drivers/input/tablet/Kconfig [new file with mode: 0644]
drivers/input/tablet/Makefile [new file with mode: 0644]
drivers/input/tablet/acecad.c [new file with mode: 0644]
drivers/input/tablet/aiptek.c [new file with mode: 0644]
drivers/input/tablet/gtco.c [new file with mode: 0644]
drivers/input/tablet/kbtab.c [new file with mode: 0644]
drivers/input/tablet/wacom.h [new file with mode: 0644]
drivers/input/tablet/wacom_sys.c [new file with mode: 0644]
drivers/input/tablet/wacom_wac.c [new file with mode: 0644]
drivers/input/tablet/wacom_wac.h [new file with mode: 0644]
drivers/usb/Makefile
drivers/usb/input/Kconfig
drivers/usb/input/Makefile
drivers/usb/input/acecad.c [deleted file]
drivers/usb/input/aiptek.c [deleted file]
drivers/usb/input/gtco.c [deleted file]
drivers/usb/input/kbtab.c [deleted file]
drivers/usb/input/wacom.h [deleted file]
drivers/usb/input/wacom_sys.c [deleted file]
drivers/usb/input/wacom_wac.c [deleted file]
drivers/usb/input/wacom_wac.h [deleted file]

index 96232313b1b97fc277aeb4c67ebff59d205eb6aa..0e9b69535ad6990a0766b346412b352562860375 100644 (file)
@@ -153,6 +153,8 @@ source "drivers/input/mouse/Kconfig"
 
 source "drivers/input/joystick/Kconfig"
 
+source "drivers/input/tablet/Kconfig"
+
 source "drivers/input/touchscreen/Kconfig"
 
 source "drivers/input/misc/Kconfig"
index b4cd10653c4f4996e7dde138db36f1171070d504..8a2dd987546c3c86a4587d9e6de9cb6862a7e3d4 100644 (file)
@@ -18,6 +18,7 @@ obj-$(CONFIG_INPUT_EVBUG)     += evbug.o
 obj-$(CONFIG_INPUT_KEYBOARD)   += keyboard/
 obj-$(CONFIG_INPUT_MOUSE)      += mouse/
 obj-$(CONFIG_INPUT_JOYSTICK)   += joystick/
+obj-$(CONFIG_INPUT_TABLET)     += tablet/
 obj-$(CONFIG_INPUT_TOUCHSCREEN)        += touchscreen/
 obj-$(CONFIG_INPUT_MISC)       += misc/
 
diff --git a/drivers/input/tablet/Kconfig b/drivers/input/tablet/Kconfig
new file mode 100644 (file)
index 0000000..12dfb0e
--- /dev/null
@@ -0,0 +1,74 @@
+#
+# Tablet driver configuration
+#
+menuconfig INPUT_TABLET
+       bool "Tablets"
+       help
+         Say Y here, and a list of supported tablets will be displayed.
+         This option doesn't affect the kernel.
+
+         If unsure, say Y.
+
+if INPUT_TABLET
+
+config TABLET_USB_ACECAD
+       tristate "Acecad Flair tablet support (USB)"
+       select USB
+       help
+         Say Y here if you want to use the USB version of the Acecad Flair
+         tablet.  Make sure to say Y to "Mouse support"
+         (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support"
+         (CONFIG_INPUT_EVDEV) as well.
+
+         To compile this driver as a module, choose M here: the
+         module will be called acecad.
+
+config TABLET_USB_AIPTEK
+       tristate "Aiptek 6000U/8000U tablet support (USB)"
+       select USB
+       help
+         Say Y here if you want to use the USB version of the Aiptek 6000U
+         or Aiptek 8000U tablet.  Make sure to say Y to "Mouse support"
+         (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support"
+         (CONFIG_INPUT_EVDEV) as well.
+
+         To compile this driver as a module, choose M here: the
+         module will be called aiptek.
+
+config TABLET_USB_GTCO
+        tristate "GTCO CalComp/InterWrite USB Support"
+        depends on USB && INPUT
+        help
+          Say Y here if you want to use the USB version of the GTCO
+          CalComp/InterWrite Tablet.  Make sure to say Y to "Mouse support"
+          (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support"
+          (CONFIG_INPUT_EVDEV) as well.
+
+          To compile this driver as a module, choose M here: the
+          module will be called gtco.
+
+config TABLET_USB_KBTAB
+       tristate "KB Gear JamStudio tablet support (USB)"
+       select USB
+       help
+         Say Y here if you want to use the USB version of the KB Gear
+         JamStudio tablet.  Make sure to say Y to "Mouse support"
+         (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support"
+         (CONFIG_INPUT_EVDEV) as well.
+
+         To compile this driver as a module, choose M here: the
+         module will be called kbtab.
+
+config TABLET_USB_WACOM
+       tristate "Wacom Intuos/Graphire tablet support (USB)"
+       select USB
+       help
+         Say Y here if you want to use the USB version of the Wacom Intuos
+         or Graphire tablet.  Make sure to say Y to "Mouse support"
+         (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support"
+         (CONFIG_INPUT_EVDEV) as well.
+
+         To compile this driver as a module, choose M here: the
+         module will be called wacom.
+
+endif
diff --git a/drivers/input/tablet/Makefile b/drivers/input/tablet/Makefile
new file mode 100644 (file)
index 0000000..ce8b9a9
--- /dev/null
@@ -0,0 +1,12 @@
+#
+# Makefile for the tablet drivers
+#
+
+# Multipart objects.
+wacom-objs     := wacom_wac.o wacom_sys.o
+
+obj-$(CONFIG_TABLET_USB_ACECAD)        += acecad.o
+obj-$(CONFIG_TABLET_USB_AIPTEK)        += aiptek.o
+obj-$(CONFIG_TABLET_USB_GTCO)  += gtco.o
+obj-$(CONFIG_TABLET_USB_KBTAB) += kbtab.o
+obj-$(CONFIG_TABLET_USB_WACOM) += wacom.o
diff --git a/drivers/input/tablet/acecad.c b/drivers/input/tablet/acecad.c
new file mode 100644 (file)
index 0000000..dd23104
--- /dev/null
@@ -0,0 +1,289 @@
+/*
+ *  Copyright (c) 2001-2005 Edouard TISSERANT   <edouard.tisserant@wanadoo.fr>
+ *  Copyright (c) 2004-2005 Stephane VOLTZ      <svoltz@numericable.fr>
+ *
+ *  USB Acecad "Acecad Flair" tablet support
+ *
+ *  Changelog:
+ *      v3.2 - Added sysfs support
+ */
+
+/*
+ * 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.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/usb/input.h>
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v3.2"
+#define DRIVER_DESC    "USB Acecad Flair tablet driver"
+#define DRIVER_LICENSE "GPL"
+#define DRIVER_AUTHOR  "Edouard TISSERANT <edouard.tisserant@wanadoo.fr>"
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE(DRIVER_LICENSE);
+
+#define USB_VENDOR_ID_ACECAD   0x0460
+#define USB_DEVICE_ID_FLAIR    0x0004
+#define USB_DEVICE_ID_302      0x0008
+
+struct usb_acecad {
+       char name[128];
+       char phys[64];
+       struct usb_device *usbdev;
+       struct input_dev *input;
+       struct urb *irq;
+
+       unsigned char *data;
+       dma_addr_t data_dma;
+};
+
+static void usb_acecad_irq(struct urb *urb)
+{
+       struct usb_acecad *acecad = urb->context;
+       unsigned char *data = acecad->data;
+       struct input_dev *dev = acecad->input;
+       int prox, status;
+
+       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 resubmit;
+       }
+
+       prox = (data[0] & 0x04) >> 2;
+       input_report_key(dev, BTN_TOOL_PEN, prox);
+
+       if (prox) {
+               int x = data[1] | (data[2] << 8);
+               int y = data[3] | (data[4] << 8);
+               /* Pressure should compute the same way for flair and 302 */
+               int pressure = data[5] | (data[6] << 8);
+               int touch = data[0] & 0x01;
+               int stylus = (data[0] & 0x10) >> 4;
+               int stylus2 = (data[0] & 0x20) >> 5;
+               input_report_abs(dev, ABS_X, x);
+               input_report_abs(dev, ABS_Y, y);
+               input_report_abs(dev, ABS_PRESSURE, pressure);
+               input_report_key(dev, BTN_TOUCH, touch);
+               input_report_key(dev, BTN_STYLUS, stylus);
+               input_report_key(dev, BTN_STYLUS2, stylus2);
+       }
+
+       /* event termination */
+       input_sync(dev);
+
+resubmit:
+       status = usb_submit_urb(urb, GFP_ATOMIC);
+       if (status)
+               err("can't resubmit intr, %s-%s/input0, status %d",
+                       acecad->usbdev->bus->bus_name, acecad->usbdev->devpath, status);
+}
+
+static int usb_acecad_open(struct input_dev *dev)
+{
+       struct usb_acecad *acecad = input_get_drvdata(dev);
+
+       acecad->irq->dev = acecad->usbdev;
+       if (usb_submit_urb(acecad->irq, GFP_KERNEL))
+               return -EIO;
+
+       return 0;
+}
+
+static void usb_acecad_close(struct input_dev *dev)
+{
+       struct usb_acecad *acecad = input_get_drvdata(dev);
+
+       usb_kill_urb(acecad->irq);
+}
+
+static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+       struct usb_device *dev = interface_to_usbdev(intf);
+       struct usb_host_interface *interface = intf->cur_altsetting;
+       struct usb_endpoint_descriptor *endpoint;
+       struct usb_acecad *acecad;
+       struct input_dev *input_dev;
+       int pipe, maxp;
+       int err = -ENOMEM;
+
+       if (interface->desc.bNumEndpoints != 1)
+               return -ENODEV;
+
+       endpoint = &interface->endpoint[0].desc;
+
+       if (!usb_endpoint_is_int_in(endpoint))
+               return -ENODEV;
+
+       pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
+       maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
+
+       acecad = kzalloc(sizeof(struct usb_acecad), GFP_KERNEL);
+       input_dev = input_allocate_device();
+       if (!acecad || !input_dev) {
+               err = -ENOMEM;
+               goto fail1;
+       }
+
+       acecad->data = usb_buffer_alloc(dev, 8, GFP_KERNEL, &acecad->data_dma);
+       if (!acecad->data) {
+               err= -ENOMEM;
+               goto fail1;
+       }
+
+       acecad->irq = usb_alloc_urb(0, GFP_KERNEL);
+       if (!acecad->irq) {
+               err = -ENOMEM;
+               goto fail2;
+       }
+
+       acecad->usbdev = dev;
+       acecad->input = input_dev;
+
+       if (dev->manufacturer)
+               strlcpy(acecad->name, dev->manufacturer, sizeof(acecad->name));
+
+       if (dev->product) {
+               if (dev->manufacturer)
+                       strlcat(acecad->name, " ", sizeof(acecad->name));
+               strlcat(acecad->name, dev->product, sizeof(acecad->name));
+       }
+
+       usb_make_path(dev, acecad->phys, sizeof(acecad->phys));
+       strlcat(acecad->phys, "/input0", sizeof(acecad->phys));
+
+       input_dev->name = acecad->name;
+       input_dev->phys = acecad->phys;
+       usb_to_input_id(dev, &input_dev->id);
+       input_dev->dev.parent = &intf->dev;
+
+       input_set_drvdata(input_dev, acecad);
+
+       input_dev->open = usb_acecad_open;
+       input_dev->close = usb_acecad_close;
+
+       input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+       input_dev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE);
+       input_dev->keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
+       input_dev->keybit[LONG(BTN_DIGI)] = BIT(BTN_TOOL_PEN) |BIT(BTN_TOUCH) | BIT(BTN_STYLUS) | BIT(BTN_STYLUS2);
+
+       switch (id->driver_info) {
+               case 0:
+                       input_dev->absmax[ABS_X] = 5000;
+                       input_dev->absmax[ABS_Y] = 3750;
+                       input_dev->absmax[ABS_PRESSURE] = 512;
+                       if (!strlen(acecad->name))
+                               snprintf(acecad->name, sizeof(acecad->name),
+                                       "USB Acecad Flair Tablet %04x:%04x",
+                                       le16_to_cpu(dev->descriptor.idVendor),
+                                       le16_to_cpu(dev->descriptor.idProduct));
+                       break;
+               case 1:
+                       input_dev->absmax[ABS_X] = 3000;
+                       input_dev->absmax[ABS_Y] = 2250;
+                       input_dev->absmax[ABS_PRESSURE] = 1024;
+                       if (!strlen(acecad->name))
+                               snprintf(acecad->name, sizeof(acecad->name),
+                                       "USB Acecad 302 Tablet %04x:%04x",
+                                       le16_to_cpu(dev->descriptor.idVendor),
+                                       le16_to_cpu(dev->descriptor.idProduct));
+                       break;
+       }
+
+       input_dev->absfuzz[ABS_X] = 4;
+       input_dev->absfuzz[ABS_Y] = 4;
+
+       usb_fill_int_urb(acecad->irq, dev, pipe,
+                       acecad->data, maxp > 8 ? 8 : maxp,
+                       usb_acecad_irq, acecad, endpoint->bInterval);
+       acecad->irq->transfer_dma = acecad->data_dma;
+       acecad->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+       err = input_register_device(acecad->input);
+       if (err)
+               goto fail2;
+
+       usb_set_intfdata(intf, acecad);
+
+       return 0;
+
+ fail2:        usb_buffer_free(dev, 8, acecad->data, acecad->data_dma);
+ fail1: input_free_device(input_dev);
+       kfree(acecad);
+       return err;
+}
+
+static void usb_acecad_disconnect(struct usb_interface *intf)
+{
+       struct usb_acecad *acecad = usb_get_intfdata(intf);
+
+       usb_set_intfdata(intf, NULL);
+       if (acecad) {
+               usb_kill_urb(acecad->irq);
+               input_unregister_device(acecad->input);
+               usb_free_urb(acecad->irq);
+               usb_buffer_free(interface_to_usbdev(intf), 10, acecad->data, acecad->data_dma);
+               kfree(acecad);
+       }
+}
+
+static struct usb_device_id usb_acecad_id_table [] = {
+       { USB_DEVICE(USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_FLAIR), .driver_info = 0 },
+       { USB_DEVICE(USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_302),   .driver_info = 1 },
+       { }
+};
+
+MODULE_DEVICE_TABLE(usb, usb_acecad_id_table);
+
+static struct usb_driver usb_acecad_driver = {
+       .name =         "usb_acecad",
+       .probe =        usb_acecad_probe,
+       .disconnect =   usb_acecad_disconnect,
+       .id_table =     usb_acecad_id_table,
+};
+
+static int __init usb_acecad_init(void)
+{
+       int result = usb_register(&usb_acecad_driver);
+       if (result == 0)
+               info(DRIVER_VERSION ":" DRIVER_DESC);
+       return result;
+}
+
+static void __exit usb_acecad_exit(void)
+{
+       usb_deregister(&usb_acecad_driver);
+}
+
+module_init(usb_acecad_init);
+module_exit(usb_acecad_exit);
diff --git a/drivers/input/tablet/aiptek.c b/drivers/input/tablet/aiptek.c
new file mode 100644 (file)
index 0000000..cc0a498
--- /dev/null
@@ -0,0 +1,2236 @@
+/*
+ *  Native support for the Aiptek HyperPen USB Tablets
+ *  (4000U/5000U/6000U/8000U/12000U)
+ *
+ *  Copyright (c) 2001      Chris Atenasio   <chris@crud.net>
+ *  Copyright (c) 2002-2004 Bryan W. Headley <bwheadley@earthlink.net>
+ *
+ *  based on wacom.c by
+ *     Vojtech Pavlik      <vojtech@suse.cz>
+ *     Andreas Bach Aaen   <abach@stofanet.dk>
+ *     Clifford Wolf       <clifford@clifford.at>
+ *     Sam Mosel           <sam.mosel@computer.org>
+ *     James E. Blair      <corvus@gnu.org>
+ *     Daniel Egger        <egger@suse.de>
+ *
+ *  Many thanks to Oliver Kuechemann for his support.
+ *
+ *  ChangeLog:
+ *      v0.1 - Initial release
+ *      v0.2 - Hack to get around fake event 28's. (Bryan W. Headley)
+ *      v0.3 - Make URB dynamic (Bryan W. Headley, Jun-8-2002)
+ *             Released to Linux 2.4.19 and 2.5.x
+ *      v0.4 - Rewrote substantial portions of the code to deal with
+ *             corrected control sequences, timing, dynamic configuration,
+ *             support of 6000U - 12000U, procfs, and macro key support
+ *             (Jan-1-2003 - Feb-5-2003, Bryan W. Headley)
+ *      v1.0 - Added support for diagnostic messages, count of messages
+ *             received from URB - Mar-8-2003, Bryan W. Headley
+ *      v1.1 - added support for tablet resolution, changed DV and proximity
+ *             some corrections - Jun-22-2003, martin schneebacher
+ *           - Added support for the sysfs interface, deprecating the
+ *             procfs interface for 2.5.x kernel. Also added support for
+ *             Wheel command. Bryan W. Headley July-15-2003.
+ *      v1.2 - Reworked jitter timer as a kernel thread.
+ *             Bryan W. Headley November-28-2003/Jan-10-2004.
+ *      v1.3 - Repaired issue of kernel thread going nuts on single-processor
+ *             machines, introduced programmableDelay as a command line
+ *             parameter. Feb 7 2004, Bryan W. Headley.
+ *      v1.4 - Re-wire jitter so it does not require a thread. Courtesy of
+ *             Rene van Paassen. Added reporting of physical pointer device
+ *             (e.g., stylus, mouse in reports 2, 3, 4, 5. We don't know
+ *             for reports 1, 6.)
+ *             what physical device reports for reports 1, 6.) Also enabled
+ *             MOUSE and LENS tool button modes. Renamed "rubber" to "eraser".
+ *             Feb 20, 2004, Bryan W. Headley.
+ *      v1.5 - Added previousJitterable, so we don't do jitter delay when the
+ *             user is holding a button down for periods of time.
+ *
+ * NOTE:
+ *      This kernel driver is augmented by the "Aiptek" XFree86 input
+ *      driver for your X server, as well as the Gaiptek GUI Front-end
+ *      "Tablet Manager".
+ *      These three products are highly interactive with one another,
+ *      so therefore it's easier to document them all as one subsystem.
+ *      Please visit the project's "home page", located at,
+ *      http://aiptektablet.sourceforge.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.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/usb/input.h>
+#include <asm/uaccess.h>
+#include <asm/unaligned.h>
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v1.5 (May-15-2004)"
+#define DRIVER_AUTHOR  "Bryan W. Headley/Chris Atenasio"
+#define DRIVER_DESC    "Aiptek HyperPen USB Tablet Driver (Linux 2.6.x)"
+
+/*
+ * Aiptek status packet:
+ *
+ * (returned as Report 1 - relative coordinates from mouse and stylus)
+ *
+ *        bit7  bit6  bit5  bit4  bit3  bit2  bit1  bit0
+ * byte0   0     0     0     0     0     0     0     1
+ * byte1   0     0     0     0     0    BS2   BS    Tip
+ * byte2  X7    X6    X5    X4    X3    X2    X1    X0
+ * byte3  Y7    Y6    Y5    Y4    Y3    Y2    Y1    Y0
+ *
+ * (returned as Report 2 - absolute coordinates from the stylus)
+ *
+ *        bit7  bit6  bit5  bit4  bit3  bit2  bit1  bit0
+ * byte0   0     0     0     0     0     0     1     0
+ * byte1  X7    X6    X5    X4    X3    X2    X1    X0
+ * byte2  X15   X14   X13   X12   X11   X10   X9    X8
+ * byte3  Y7    Y6    Y5    Y4    Y3    Y2    Y1    Y0
+ * byte4  Y15   Y14   Y13   Y12   Y11   Y10   Y9    Y8
+ * byte5   *     *     *    BS2   BS1   Tip   IR    DV
+ * byte6  P7    P6    P5    P4    P3    P2    P1    P0
+ * byte7  P15   P14   P13   P12   P11   P10   P9    P8
+ *
+ * (returned as Report 3 - absolute coordinates from the mouse)
+ *
+ *        bit7  bit6  bit5  bit4  bit3  bit2  bit1  bit0
+ * byte0   0     0     0     0     0     0     1     0
+ * byte1  X7    X6    X5    X4    X3    X2    X1    X0
+ * byte2  X15   X14   X13   X12   X11   X10   X9    X8
+ * byte3  Y7    Y6    Y5    Y4    Y3    Y2    Y1    Y0
+ * byte4  Y15   Y14   Y13   Y12   Y11   Y10   Y9    Y8
+ * byte5   *     *     *    BS2   BS1   Tip   IR    DV
+ * byte6  P7    P6    P5    P4    P3    P2    P1    P0
+ * byte7  P15   P14   P13   P12   P11   P10   P9    P8
+ *
+ * (returned as Report 4 - macrokeys from the stylus)
+ *
+ *        bit7  bit6  bit5  bit4  bit3  bit2  bit1  bit0
+ * byte0   0     0     0     0     0     1     0     0
+ * byte1   0     0     0    BS2   BS    Tip   IR    DV
+ * byte2   0     0     0     0     0     0     1     0
+ * byte3   0     0     0    K4    K3    K2    K1    K0
+ * byte4  P7    P6    P5    P4    P3    P2    P1    P0
+ * byte5  P15   P14   P13   P12   P11   P10   P9    P8
+ *
+ * (returned as Report 5 - macrokeys from the mouse)
+ *
+ *        bit7  bit6  bit5  bit4  bit3  bit2  bit1  bit0
+ * byte0   0     0     0     0     0     1     0     0
+ * byte1   0     0     0    BS2   BS    Tip   IR    DV
+ * byte2   0     0     0     0     0     0     1     0
+ * byte3   0     0     0    K4    K3    K2    K1    K0
+ * byte4  P7    P6    P5    P4    P3    P2    P1    P0
+ * byte5  P15   P14   P13   P12   P11   P10   P9    P8
+ *
+ * IR: In Range = Proximity on
+ * DV = Data Valid
+ * BS = Barrel Switch (as in, macro keys)
+ * BS2 also referred to as Tablet Pick
+ *
+ * Command Summary:
+ *
+ * Use report_type CONTROL (3)
+ * Use report_id   2
+ *
+ * Command/Data    Description     Return Bytes    Return Value
+ * 0x10/0x00       SwitchToMouse       0
+ * 0x10/0x01       SwitchToTablet      0
+ * 0x18/0x04       SetResolution       0
+ * 0x12/0xFF       AutoGainOn          0
+ * 0x17/0x00       FilterOn            0
+ * 0x01/0x00       GetXExtension       2           MaxX
+ * 0x01/0x01       GetYExtension       2           MaxY
+ * 0x02/0x00       GetModelCode        2           ModelCode = LOBYTE
+ * 0x03/0x00       GetODMCode          2           ODMCode
+ * 0x08/0x00       GetPressureLevels   2           =512
+ * 0x04/0x00       GetFirmwareVersion  2           Firmware Version
+ * 0x11/0x02       EnableMacroKeys     0
+ *
+ * To initialize the tablet:
+ *
+ * (1) Send Resolution500LPI (Command)
+ * (2) Query for Model code (Option Report)
+ * (3) Query for ODM code (Option Report)
+ * (4) Query for firmware (Option Report)
+ * (5) Query for GetXExtension (Option Report)
+ * (6) Query for GetYExtension (Option Report)
+ * (7) Query for GetPressureLevels (Option Report)
+ * (8) SwitchToTablet for Absolute coordinates, or
+ *     SwitchToMouse for Relative coordinates (Command)
+ * (9) EnableMacroKeys (Command)
+ * (10) FilterOn (Command)
+ * (11) AutoGainOn (Command)
+ *
+ * (Step 9 can be omitted, but you'll then have no function keys.)
+ */
+
+#define USB_VENDOR_ID_AIPTEK                           0x08ca
+#define USB_REQ_GET_REPORT                             0x01
+#define USB_REQ_SET_REPORT                             0x09
+
+       /* PointerMode codes
+        */
+#define AIPTEK_POINTER_ONLY_MOUSE_MODE                 0
+#define AIPTEK_POINTER_ONLY_STYLUS_MODE                        1
+#define AIPTEK_POINTER_EITHER_MODE                     2
+
+#define AIPTEK_POINTER_ALLOW_MOUSE_MODE(a)             \
+       (a == AIPTEK_POINTER_ONLY_MOUSE_MODE ||         \
+        a == AIPTEK_POINTER_EITHER_MODE)
+#define AIPTEK_POINTER_ALLOW_STYLUS_MODE(a)            \
+       (a == AIPTEK_POINTER_ONLY_STYLUS_MODE ||        \
+        a == AIPTEK_POINTER_EITHER_MODE)
+
+       /* CoordinateMode code
+        */
+#define AIPTEK_COORDINATE_RELATIVE_MODE                        0
+#define AIPTEK_COORDINATE_ABSOLUTE_MODE                        1
+
+       /* XTilt and YTilt values
+        */
+#define AIPTEK_TILT_MIN                                        (-128)
+#define AIPTEK_TILT_MAX                                        127
+#define AIPTEK_TILT_DISABLE                            (-10101)
+
+       /* Wheel values
+        */
+#define AIPTEK_WHEEL_MIN                               0
+#define AIPTEK_WHEEL_MAX                               1024
+#define AIPTEK_WHEEL_DISABLE                           (-10101)
+
+       /* ToolCode values, which BTW are 0x140 .. 0x14f
+        * We have things set up such that if TOOL_BUTTON_FIRED_BIT is
+        * not set, we'll send one instance of AIPTEK_TOOL_BUTTON_xxx.
+        *
+        * Whenever the user resets the value, TOOL_BUTTON_FIRED_BIT will
+        * get reset.
+        */
+#define TOOL_BUTTON(x)                                 ((x) & 0x14f)
+#define TOOL_BUTTON_FIRED(x)                           ((x) & 0x200)
+#define TOOL_BUTTON_FIRED_BIT                          0x200
+       /* toolMode codes
+        */
+#define AIPTEK_TOOL_BUTTON_PEN_MODE                    BTN_TOOL_PEN
+#define AIPTEK_TOOL_BUTTON_PEN_MODE                    BTN_TOOL_PEN
+#define AIPTEK_TOOL_BUTTON_PENCIL_MODE                 BTN_TOOL_PENCIL
+#define AIPTEK_TOOL_BUTTON_BRUSH_MODE                  BTN_TOOL_BRUSH
+#define AIPTEK_TOOL_BUTTON_AIRBRUSH_MODE               BTN_TOOL_AIRBRUSH
+#define AIPTEK_TOOL_BUTTON_ERASER_MODE                 BTN_TOOL_RUBBER
+#define AIPTEK_TOOL_BUTTON_MOUSE_MODE                  BTN_TOOL_MOUSE
+#define AIPTEK_TOOL_BUTTON_LENS_MODE                   BTN_TOOL_LENS
+
+       /* Diagnostic message codes
+        */
+#define AIPTEK_DIAGNOSTIC_NA                           0
+#define AIPTEK_DIAGNOSTIC_SENDING_RELATIVE_IN_ABSOLUTE 1
+#define AIPTEK_DIAGNOSTIC_SENDING_ABSOLUTE_IN_RELATIVE 2
+#define AIPTEK_DIAGNOSTIC_TOOL_DISALLOWED              3
+
+       /* Time to wait (in ms) to help mask hand jittering
+        * when pressing the stylus buttons.
+        */
+#define AIPTEK_JITTER_DELAY_DEFAULT                    50
+
+       /* Time to wait (in ms) in-between sending the tablet
+        * a command and beginning the process of reading the return
+        * sequence from the tablet.
+        */
+#define AIPTEK_PROGRAMMABLE_DELAY_25           25
+#define AIPTEK_PROGRAMMABLE_DELAY_50           50
+#define AIPTEK_PROGRAMMABLE_DELAY_100          100
+#define AIPTEK_PROGRAMMABLE_DELAY_200          200
+#define AIPTEK_PROGRAMMABLE_DELAY_300          300
+#define AIPTEK_PROGRAMMABLE_DELAY_400          400
+#define AIPTEK_PROGRAMMABLE_DELAY_DEFAULT      AIPTEK_PROGRAMMABLE_DELAY_400
+
+       /* Mouse button programming
+        */
+#define AIPTEK_MOUSE_LEFT_BUTTON               0x01
+#define AIPTEK_MOUSE_RIGHT_BUTTON              0x02
+#define AIPTEK_MOUSE_MIDDLE_BUTTON             0x04
+
+       /* Stylus button programming
+        */
+#define AIPTEK_STYLUS_LOWER_BUTTON             0x08
+#define AIPTEK_STYLUS_UPPER_BUTTON             0x10
+
+       /* Length of incoming packet from the tablet
+        */
+#define AIPTEK_PACKET_LENGTH                   8
+
+       /* We report in EV_MISC both the proximity and
+        * whether the report came from the stylus, tablet mouse
+        * or "unknown" -- Unknown when the tablet is in relative
+        * mode, because we only get report 1's.
+        */
+#define AIPTEK_REPORT_TOOL_UNKNOWN             0x10
+#define AIPTEK_REPORT_TOOL_STYLUS              0x20
+#define AIPTEK_REPORT_TOOL_MOUSE               0x40
+
+static int programmableDelay = AIPTEK_PROGRAMMABLE_DELAY_DEFAULT;
+static int jitterDelay = AIPTEK_JITTER_DELAY_DEFAULT;
+
+struct aiptek_features {
+       int odmCode;            /* Tablet manufacturer code       */
+       int modelCode;          /* Tablet model code (not unique) */
+       int firmwareCode;       /* prom/eeprom version            */
+       char usbPath[64 + 1];   /* device's physical usb path     */
+       char inputPath[64 + 1]; /* input device path              */
+};
+
+struct aiptek_settings {
+       int pointerMode;        /* stylus-, mouse-only or either */
+       int coordinateMode;     /* absolute/relative coords      */
+       int toolMode;           /* pen, pencil, brush, etc. tool */
+       int xTilt;              /* synthetic xTilt amount        */
+       int yTilt;              /* synthetic yTilt amount        */
+       int wheel;              /* synthetic wheel amount        */
+       int stylusButtonUpper;  /* stylus upper btn delivers...  */
+       int stylusButtonLower;  /* stylus lower btn delivers...  */
+       int mouseButtonLeft;    /* mouse left btn delivers...    */
+       int mouseButtonMiddle;  /* mouse middle btn delivers...  */
+       int mouseButtonRight;   /* mouse right btn delivers...   */
+       int programmableDelay;  /* delay for tablet programming  */
+       int jitterDelay;        /* delay for hand jittering      */
+};
+
+struct aiptek {
+       struct input_dev *inputdev;             /* input device struct           */
+       struct usb_device *usbdev;              /* usb device struct             */
+       struct urb *urb;                        /* urb for incoming reports      */
+       dma_addr_t data_dma;                    /* our dma stuffage              */
+       struct aiptek_features features;        /* tablet's array of features    */
+       struct aiptek_settings curSetting;      /* tablet's current programmable */
+       struct aiptek_settings newSetting;      /* ... and new param settings    */
+       unsigned int ifnum;                     /* interface number for IO       */
+       int diagnostic;                         /* tablet diagnostic codes       */
+       unsigned long eventCount;               /* event count                   */
+       int inDelay;                            /* jitter: in jitter delay?      */
+       unsigned long endDelay;                 /* jitter: time when delay ends  */
+       int previousJitterable;                 /* jitterable prev value     */
+       unsigned char *data;                    /* incoming packet data          */
+};
+
+/*
+ * Permit easy lookup of keyboard events to send, versus
+ * the bitmap which comes from the tablet. This hides the
+ * issue that the F_keys are not sequentially numbered.
+ */
+static const int macroKeyEvents[] = {
+       KEY_ESC, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5,
+       KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_F11,
+       KEY_F12, KEY_F13, KEY_F14, KEY_F15, KEY_F16, KEY_F17,
+       KEY_F18, KEY_F19, KEY_F20, KEY_F21, KEY_F22, KEY_F23,
+       KEY_F24, KEY_STOP, KEY_AGAIN, KEY_PROPS, KEY_UNDO,
+       KEY_FRONT, KEY_COPY, KEY_OPEN, KEY_PASTE, 0
+};
+
+/***********************************************************************
+ * Relative reports deliver values in 2's complement format to
+ * deal with negative offsets.
+ */
+static int aiptek_convert_from_2s_complement(unsigned char c)
+{
+       int ret;
+       unsigned char b = c;
+       int negate = 0;
+
+       if ((b & 0x80) != 0) {
+               b = ~b;
+               b--;
+               negate = 1;
+       }
+       ret = b;
+       ret = (negate == 1) ? -ret : ret;
+       return ret;
+}
+
+/***********************************************************************
+ * aiptek_irq can receive one of six potential reports.
+ * The documentation for each is in the body of the function.
+ *
+ * The tablet reports on several attributes per invocation of
+ * aiptek_irq. Because the Linux Input Event system allows the
+ * transmission of ONE attribute per input_report_xxx() call,
+ * collation has to be done on the other end to reconstitute
+ * a complete tablet report. Further, the number of Input Event reports
+ * submitted varies, depending on what USB report type, and circumstance.
+ * To deal with this, EV_MSC is used to indicate an 'end-of-report'
+ * message. This has been an undocumented convention understood by the kernel
+ * tablet driver and clients such as gpm and XFree86's tablet drivers.
+ *
+ * Of the information received from the tablet, the one piece I
+ * cannot transmit is the proximity bit (without resorting to an EV_MSC
+ * convention above.) I therefore have taken over REL_MISC and ABS_MISC
+ * (for relative and absolute reports, respectively) for communicating
+ * Proximity. Why two events? I thought it interesting to know if the
+ * Proximity event occurred while the tablet was in absolute or relative
+ * mode.
+ *
+ * Other tablets use the notion of a certain minimum stylus pressure
+ * to infer proximity. While that could have been done, that is yet
+ * another 'by convention' behavior, the documentation for which
+ * would be spread between two (or more) pieces of software.
+ *
+ * EV_MSC usage was terminated for this purpose in Linux 2.5.x, and
+ * replaced with the input_sync() method (which emits EV_SYN.)
+ */
+
+static void aiptek_irq(struct urb *urb)
+{
+       struct aiptek *aiptek = urb->context;
+       unsigned char *data = aiptek->data;
+       struct input_dev *inputdev = aiptek->inputdev;
+       int jitterable = 0;
+       int retval, macro, x, y, z, left, right, middle, p, dv, tip, bs, pck;
+
+       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;
+       }
+
+       /* See if we are in a delay loop -- throw out report if true.
+        */
+       if (aiptek->inDelay == 1 && time_after(aiptek->endDelay, jiffies)) {
+               goto exit;
+       }
+
+       aiptek->inDelay = 0;
+       aiptek->eventCount++;
+
+       /* Report 1 delivers relative coordinates with either a stylus
+        * or the mouse. You do not know, however, which input
+        * tool generated the event.
+        */
+       if (data[0] == 1) {
+               if (aiptek->curSetting.coordinateMode ==
+                   AIPTEK_COORDINATE_ABSOLUTE_MODE) {
+                       aiptek->diagnostic =
+                           AIPTEK_DIAGNOSTIC_SENDING_RELATIVE_IN_ABSOLUTE;
+               } else {
+                       x = aiptek_convert_from_2s_complement(data[2]);
+                       y = aiptek_convert_from_2s_complement(data[3]);
+
+                       /* jitterable keeps track of whether any button has been pressed.
+                        * We're also using it to remap the physical mouse button mask
+                        * to pseudo-settings. (We don't specifically care about it's
+                        * value after moving/transposing mouse button bitmasks, except
+                        * that a non-zero value indicates that one or more
+                        * mouse button was pressed.)
+                        */
+                       jitterable = data[5] & 0x07;
+
+                       left = (data[5] & aiptek->curSetting.mouseButtonLeft) != 0 ? 1 : 0;
+                       right = (data[5] & aiptek->curSetting.mouseButtonRight) != 0 ? 1 : 0;
+                       middle = (data[5] & aiptek->curSetting.mouseButtonMiddle) != 0 ? 1 : 0;
+
+                       input_report_key(inputdev, BTN_LEFT, left);
+                       input_report_key(inputdev, BTN_MIDDLE, middle);
+                       input_report_key(inputdev, BTN_RIGHT, right);
+                       input_report_rel(inputdev, REL_X, x);
+                       input_report_rel(inputdev, REL_Y, y);
+                       input_report_rel(inputdev, REL_MISC, 1 | AIPTEK_REPORT_TOOL_UNKNOWN);
+
+                       /* Wheel support is in the form of a single-event
+                        * firing.
+                        */
+                       if (aiptek->curSetting.wheel != AIPTEK_WHEEL_DISABLE) {
+                               input_report_rel(inputdev, REL_WHEEL,
+                                                aiptek->curSetting.wheel);
+                               aiptek->curSetting.wheel = AIPTEK_WHEEL_DISABLE;
+                       }
+                       input_sync(inputdev);
+               }
+       }
+       /* Report 2 is delivered only by the stylus, and delivers
+        * absolute coordinates.
+        */
+       else if (data[0] == 2) {
+               if (aiptek->curSetting.coordinateMode == AIPTEK_COORDINATE_RELATIVE_MODE) {
+                       aiptek->diagnostic = AIPTEK_DIAGNOSTIC_SENDING_ABSOLUTE_IN_RELATIVE;
+               } else if (!AIPTEK_POINTER_ALLOW_STYLUS_MODE
+                           (aiptek->curSetting.pointerMode)) {
+                               aiptek->diagnostic = AIPTEK_DIAGNOSTIC_TOOL_DISALLOWED;
+               } else {
+                       x = le16_to_cpu(get_unaligned((__le16 *) (data + 1)));
+                       y = le16_to_cpu(get_unaligned((__le16 *) (data + 3)));
+                       z = le16_to_cpu(get_unaligned((__le16 *) (data + 6)));
+
+                       p = (data[5] & 0x01) != 0 ? 1 : 0;
+                       dv = (data[5] & 0x02) != 0 ? 1 : 0;
+                       tip = (data[5] & 0x04) != 0 ? 1 : 0;
+
+                       /* Use jitterable to re-arrange button masks
+                        */
+                       jitterable = data[5] & 0x18;
+
+                       bs = (data[5] & aiptek->curSetting.stylusButtonLower) != 0 ? 1 : 0;
+                       pck = (data[5] & aiptek->curSetting.stylusButtonUpper) != 0 ? 1 : 0;
+
+                       /* dv indicates 'data valid' (e.g., the tablet is in sync
+                        * and has delivered a "correct" report) We will ignore
+                        * all 'bad' reports...
+                        */
+                       if (dv != 0) {
+                               /* If we've not already sent a tool_button_?? code, do
+                                * so now. Then set FIRED_BIT so it won't be resent unless
+                                * the user forces FIRED_BIT off.
+                                */
+                               if (TOOL_BUTTON_FIRED
+                                   (aiptek->curSetting.toolMode) == 0) {
+                                       input_report_key(inputdev,
+                                                        TOOL_BUTTON(aiptek->curSetting.toolMode),
+                                                        1);
+                                       aiptek->curSetting.toolMode |= TOOL_BUTTON_FIRED_BIT;
+                               }
+
+                               if (p != 0) {
+                                       input_report_abs(inputdev, ABS_X, x);
+                                       input_report_abs(inputdev, ABS_Y, y);
+                                       input_report_abs(inputdev, ABS_PRESSURE, z);
+
+                                       input_report_key(inputdev, BTN_TOUCH, tip);
+                                       input_report_key(inputdev, BTN_STYLUS, bs);
+                                       input_report_key(inputdev, BTN_STYLUS2, pck);
+
+                                       if (aiptek->curSetting.xTilt !=
+                                           AIPTEK_TILT_DISABLE) {
+                                               input_report_abs(inputdev,
+                                                                ABS_TILT_X,
+                                                                aiptek->curSetting.xTilt);
+                                       }
+                                       if (aiptek->curSetting.yTilt != AIPTEK_TILT_DISABLE) {
+                                               input_report_abs(inputdev,
+                                                                ABS_TILT_Y,
+                                                                aiptek->curSetting.yTilt);
+                                       }
+
+                                       /* Wheel support is in the form of a single-event
+                                        * firing.
+                                        */
+                                       if (aiptek->curSetting.wheel !=
+                                           AIPTEK_WHEEL_DISABLE) {
+                                               input_report_abs(inputdev,
+                                                                ABS_WHEEL,
+                                                                aiptek->curSetting.wheel);
+                                               aiptek->curSetting.wheel = AIPTEK_WHEEL_DISABLE;
+                                       }
+                               }
+                               input_report_abs(inputdev, ABS_MISC, p | AIPTEK_REPORT_TOOL_STYLUS);
+                               input_sync(inputdev);
+                       }
+               }
+       }
+       /* Report 3's come from the mouse in absolute mode.
+        */
+       else if (data[0] == 3) {
+               if (aiptek->curSetting.coordinateMode == AIPTEK_COORDINATE_RELATIVE_MODE) {
+                       aiptek->diagnostic = AIPTEK_DIAGNOSTIC_SENDING_ABSOLUTE_IN_RELATIVE;
+               } else if (!AIPTEK_POINTER_ALLOW_MOUSE_MODE
+                       (aiptek->curSetting.pointerMode)) {
+                       aiptek->diagnostic = AIPTEK_DIAGNOSTIC_TOOL_DISALLOWED;
+               } else {
+                       x = le16_to_cpu(get_unaligned((__le16 *) (data + 1)));
+                       y = le16_to_cpu(get_unaligned((__le16 *) (data + 3)));
+
+                       jitterable = data[5] & 0x1c;
+
+                       p = (data[5] & 0x01) != 0 ? 1 : 0;
+                       dv = (data[5] & 0x02) != 0 ? 1 : 0;
+                       left = (data[5] & aiptek->curSetting.mouseButtonLeft) != 0 ? 1 : 0;
+                       right = (data[5] & aiptek->curSetting.mouseButtonRight) != 0 ? 1 : 0;
+                       middle = (data[5] & aiptek->curSetting.mouseButtonMiddle) != 0 ? 1 : 0;
+
+                       if (dv != 0) {
+                               /* If we've not already sent a tool_button_?? code, do
+                                * so now. Then set FIRED_BIT so it won't be resent unless
+                                * the user forces FIRED_BIT off.
+                                */
+                               if (TOOL_BUTTON_FIRED
+                                   (aiptek->curSetting.toolMode) == 0) {
+                                       input_report_key(inputdev,
+                                                        TOOL_BUTTON(aiptek->curSetting.toolMode),
+                                                        1);
+                                       aiptek->curSetting.toolMode |= TOOL_BUTTON_FIRED_BIT;
+                               }
+
+                               if (p != 0) {
+                                       input_report_abs(inputdev, ABS_X, x);
+                                       input_report_abs(inputdev, ABS_Y, y);
+
+                                       input_report_key(inputdev, BTN_LEFT, left);
+                                       input_report_key(inputdev, BTN_MIDDLE, middle);
+                                       input_report_key(inputdev, BTN_RIGHT, right);
+
+                                       /* Wheel support is in the form of a single-event
+                                        * firing.
+                                        */
+                                       if (aiptek->curSetting.wheel != AIPTEK_WHEEL_DISABLE) {
+                                               input_report_abs(inputdev,
+                                                                ABS_WHEEL,
+                                                                aiptek->curSetting.wheel);
+                                               aiptek->curSetting.wheel = AIPTEK_WHEEL_DISABLE;
+                                       }
+                               }
+                               input_report_rel(inputdev, REL_MISC, p | AIPTEK_REPORT_TOOL_MOUSE);
+                               input_sync(inputdev);
+                       }
+               }
+       }
+       /* Report 4s come from the macro keys when pressed by stylus
+        */
+       else if (data[0] == 4) {
+               jitterable = data[1] & 0x18;
+
+               p = (data[1] & 0x01) != 0 ? 1 : 0;
+               dv = (data[1] & 0x02) != 0 ? 1 : 0;
+               tip = (data[1] & 0x04) != 0 ? 1 : 0;
+               bs = (data[1] & aiptek->curSetting.stylusButtonLower) != 0 ? 1 : 0;
+               pck = (data[1] & aiptek->curSetting.stylusButtonUpper) != 0 ? 1 : 0;
+
+               macro = data[3];
+               z = le16_to_cpu(get_unaligned((__le16 *) (data + 4)));
+
+               if (dv != 0) {
+                       /* If we've not already sent a tool_button_?? code, do
+                        * so now. Then set FIRED_BIT so it won't be resent unless
+                        * the user forces FIRED_BIT off.
+                        */
+                       if (TOOL_BUTTON_FIRED(aiptek->curSetting.toolMode) == 0) {
+                               input_report_key(inputdev,
+                                                TOOL_BUTTON(aiptek->curSetting.toolMode),
+                                                1);
+                               aiptek->curSetting.toolMode |= TOOL_BUTTON_FIRED_BIT;
+                       }
+
+                       if (p != 0) {
+                               input_report_key(inputdev, BTN_TOUCH, tip);
+                               input_report_key(inputdev, BTN_STYLUS, bs);
+                               input_report_key(inputdev, BTN_STYLUS2, pck);
+                               input_report_abs(inputdev, ABS_PRESSURE, z);
+                       }
+
+                       /* For safety, we're sending key 'break' codes for the
+                        * neighboring macro keys.
+                        */
+                       if (macro > 0) {
+                               input_report_key(inputdev,
+                                                macroKeyEvents[macro - 1], 0);
+                       }
+                       if (macro < 25) {
+                               input_report_key(inputdev,
+                                                macroKeyEvents[macro + 1], 0);
+                       }
+                       input_report_key(inputdev, macroKeyEvents[macro], p);
+                       input_report_abs(inputdev, ABS_MISC,
+                                        p | AIPTEK_REPORT_TOOL_STYLUS);
+                       input_sync(inputdev);
+               }
+       }
+       /* Report 5s come from the macro keys when pressed by mouse
+        */
+       else if (data[0] == 5) {
+               jitterable = data[1] & 0x1c;
+
+               p = (data[1] & 0x01) != 0 ? 1 : 0;
+               dv = (data[1] & 0x02) != 0 ? 1 : 0;
+               left = (data[1]& aiptek->curSetting.mouseButtonLeft) != 0 ? 1 : 0;
+               right = (data[1] & aiptek->curSetting.mouseButtonRight) != 0 ? 1 : 0;
+               middle = (data[1] & aiptek->curSetting.mouseButtonMiddle) != 0 ? 1 : 0;
+               macro = data[3];
+
+               if (dv != 0) {
+                       /* If we've not already sent a tool_button_?? code, do
+                        * so now. Then set FIRED_BIT so it won't be resent unless
+                        * the user forces FIRED_BIT off.
+                        */
+                       if (TOOL_BUTTON_FIRED(aiptek->curSetting.toolMode) == 0) {
+                               input_report_key(inputdev,
+                                                TOOL_BUTTON(aiptek->curSetting.toolMode),
+                                                1);
+                               aiptek->curSetting.toolMode |= TOOL_BUTTON_FIRED_BIT;
+                       }
+
+                       if (p != 0) {
+                               input_report_key(inputdev, BTN_LEFT, left);
+                               input_report_key(inputdev, BTN_MIDDLE, middle);
+                               input_report_key(inputdev, BTN_RIGHT, right);
+                       }
+
+                       /* For safety, we're sending key 'break' codes for the
+                        * neighboring macro keys.
+                        */
+                       if (macro > 0) {
+                               input_report_key(inputdev,
+                                                macroKeyEvents[macro - 1], 0);
+                       }
+                       if (macro < 25) {
+                               input_report_key(inputdev,
+                                                macroKeyEvents[macro + 1], 0);
+                       }
+
+                       input_report_key(inputdev, macroKeyEvents[macro], 1);
+                       input_report_rel(inputdev, ABS_MISC,
+                                        p | AIPTEK_REPORT_TOOL_MOUSE);
+                       input_sync(inputdev);
+               }
+       }
+       /* We have no idea which tool can generate a report 6. Theoretically,
+        * neither need to, having been given reports 4 & 5 for such use.
+        * However, report 6 is the 'official-looking' report for macroKeys;
+        * reports 4 & 5 supposively are used to support unnamed, unknown
+        * hat switches (which just so happen to be the macroKeys.)
+        */
+       else if (data[0] == 6) {
+               macro = le16_to_cpu(get_unaligned((__le16 *) (data + 1)));
+               if (macro > 0) {
+                       input_report_key(inputdev, macroKeyEvents[macro - 1],
+                                        0);
+               }
+               if (macro < 25) {
+                       input_report_key(inputdev, macroKeyEvents[macro + 1],
+                                        0);
+               }
+
+               /* If we've not already sent a tool_button_?? code, do
+                * so now. Then set FIRED_BIT so it won't be resent unless
+                * the user forces FIRED_BIT off.
+                */
+               if (TOOL_BUTTON_FIRED(aiptek->curSetting.toolMode) == 0) {
+                       input_report_key(inputdev,
+                                        TOOL_BUTTON(aiptek->curSetting.
+                                                    toolMode), 1);
+                       aiptek->curSetting.toolMode |= TOOL_BUTTON_FIRED_BIT;
+               }
+
+               input_report_key(inputdev, macroKeyEvents[macro], 1);
+               input_report_abs(inputdev, ABS_MISC,
+                                1 | AIPTEK_REPORT_TOOL_UNKNOWN);
+               input_sync(inputdev);
+       } else {
+               dbg("Unknown report %d", data[0]);
+       }
+
+       /* Jitter may occur when the user presses a button on the stlyus
+        * or the mouse. What we do to prevent that is wait 'x' milliseconds
+        * following a 'jitterable' event, which should give the hand some time
+        * stabilize itself.
+        *
+        * We just introduced aiptek->previousJitterable to carry forth the
+        * notion that jitter occurs when the button state changes from on to off:
+        * a person drawing, holding a button down is not subject to jittering.
+        * With that in mind, changing from upper button depressed to lower button
+        * WILL transition through a jitter delay.
+        */
+
+       if (aiptek->previousJitterable != jitterable &&
+           aiptek->curSetting.jitterDelay != 0 && aiptek->inDelay != 1) {
+               aiptek->endDelay = jiffies +
+                   ((aiptek->curSetting.jitterDelay * HZ) / 1000);
+               aiptek->inDelay = 1;
+       }
+       aiptek->previousJitterable = jitterable;
+
+exit:
+       retval = usb_submit_urb(urb, GFP_ATOMIC);
+       if (retval != 0) {
+               err("%s - usb_submit_urb failed with result %d",
+                   __FUNCTION__, retval);
+       }
+}
+
+/***********************************************************************
+ * These are the USB id's known so far. We do not identify them to
+ * specific Aiptek model numbers, because there has been overlaps,
+ * use, and reuse of id's in existing models. Certain models have
+ * been known to use more than one ID, indicative perhaps of
+ * manufacturing revisions. In any event, we consider these
+ * IDs to not be model-specific nor unique.
+ */
+static const struct usb_device_id aiptek_ids[] = {
+       {USB_DEVICE(USB_VENDOR_ID_AIPTEK, 0x01)},
+       {USB_DEVICE(USB_VENDOR_ID_AIPTEK, 0x10)},
+       {USB_DEVICE(USB_VENDOR_ID_AIPTEK, 0x20)},
+       {USB_DEVICE(USB_VENDOR_ID_AIPTEK, 0x21)},
+       {USB_DEVICE(USB_VENDOR_ID_AIPTEK, 0x22)},
+       {USB_DEVICE(USB_VENDOR_ID_AIPTEK, 0x23)},
+       {USB_DEVICE(USB_VENDOR_ID_AIPTEK, 0x24)},
+       {}
+};
+
+MODULE_DEVICE_TABLE(usb, aiptek_ids);
+
+/***********************************************************************
+ * Open an instance of the tablet driver.
+ */
+static int aiptek_open(struct input_dev *inputdev)
+{
+       struct aiptek *aiptek = input_get_drvdata(inputdev);
+
+       aiptek->urb->dev = aiptek->usbdev;
+       if (usb_submit_urb(aiptek->urb, GFP_KERNEL) != 0)
+               return -EIO;
+
+       return 0;
+}
+
+/***********************************************************************
+ * Close an instance of the tablet driver.
+ */
+static void aiptek_close(struct input_dev *inputdev)
+{
+       struct aiptek *aiptek = input_get_drvdata(inputdev);
+
+       usb_kill_urb(aiptek->urb);
+}
+
+/***********************************************************************
+ * aiptek_set_report and aiptek_get_report() are borrowed from Linux 2.4.x,
+ * where they were known as usb_set_report and usb_get_report.
+ */
+static int
+aiptek_set_report(struct aiptek *aiptek,
+                 unsigned char report_type,
+                 unsigned char report_id, void *buffer, int size)
+{
+       return usb_control_msg(aiptek->usbdev,
+                              usb_sndctrlpipe(aiptek->usbdev, 0),
+                              USB_REQ_SET_REPORT,
+                              USB_TYPE_CLASS | USB_RECIP_INTERFACE |
+                              USB_DIR_OUT, (report_type << 8) + report_id,
+                              aiptek->ifnum, buffer, size, 5000);
+}
+
+static int
+aiptek_get_report(struct aiptek *aiptek,
+                 unsigned char report_type,
+                 unsigned char report_id, void *buffer, int size)
+{
+       return usb_control_msg(aiptek->usbdev,
+                              usb_rcvctrlpipe(aiptek->usbdev, 0),
+                              USB_REQ_GET_REPORT,
+                              USB_TYPE_CLASS | USB_RECIP_INTERFACE |
+                              USB_DIR_IN, (report_type << 8) + report_id,
+                              aiptek->ifnum, buffer, size, 5000);
+}
+
+/***********************************************************************
+ * Send a command to the tablet.
+ */
+static int
+aiptek_command(struct aiptek *aiptek, unsigned char command, unsigned char data)
+{
+       const int sizeof_buf = 3 * sizeof(u8);
+       int ret;
+       u8 *buf;
+
+       buf = kmalloc(sizeof_buf, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       buf[0] = 2;
+       buf[1] = command;
+       buf[2] = data;
+
+       if ((ret =
+            aiptek_set_report(aiptek, 3, 2, buf, sizeof_buf)) != sizeof_buf) {
+               dbg("aiptek_program: failed, tried to send: 0x%02x 0x%02x",
+                   command, data);
+       }
+       kfree(buf);
+       return ret < 0 ? ret : 0;
+}
+
+/***********************************************************************
+ * Retrieve information from the tablet. Querying info is defined as first
+ * sending the {command,data} sequence as a command, followed by a wait
+ * (aka, "programmaticDelay") and then a "read" request.
+ */
+static int
+aiptek_query(struct aiptek *aiptek, unsigned char command, unsigned char data)
+{
+       const int sizeof_buf = 3 * sizeof(u8);
+       int ret;
+       u8 *buf;
+
+       buf = kmalloc(sizeof_buf, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       buf[0] = 2;
+       buf[1] = command;
+       buf[2] = data;
+
+       if (aiptek_command(aiptek, command, data) != 0) {
+               kfree(buf);
+               return -EIO;
+       }
+       msleep(aiptek->curSetting.programmableDelay);
+
+       if ((ret =
+            aiptek_get_report(aiptek, 3, 2, buf, sizeof_buf)) != sizeof_buf) {
+               dbg("aiptek_query failed: returned 0x%02x 0x%02x 0x%02x",
+                   buf[0], buf[1], buf[2]);
+               ret = -EIO;
+       } else {
+               ret = le16_to_cpu(get_unaligned((__le16 *) (buf + 1)));
+       }
+       kfree(buf);
+       return ret;
+}
+
+/***********************************************************************
+ * Program the tablet into either absolute or relative mode.
+ * We also get information about the tablet's size.
+ */
+static int aiptek_program_tablet(struct aiptek *aiptek)
+{
+       int ret;
+       /* Execute Resolution500LPI */
+       if ((ret = aiptek_command(aiptek, 0x18, 0x04)) < 0)
+               return ret;
+
+       /* Query getModelCode */
+       if ((ret = aiptek_query(aiptek, 0x02, 0x00)) < 0)
+               return ret;
+       aiptek->features.modelCode = ret & 0xff;
+
+       /* Query getODMCode */
+       if ((ret = aiptek_query(aiptek, 0x03, 0x00)) < 0)
+               return ret;
+       aiptek->features.odmCode = ret;
+
+       /* Query getFirmwareCode */
+       if ((ret = aiptek_query(aiptek, 0x04, 0x00)) < 0)
+               return ret;
+       aiptek->features.firmwareCode = ret;
+
+       /* Query getXextension */
+       if ((ret = aiptek_query(aiptek, 0x01, 0x00)) < 0)
+               return ret;
+       aiptek->inputdev->absmin[ABS_X] = 0;
+       aiptek->inputdev->absmax[ABS_X] = ret - 1;
+
+       /* Query getYextension */
+       if ((ret = aiptek_query(aiptek, 0x01, 0x01)) < 0)
+               return ret;
+       aiptek->inputdev->absmin[ABS_Y] = 0;
+       aiptek->inputdev->absmax[ABS_Y] = ret - 1;
+
+       /* Query getPressureLevels */
+       if ((ret = aiptek_query(aiptek, 0x08, 0x00)) < 0)
+               return ret;
+       aiptek->inputdev->absmin[ABS_PRESSURE] = 0;
+       aiptek->inputdev->absmax[ABS_PRESSURE] = ret - 1;
+
+       /* Depending on whether we are in absolute or relative mode, we will
+        * do a switchToTablet(absolute) or switchToMouse(relative) command.
+        */
+       if (aiptek->curSetting.coordinateMode ==
+           AIPTEK_COORDINATE_ABSOLUTE_MODE) {
+               /* Execute switchToTablet */
+               if ((ret = aiptek_command(aiptek, 0x10, 0x01)) < 0) {
+                       return ret;
+               }
+       } else {
+               /* Execute switchToMouse */
+               if ((ret = aiptek_command(aiptek, 0x10, 0x00)) < 0) {
+                       return ret;
+               }
+       }
+
+       /* Enable the macro keys */
+       if ((ret = aiptek_command(aiptek, 0x11, 0x02)) < 0)
+               return ret;
+#if 0
+       /* Execute FilterOn */
+       if ((ret = aiptek_command(aiptek, 0x17, 0x00)) < 0)
+               return ret;
+#endif
+
+       /* Execute AutoGainOn */
+       if ((ret = aiptek_command(aiptek, 0x12, 0xff)) < 0)
+               return ret;
+
+       /* Reset the eventCount, so we track events from last (re)programming
+        */
+       aiptek->diagnostic = AIPTEK_DIAGNOSTIC_NA;
+       aiptek->eventCount = 0;
+
+       return 0;
+}
+
+/***********************************************************************
+ * Sysfs functions. Sysfs prefers that individually-tunable parameters
+ * exist in their separate pseudo-files. Summary data that is immutable
+ * may exist in a singular file so long as you don't define a writeable
+ * interface.
+ */
+
+/***********************************************************************
+ * support the 'size' file -- display support
+ */
+static ssize_t show_tabletSize(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct aiptek *aiptek = dev_get_drvdata(dev);
+
+       if (aiptek == NULL)
+               return 0;
+
+       return snprintf(buf, PAGE_SIZE, "%dx%d\n",
+                       aiptek->inputdev->absmax[ABS_X] + 1,
+                       aiptek->inputdev->absmax[ABS_Y] + 1);
+}
+
+/* These structs define the sysfs files, param #1 is the name of the
+ * file, param 2 is the file permissions, param 3 & 4 are to the
+ * output generator and input parser routines. Absence of a routine is
+ * permitted -- it only means can't either 'cat' the file, or send data
+ * to it.
+ */
+static DEVICE_ATTR(size, S_IRUGO, show_tabletSize, NULL);
+
+/***********************************************************************
+ * support routines for the 'product_id' file
+ */
+static ssize_t show_tabletProductId(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct aiptek *aiptek = dev_get_drvdata(dev);
+
+       if (aiptek == NULL)
+               return 0;
+
+       return snprintf(buf, PAGE_SIZE, "0x%04x\n",
+                       aiptek->inputdev->id.product);
+}
+
+static DEVICE_ATTR(product_id, S_IRUGO, show_tabletProductId, NULL);
+
+/***********************************************************************
+ * support routines for the 'vendor_id' file
+ */
+static ssize_t show_tabletVendorId(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct aiptek *aiptek = dev_get_drvdata(dev);
+
+       if (aiptek == NULL)
+               return 0;
+
+       return snprintf(buf, PAGE_SIZE, "0x%04x\n", aiptek->inputdev->id.vendor);
+}
+
+static DEVICE_ATTR(vendor_id, S_IRUGO, show_tabletVendorId, NULL);
+
+/***********************************************************************
+ * support routines for the 'vendor' file
+ */
+static ssize_t show_tabletManufacturer(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct aiptek *aiptek = dev_get_drvdata(dev);
+       int retval;
+
+       if (aiptek == NULL)
+               return 0;
+
+       retval = snprintf(buf, PAGE_SIZE, "%s\n", aiptek->usbdev->manufacturer);
+       return retval;
+}
+
+static DEVICE_ATTR(vendor, S_IRUGO, show_tabletManufacturer, NULL);
+
+/***********************************************************************
+ * support routines for the 'product' file
+ */
+static ssize_t show_tabletProduct(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct aiptek *aiptek = dev_get_drvdata(dev);
+       int retval;
+
+       if (aiptek == NULL)
+               return 0;
+
+       retval = snprintf(buf, PAGE_SIZE, "%s\n", aiptek->usbdev->product);
+       return retval;
+}
+
+static DEVICE_ATTR(product, S_IRUGO, show_tabletProduct, NULL);
+
+/***********************************************************************
+ * support routines for the 'pointer_mode' file. Note that this file
+ * both displays current setting and allows reprogramming.
+ */
+static ssize_t show_tabletPointerMode(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct aiptek *aiptek = dev_get_drvdata(dev);
+       char *s;
+
+       if (aiptek == NULL)
+               return 0;
+
+       switch (aiptek->curSetting.pointerMode) {
+       case AIPTEK_POINTER_ONLY_STYLUS_MODE:
+               s = "stylus";
+               break;
+
+       case AIPTEK_POINTER_ONLY_MOUSE_MODE:
+               s = "mouse";
+               break;
+
+       case AIPTEK_POINTER_EITHER_MODE:
+               s = "either";
+               break;
+
+       default:
+               s = "unknown";
+               break;
+       }
+       return snprintf(buf, PAGE_SIZE, "%s\n", s);
+}
+
+static ssize_t
+store_tabletPointerMode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct aiptek *aiptek = dev_get_drvdata(dev);
+       if (aiptek == NULL)
+               return 0;
+
+       if (strcmp(buf, "stylus") == 0) {
+               aiptek->newSetting.pointerMode =
+                   AIPTEK_POINTER_ONLY_STYLUS_MODE;
+       } else if (strcmp(buf, "mouse") == 0) {
+               aiptek->newSetting.pointerMode = AIPTEK_POINTER_ONLY_MOUSE_MODE;
+       } else if (strcmp(buf, "either") == 0) {
+               aiptek->newSetting.pointerMode = AIPTEK_POINTER_EITHER_MODE;
+       }
+       return count;
+}
+
+static DEVICE_ATTR(pointer_mode,
+                  S_IRUGO | S_IWUGO,
+                  show_tabletPointerMode, store_tabletPointerMode);
+
+/***********************************************************************
+ * support routines for the 'coordinate_mode' file. Note that this file
+ * both displays current setting and allows reprogramming.
+ */
+static ssize_t show_tabletCoordinateMode(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct aiptek *aiptek = dev_get_drvdata(dev);
+       char *s;
+
+       if (aiptek == NULL)
+               return 0;
+
+       switch (aiptek->curSetting.coordinateMode) {
+       case AIPTEK_COORDINATE_ABSOLUTE_MODE:
+               s = "absolute";
+               break;
+
+       case AIPTEK_COORDINATE_RELATIVE_MODE:
+               s = "relative";
+               break;
+
+       default:
+               s = "unknown";
+               break;
+       }
+       return snprintf(buf, PAGE_SIZE, "%s\n", s);
+}
+
+static ssize_t
+store_tabletCoordinateMode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct aiptek *aiptek = dev_get_drvdata(dev);
+       if (aiptek == NULL)
+               return 0;
+
+       if (strcmp(buf, "absolute") == 0) {
+               aiptek->newSetting.pointerMode =
+                   AIPTEK_COORDINATE_ABSOLUTE_MODE;
+       } else if (strcmp(buf, "relative") == 0) {
+               aiptek->newSetting.pointerMode =
+                   AIPTEK_COORDINATE_RELATIVE_MODE;
+       }
+       return count;
+}
+
+static DEVICE_ATTR(coordinate_mode,
+                  S_IRUGO | S_IWUGO,
+                  show_tabletCoordinateMode, store_tabletCoordinateMode);
+
+/***********************************************************************
+ * support routines for the 'tool_mode' file. Note that this file
+ * both displays current setting and allows reprogramming.
+ */
+static ssize_t show_tabletToolMode(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct aiptek *aiptek = dev_get_drvdata(dev);
+       char *s;
+
+       if (aiptek == NULL)
+               return 0;
+
+       switch (TOOL_BUTTON(aiptek->curSetting.toolMode)) {
+       case AIPTEK_TOOL_BUTTON_MOUSE_MODE:
+               s = "mouse";
+               break;
+
+       case AIPTEK_TOOL_BUTTON_ERASER_MODE:
+               s = "eraser";
+               break;
+
+       case AIPTEK_TOOL_BUTTON_PENCIL_MODE:
+               s = "pencil";
+               break;
+
+       case AIPTEK_TOOL_BUTTON_PEN_MODE:
+               s = "pen";
+               break;
+
+       case AIPTEK_TOOL_BUTTON_BRUSH_MODE:
+               s = "brush";
+               break;
+
+       case AIPTEK_TOOL_BUTTON_AIRBRUSH_MODE:
+               s = "airbrush";
+               break;
+
+       case AIPTEK_TOOL_BUTTON_LENS_MODE:
+               s = "lens";
+               break;
+
+       default:
+               s = "unknown";
+               break;
+       }
+       return snprintf(buf, PAGE_SIZE, "%s\n", s);
+}
+
+static ssize_t
+store_tabletToolMode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct aiptek *aiptek = dev_get_drvdata(dev);
+       if (aiptek == NULL)
+               return 0;
+
+       if (strcmp(buf, "mouse") == 0) {
+               aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_MOUSE_MODE;
+       } else if (strcmp(buf, "eraser") == 0) {
+               aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_ERASER_MODE;
+       } else if (strcmp(buf, "pencil") == 0) {
+               aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_PENCIL_MODE;
+       } else if (strcmp(buf, "pen") == 0) {
+               aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_PEN_MODE;
+       } else if (strcmp(buf, "brush") == 0) {
+               aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_BRUSH_MODE;
+       } else if (strcmp(buf, "airbrush") == 0) {
+               aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_AIRBRUSH_MODE;
+       } else if (strcmp(buf, "lens") == 0) {
+               aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_LENS_MODE;
+       }
+
+       return count;
+}
+
+static DEVICE_ATTR(tool_mode,
+                  S_IRUGO | S_IWUGO,
+                  show_tabletToolMode, store_tabletToolMode);
+
+/***********************************************************************
+ * support routines for the 'xtilt' file. Note that this file
+ * both displays current setting and allows reprogramming.
+ */
+static ssize_t show_tabletXtilt(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct aiptek *aiptek = dev_get_drvdata(dev);
+
+       if (aiptek == NULL)
+               return 0;
+
+       if (aiptek->curSetting.xTilt == AIPTEK_TILT_DISABLE) {
+               return snprintf(buf, PAGE_SIZE, "disable\n");
+       } else {
+               return snprintf(buf, PAGE_SIZE, "%d\n",
+                               aiptek->curSetting.xTilt);
+       }
+}
+
+static ssize_t
+store_tabletXtilt(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct aiptek *aiptek = dev_get_drvdata(dev);
+       int x;
+
+       if (aiptek == NULL)
+               return 0;
+
+       if (strcmp(buf, "disable") == 0) {
+               aiptek->newSetting.xTilt = AIPTEK_TILT_DISABLE;
+       } else {
+               x = (int)simple_strtol(buf, NULL, 10);
+               if (x >= AIPTEK_TILT_MIN && x <= AIPTEK_TILT_MAX) {
+                       aiptek->newSetting.xTilt = x;
+               }
+       }
+       return count;
+}
+
+static DEVICE_ATTR(xtilt,
+                  S_IRUGO | S_IWUGO, show_tabletXtilt, store_tabletXtilt);
+
+/***********************************************************************
+ * support routines for the 'ytilt' file. Note that this file
+ * both displays current setting and allows reprogramming.
+ */
+static ssize_t show_tabletYtilt(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct aiptek *aiptek = dev_get_drvdata(dev);
+
+       if (aiptek == NULL)
+               return 0;
+
+       if (aiptek->curSetting.yTilt == AIPTEK_TILT_DISABLE) {
+               return snprintf(buf, PAGE_SIZE, "disable\n");
+       } else {
+               return snprintf(buf, PAGE_SIZE, "%d\n",
+                               aiptek->curSetting.yTilt);
+       }
+}
+
+static ssize_t
+store_tabletYtilt(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct aiptek *aiptek = dev_get_drvdata(dev);
+       int y;
+
+       if (aiptek == NULL)
+               return 0;
+
+       if (strcmp(buf, "disable") == 0) {
+               aiptek->newSetting.yTilt = AIPTEK_TILT_DISABLE;
+       } else {
+               y = (int)simple_strtol(buf, NULL, 10);
+               if (y >= AIPTEK_TILT_MIN && y <= AIPTEK_TILT_MAX) {
+                       aiptek->newSetting.yTilt = y;
+               }
+       }
+       return count;
+}
+
+static DEVICE_ATTR(ytilt,
+                  S_IRUGO | S_IWUGO, show_tabletYtilt, store_tabletYtilt);
+
+/***********************************************************************
+ * support routines for the 'jitter' file. Note that this file
+ * both displays current setting and allows reprogramming.
+ */
+static ssize_t show_tabletJitterDelay(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct aiptek *aiptek = dev_get_drvdata(dev);
+
+       if (aiptek == NULL)
+               return 0;
+
+       return snprintf(buf, PAGE_SIZE, "%d\n", aiptek->curSetting.jitterDelay);
+}
+
+static ssize_t
+store_tabletJitterDelay(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct aiptek *aiptek = dev_get_drvdata(dev);
+
+       if (aiptek == NULL)
+               return 0;
+
+       aiptek->newSetting.jitterDelay = (int)simple_strtol(buf, NULL, 10);
+       return count;
+}
+
+static DEVICE_ATTR(jitter,
+                  S_IRUGO | S_IWUGO,
+                  show_tabletJitterDelay, store_tabletJitterDelay);
+
+/***********************************************************************
+ * support routines for the 'delay' file. Note that this file
+ * both displays current setting and allows reprogramming.
+ */
+static ssize_t show_tabletProgrammableDelay(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct aiptek *aiptek = dev_get_drvdata(dev);
+
+       if (aiptek == NULL)
+               return 0;
+
+       return snprintf(buf, PAGE_SIZE, "%d\n",
+                       aiptek->curSetting.programmableDelay);
+}
+
+static ssize_t
+store_tabletProgrammableDelay(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct aiptek *aiptek = dev_get_drvdata(dev);
+
+       if (aiptek == NULL)
+               return 0;
+
+       aiptek->newSetting.programmableDelay = (int)simple_strtol(buf, NULL, 10);
+       return count;
+}
+
+static DEVICE_ATTR(delay,
+                  S_IRUGO | S_IWUGO,
+                  show_tabletProgrammableDelay, store_tabletProgrammableDelay);
+
+/***********************************************************************
+ * support routines for the 'input_path' file. Note that this file
+ * only displays current setting.
+ */
+static ssize_t show_tabletInputDevice(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct aiptek *aiptek = dev_get_drvdata(dev);
+
+       if (aiptek == NULL)
+               return 0;
+
+       return snprintf(buf, PAGE_SIZE, "/dev/input/%s\n",
+                       aiptek->features.inputPath);
+}
+
+static DEVICE_ATTR(input_path, S_IRUGO, show_tabletInputDevice, NULL);
+
+/***********************************************************************
+ * support routines for the 'event_count' file. Note that this file
+ * only displays current setting.
+ */
+static ssize_t show_tabletEventsReceived(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct aiptek *aiptek = dev_get_drvdata(dev);
+
+       if (aiptek == NULL)
+               return 0;
+
+       return snprintf(buf, PAGE_SIZE, "%ld\n", aiptek->eventCount);
+}
+
+static DEVICE_ATTR(event_count, S_IRUGO, show_tabletEventsReceived, NULL);
+
+/***********************************************************************
+ * support routines for the 'diagnostic' file. Note that this file
+ * only displays current setting.
+ */
+static ssize_t show_tabletDiagnosticMessage(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct aiptek *aiptek = dev_get_drvdata(dev);
+       char *retMsg;
+
+       if (aiptek == NULL)
+               return 0;
+
+       switch (aiptek->diagnostic) {
+       case AIPTEK_DIAGNOSTIC_NA:
+               retMsg = "no errors\n";
+               break;
+
+       case AIPTEK_DIAGNOSTIC_SENDING_RELATIVE_IN_ABSOLUTE:
+               retMsg = "Error: receiving relative reports\n";
+               break;
+
+       case AIPTEK_DIAGNOSTIC_SENDING_ABSOLUTE_IN_RELATIVE:
+               retMsg = "Error: receiving absolute reports\n";
+               break;
+
+       case AIPTEK_DIAGNOSTIC_TOOL_DISALLOWED:
+               if (aiptek->curSetting.pointerMode ==
+                   AIPTEK_POINTER_ONLY_MOUSE_MODE) {
+                       retMsg = "Error: receiving stylus reports\n";
+               } else {
+                       retMsg = "Error: receiving mouse reports\n";
+               }
+               break;
+
+       default:
+               return 0;
+       }
+       return snprintf(buf, PAGE_SIZE, retMsg);
+}
+
+static DEVICE_ATTR(diagnostic, S_IRUGO, show_tabletDiagnosticMessage, NULL);
+
+/***********************************************************************
+ * support routines for the 'stylus_upper' file. Note that this file
+ * both displays current setting and allows for setting changing.
+ */
+static ssize_t show_tabletStylusUpper(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct aiptek *aiptek = dev_get_drvdata(dev);
+       char *s;
+
+       if (aiptek == NULL)
+               return 0;
+
+       switch (aiptek->curSetting.stylusButtonUpper) {
+       case AIPTEK_STYLUS_UPPER_BUTTON:
+               s = "upper";
+               break;
+
+       case AIPTEK_STYLUS_LOWER_BUTTON:
+               s = "lower";
+               break;
+
+       default:
+               s = "unknown";
+               break;
+       }
+       return snprintf(buf, PAGE_SIZE, "%s\n", s);
+}
+
+static ssize_t
+store_tabletStylusUpper(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct aiptek *aiptek = dev_get_drvdata(dev);
+
+       if (aiptek == NULL)
+               return 0;
+
+       if (strcmp(buf, "upper") == 0) {
+               aiptek->newSetting.stylusButtonUpper =
+                   AIPTEK_STYLUS_UPPER_BUTTON;
+       } else if (strcmp(buf, "lower") == 0) {
+               aiptek->newSetting.stylusButtonUpper =
+                   AIPTEK_STYLUS_LOWER_BUTTON;
+       }
+       return count;
+}
+
+static DEVICE_ATTR(stylus_upper,
+                  S_IRUGO | S_IWUGO,
+                  show_tabletStylusUpper, store_tabletStylusUpper);
+
+/***********************************************************************
+ * support routines for the 'stylus_lower' file. Note that this file
+ * both displays current setting and allows for setting changing.
+ */
+static ssize_t show_tabletStylusLower(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct aiptek *aiptek = dev_get_drvdata(dev);
+       char *s;
+
+       if (aiptek == NULL)
+               return 0;
+
+       switch (aiptek->curSetting.stylusButtonLower) {
+       case AIPTEK_STYLUS_UPPER_BUTTON:
+               s = "upper";
+               break;
+
+       case AIPTEK_STYLUS_LOWER_BUTTON:
+               s = "lower";
+               break;
+
+       default:
+               s = "unknown";
+               break;
+       }
+       return snprintf(buf, PAGE_SIZE, "%s\n", s);
+}
+
+static ssize_t
+store_tabletStylusLower(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct aiptek *aiptek = dev_get_drvdata(dev);
+
+       if (aiptek == NULL)
+               return 0;
+
+       if (strcmp(buf, "upper") == 0) {
+               aiptek->newSetting.stylusButtonLower =
+                   AIPTEK_STYLUS_UPPER_BUTTON;
+       } else if (strcmp(buf, "lower") == 0) {
+               aiptek->newSetting.stylusButtonLower =
+                   AIPTEK_STYLUS_LOWER_BUTTON;
+       }
+       return count;
+}
+
+static DEVICE_ATTR(stylus_lower,
+                  S_IRUGO | S_IWUGO,
+                  show_tabletStylusLower, store_tabletStylusLower);
+
+/***********************************************************************
+ * support routines for the 'mouse_left' file. Note that this file
+ * both displays current setting and allows for setting changing.
+ */
+static ssize_t show_tabletMouseLeft(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct aiptek *aiptek = dev_get_drvdata(dev);
+       char *s;
+
+       if (aiptek == NULL)
+               return 0;
+
+       switch (aiptek->curSetting.mouseButtonLeft) {
+       case AIPTEK_MOUSE_LEFT_BUTTON:
+               s = "left";
+               break;
+
+       case AIPTEK_MOUSE_MIDDLE_BUTTON:
+               s = "middle";
+               break;
+
+       case AIPTEK_MOUSE_RIGHT_BUTTON:
+               s = "right";
+               break;
+
+       default:
+               s = "unknown";
+               break;
+       }
+       return snprintf(buf, PAGE_SIZE, "%s\n", s);
+}
+
+static ssize_t
+store_tabletMouseLeft(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct aiptek *aiptek = dev_get_drvdata(dev);
+
+       if (aiptek == NULL)
+               return 0;
+
+       if (strcmp(buf, "left") == 0) {
+               aiptek->newSetting.mouseButtonLeft = AIPTEK_MOUSE_LEFT_BUTTON;
+       } else if (strcmp(buf, "middle") == 0) {
+               aiptek->newSetting.mouseButtonLeft = AIPTEK_MOUSE_MIDDLE_BUTTON;
+       } else if (strcmp(buf, "right") == 0) {
+               aiptek->newSetting.mouseButtonLeft = AIPTEK_MOUSE_RIGHT_BUTTON;
+       }
+       return count;
+}
+
+static DEVICE_ATTR(mouse_left,
+                  S_IRUGO | S_IWUGO,
+                  show_tabletMouseLeft, store_tabletMouseLeft);
+
+/***********************************************************************
+ * support routines for the 'mouse_middle' file. Note that this file
+ * both displays current setting and allows for setting changing.
+ */
+static ssize_t show_tabletMouseMiddle(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct aiptek *aiptek = dev_get_drvdata(dev);
+       char *s;
+
+       if (aiptek == NULL)
+               return 0;
+
+       switch (aiptek->curSetting.mouseButtonMiddle) {
+       case AIPTEK_MOUSE_LEFT_BUTTON:
+               s = "left";
+               break;
+
+       case AIPTEK_MOUSE_MIDDLE_BUTTON:
+               s = "middle";
+               break;
+
+       case AIPTEK_MOUSE_RIGHT_BUTTON:
+               s = "right";
+               break;
+
+       default:
+               s = "unknown";
+               break;
+       }
+       return snprintf(buf, PAGE_SIZE, "%s\n", s);
+}
+
+static ssize_t
+store_tabletMouseMiddle(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct aiptek *aiptek = dev_get_drvdata(dev);
+
+       if (aiptek == NULL)
+               return 0;
+
+       if (strcmp(buf, "left") == 0) {
+               aiptek->newSetting.mouseButtonMiddle = AIPTEK_MOUSE_LEFT_BUTTON;
+       } else if (strcmp(buf, "middle") == 0) {
+               aiptek->newSetting.mouseButtonMiddle =
+                   AIPTEK_MOUSE_MIDDLE_BUTTON;
+       } else if (strcmp(buf, "right") == 0) {
+               aiptek->newSetting.mouseButtonMiddle =
+                   AIPTEK_MOUSE_RIGHT_BUTTON;
+       }
+       return count;
+}
+
+static DEVICE_ATTR(mouse_middle,
+                  S_IRUGO | S_IWUGO,
+                  show_tabletMouseMiddle, store_tabletMouseMiddle);
+
+/***********************************************************************
+ * support routines for the 'mouse_right' file. Note that this file
+ * both displays current setting and allows for setting changing.
+ */
+static ssize_t show_tabletMouseRight(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct aiptek *aiptek = dev_get_drvdata(dev);
+       char *s;
+
+       if (aiptek == NULL)
+               return 0;
+
+       switch (aiptek->curSetting.mouseButtonRight) {
+       case AIPTEK_MOUSE_LEFT_BUTTON:
+               s = "left";
+               break;
+
+       case AIPTEK_MOUSE_MIDDLE_BUTTON:
+               s = "middle";
+               break;
+
+       case AIPTEK_MOUSE_RIGHT_BUTTON:
+               s = "right";
+               break;
+
+       default:
+               s = "unknown";
+               break;
+       }
+       return snprintf(buf, PAGE_SIZE, "%s\n", s);
+}
+
+static ssize_t
+store_tabletMouseRight(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct aiptek *aiptek = dev_get_drvdata(dev);
+
+       if (aiptek == NULL)
+               return 0;
+
+       if (strcmp(buf, "left") == 0) {
+               aiptek->newSetting.mouseButtonRight = AIPTEK_MOUSE_LEFT_BUTTON;
+       } else if (strcmp(buf, "middle") == 0) {
+               aiptek->newSetting.mouseButtonRight =
+                   AIPTEK_MOUSE_MIDDLE_BUTTON;
+       } else if (strcmp(buf, "right") == 0) {
+               aiptek->newSetting.mouseButtonRight = AIPTEK_MOUSE_RIGHT_BUTTON;
+       }
+       return count;
+}
+
+static DEVICE_ATTR(mouse_right,
+                  S_IRUGO | S_IWUGO,
+                  show_tabletMouseRight, store_tabletMouseRight);
+
+/***********************************************************************
+ * support routines for the 'wheel' file. Note that this file
+ * both displays current setting and allows for setting changing.
+ */
+static ssize_t show_tabletWheel(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct aiptek *aiptek = dev_get_drvdata(dev);
+
+       if (aiptek == NULL)
+               return 0;
+
+       if (aiptek->curSetting.wheel == AIPTEK_WHEEL_DISABLE) {
+               return snprintf(buf, PAGE_SIZE, "disable\n");
+       } else {
+               return snprintf(buf, PAGE_SIZE, "%d\n",
+                               aiptek->curSetting.wheel);
+       }
+}
+
+static ssize_t
+store_tabletWheel(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct aiptek *aiptek = dev_get_drvdata(dev);
+
+       if (aiptek == NULL)
+               return 0;
+
+       aiptek->newSetting.wheel = (int)simple_strtol(buf, NULL, 10);
+       return count;
+}
+
+static DEVICE_ATTR(wheel,
+                  S_IRUGO | S_IWUGO, show_tabletWheel, store_tabletWheel);
+
+/***********************************************************************
+ * support routines for the 'execute' file. Note that this file
+ * both displays current setting and allows for setting changing.
+ */
+static ssize_t show_tabletExecute(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct aiptek *aiptek = dev_get_drvdata(dev);
+
+       if (aiptek == NULL)
+               return 0;
+
+       /* There is nothing useful to display, so a one-line manual
+        * is in order...
+        */
+       return snprintf(buf, PAGE_SIZE,
+                       "Write anything to this file to program your tablet.\n");
+}
+
+static ssize_t
+store_tabletExecute(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct aiptek *aiptek = dev_get_drvdata(dev);
+
+       if (aiptek == NULL)
+               return 0;
+
+       /* We do not care what you write to this file. Merely the action
+        * of writing to this file triggers a tablet reprogramming.
+        */
+       memcpy(&aiptek->curSetting, &aiptek->newSetting,
+              sizeof(struct aiptek_settings));
+
+       if (aiptek_program_tablet(aiptek) < 0)
+               return -EIO;
+
+       return count;
+}
+
+static DEVICE_ATTR(execute,
+                  S_IRUGO | S_IWUGO, show_tabletExecute, store_tabletExecute);
+
+/***********************************************************************
+ * support routines for the 'odm_code' file. Note that this file
+ * only displays current setting.
+ */
+static ssize_t show_tabletODMCode(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct aiptek *aiptek = dev_get_drvdata(dev);
+
+       if (aiptek == NULL)
+               return 0;
+
+       return snprintf(buf, PAGE_SIZE, "0x%04x\n", aiptek->features.odmCode);
+}
+
+static DEVICE_ATTR(odm_code, S_IRUGO, show_tabletODMCode, NULL);
+
+/***********************************************************************
+ * support routines for the 'model_code' file. Note that this file
+ * only displays current setting.
+ */
+static ssize_t show_tabletModelCode(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct aiptek *aiptek = dev_get_drvdata(dev);
+
+       if (aiptek == NULL)
+               return 0;
+
+       return snprintf(buf, PAGE_SIZE, "0x%04x\n", aiptek->features.modelCode);
+}
+
+static DEVICE_ATTR(model_code, S_IRUGO, show_tabletModelCode, NULL);
+
+/***********************************************************************
+ * support routines for the 'firmware_code' file. Note that this file
+ * only displays current setting.
+ */
+static ssize_t show_firmwareCode(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct aiptek *aiptek = dev_get_drvdata(dev);
+
+       if (aiptek == NULL)
+               return 0;
+
+       return snprintf(buf, PAGE_SIZE, "%04x\n",
+                       aiptek->features.firmwareCode);
+}
+
+static DEVICE_ATTR(firmware_code, S_IRUGO, show_firmwareCode, NULL);
+
+/***********************************************************************
+ * This routine removes all existing sysfs files managed by this device
+ * driver.
+ */
+static void aiptek_delete_files(struct device *dev)
+{
+       device_remove_file(dev, &dev_attr_size);
+       device_remove_file(dev, &dev_attr_product_id);
+       device_remove_file(dev, &dev_attr_vendor_id);
+       device_remove_file(dev, &dev_attr_vendor);
+       device_remove_file(dev, &dev_attr_product);
+       device_remove_file(dev, &dev_attr_pointer_mode);
+       device_remove_file(dev, &dev_attr_coordinate_mode);
+       device_remove_file(dev, &dev_attr_tool_mode);
+       device_remove_file(dev, &dev_attr_xtilt);
+       device_remove_file(dev, &dev_attr_ytilt);
+       device_remove_file(dev, &dev_attr_jitter);
+       device_remove_file(dev, &dev_attr_delay);
+       device_remove_file(dev, &dev_attr_input_path);
+       device_remove_file(dev, &dev_attr_event_count);
+       device_remove_file(dev, &dev_attr_diagnostic);
+       device_remove_file(dev, &dev_attr_odm_code);
+       device_remove_file(dev, &dev_attr_model_code);
+       device_remove_file(dev, &dev_attr_firmware_code);
+       device_remove_file(dev, &dev_attr_stylus_lower);
+       device_remove_file(dev, &dev_attr_stylus_upper);
+       device_remove_file(dev, &dev_attr_mouse_left);
+       device_remove_file(dev, &dev_attr_mouse_middle);
+       device_remove_file(dev, &dev_attr_mouse_right);
+       device_remove_file(dev, &dev_attr_wheel);
+       device_remove_file(dev, &dev_attr_execute);
+}
+
+/***********************************************************************
+ * This routine creates the sysfs files managed by this device
+ * driver.
+ */
+static int aiptek_add_files(struct device *dev)
+{
+       int ret;
+
+       if ((ret = device_create_file(dev, &dev_attr_size)) ||
+           (ret = device_create_file(dev, &dev_attr_product_id)) ||
+           (ret = device_create_file(dev, &dev_attr_vendor_id)) ||
+           (ret = device_create_file(dev, &dev_attr_vendor)) ||
+           (ret = device_create_file(dev, &dev_attr_product)) ||
+           (ret = device_create_file(dev, &dev_attr_pointer_mode)) ||
+           (ret = device_create_file(dev, &dev_attr_coordinate_mode)) ||
+           (ret = device_create_file(dev, &dev_attr_tool_mode)) ||
+           (ret = device_create_file(dev, &dev_attr_xtilt)) ||
+           (ret = device_create_file(dev, &dev_attr_ytilt)) ||
+           (ret = device_create_file(dev, &dev_attr_jitter)) ||
+           (ret = device_create_file(dev, &dev_attr_delay)) ||
+           (ret = device_create_file(dev, &dev_attr_input_path)) ||
+           (ret = device_create_file(dev, &dev_attr_event_count)) ||
+           (ret = device_create_file(dev, &dev_attr_diagnostic)) ||
+           (ret = device_create_file(dev, &dev_attr_odm_code)) ||
+           (ret = device_create_file(dev, &dev_attr_model_code)) ||
+           (ret = device_create_file(dev, &dev_attr_firmware_code)) ||
+           (ret = device_create_file(dev, &dev_attr_stylus_lower)) ||
+           (ret = device_create_file(dev, &dev_attr_stylus_upper)) ||
+           (ret = device_create_file(dev, &dev_attr_mouse_left)) ||
+           (ret = device_create_file(dev, &dev_attr_mouse_middle)) ||
+           (ret = device_create_file(dev, &dev_attr_mouse_right)) ||
+           (ret = device_create_file(dev, &dev_attr_wheel)) ||
+           (ret = device_create_file(dev, &dev_attr_execute))) {
+               err("aiptek: killing own sysfs device files\n");
+               aiptek_delete_files(dev);
+       }
+       return ret;
+}
+
+/***********************************************************************
+ * This routine is called when a tablet has been identified. It basically
+ * sets up the tablet and the driver's internal structures.
+ */
+static int
+aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+       struct usb_device *usbdev = interface_to_usbdev(intf);
+       struct usb_endpoint_descriptor *endpoint;
+       struct aiptek *aiptek;
+       struct input_dev *inputdev;
+       struct input_handle *inputhandle;
+       struct list_head *node, *next;
+       int i;
+       int speeds[] = { 0,
+               AIPTEK_PROGRAMMABLE_DELAY_50,
+               AIPTEK_PROGRAMMABLE_DELAY_400,
+               AIPTEK_PROGRAMMABLE_DELAY_25,
+               AIPTEK_PROGRAMMABLE_DELAY_100,
+               AIPTEK_PROGRAMMABLE_DELAY_200,
+               AIPTEK_PROGRAMMABLE_DELAY_300
+       };
+       int err = -ENOMEM;
+
+       /* programmableDelay is where the command-line specified
+        * delay is kept. We make it the first element of speeds[],
+        * so therefore, your override speed is tried first, then the
+        * remainder. Note that the default value of 400ms will be tried
+        * if you do not specify any command line parameter.
+        */
+       speeds[0] = programmableDelay;
+
+       aiptek = kzalloc(sizeof(struct aiptek), GFP_KERNEL);
+       inputdev = input_allocate_device();
+       if (!aiptek || !inputdev)
+               goto fail1;
+
+       aiptek->data = usb_buffer_alloc(usbdev, AIPTEK_PACKET_LENGTH,
+                                       GFP_ATOMIC, &aiptek->data_dma);
+       if (!aiptek->data)
+               goto fail1;
+
+       aiptek->urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!aiptek->urb)
+               goto fail2;
+
+       aiptek->inputdev = inputdev;
+       aiptek->usbdev = usbdev;
+       aiptek->ifnum = intf->altsetting[0].desc.bInterfaceNumber;
+       aiptek->inDelay = 0;
+       aiptek->endDelay = 0;
+       aiptek->previousJitterable = 0;
+
+       /* Set up the curSettings struct. Said struct contains the current
+        * programmable parameters. The newSetting struct contains changes
+        * the user makes to the settings via the sysfs interface. Those
+        * changes are not "committed" to curSettings until the user
+        * writes to the sysfs/.../execute file.
+        */
+       aiptek->curSetting.pointerMode = AIPTEK_POINTER_EITHER_MODE;
+       aiptek->curSetting.coordinateMode = AIPTEK_COORDINATE_ABSOLUTE_MODE;
+       aiptek->curSetting.toolMode = AIPTEK_TOOL_BUTTON_PEN_MODE;
+       aiptek->curSetting.xTilt = AIPTEK_TILT_DISABLE;
+       aiptek->curSetting.yTilt = AIPTEK_TILT_DISABLE;
+       aiptek->curSetting.mouseButtonLeft = AIPTEK_MOUSE_LEFT_BUTTON;
+       aiptek->curSetting.mouseButtonMiddle = AIPTEK_MOUSE_MIDDLE_BUTTON;
+       aiptek->curSetting.mouseButtonRight = AIPTEK_MOUSE_RIGHT_BUTTON;
+       aiptek->curSetting.stylusButtonUpper = AIPTEK_STYLUS_UPPER_BUTTON;
+       aiptek->curSetting.stylusButtonLower = AIPTEK_STYLUS_LOWER_BUTTON;
+       aiptek->curSetting.jitterDelay = jitterDelay;
+       aiptek->curSetting.programmableDelay = programmableDelay;
+
+       /* Both structs should have equivalent settings
+        */
+       aiptek->newSetting = aiptek->curSetting;
+
+       /* Determine the usb devices' physical path.
+        * Asketh not why we always pretend we're using "../input0",
+        * but I suspect this will have to be refactored one
+        * day if a single USB device can be a keyboard & a mouse
+        * & a tablet, and the inputX number actually will tell
+        * us something...
+        */
+       usb_make_path(usbdev, aiptek->features.usbPath,
+                       sizeof(aiptek->features.usbPath));
+       strlcat(aiptek->features.usbPath, "/input0",
+               sizeof(aiptek->features.usbPath));
+
+       /* Set up client data, pointers to open and close routines
+        * for the input device.
+        */
+       inputdev->name = "Aiptek";
+       inputdev->phys = aiptek->features.usbPath;
+       usb_to_input_id(usbdev, &inputdev->id);
+       inputdev->dev.parent = &intf->dev;
+
+       input_set_drvdata(inputdev, aiptek);
+
+       inputdev->open = aiptek_open;
+       inputdev->close = aiptek_close;
+
+       /* Now program the capacities of the tablet, in terms of being
+        * an input device.
+        */
+       inputdev->evbit[0] |= BIT(EV_KEY)
+           | BIT(EV_ABS)
+           | BIT(EV_REL)
+           | BIT(EV_MSC);
+
+       inputdev->absbit[0] |= BIT(ABS_MISC);
+
+       inputdev->relbit[0] |=
+           (BIT(REL_X) | BIT(REL_Y) | BIT(REL_WHEEL) | BIT(REL_MISC));
+
+       inputdev->keybit[LONG(BTN_LEFT)] |=
+           (BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE));
+
+       inputdev->keybit[LONG(BTN_DIGI)] |=
+           (BIT(BTN_TOOL_PEN) |
+            BIT(BTN_TOOL_RUBBER) |
+            BIT(BTN_TOOL_PENCIL) |
+            BIT(BTN_TOOL_AIRBRUSH) |
+            BIT(BTN_TOOL_BRUSH) |
+            BIT(BTN_TOOL_MOUSE) |
+            BIT(BTN_TOOL_LENS) |
+            BIT(BTN_TOUCH) | BIT(BTN_STYLUS) | BIT(BTN_STYLUS2));
+
+       inputdev->mscbit[0] = BIT(MSC_SERIAL);
+
+       /* Programming the tablet macro keys needs to be done with a for loop
+        * as the keycodes are discontiguous.
+        */
+       for (i = 0; i < ARRAY_SIZE(macroKeyEvents); ++i)
+               set_bit(macroKeyEvents[i], inputdev->keybit);
+
+       /*
+        * Program the input device coordinate capacities. We do not yet
+        * know what maximum X, Y, and Z values are, so we're putting fake
+        * values in. Later, we'll ask the tablet to put in the correct
+        * values.
+        */
+       input_set_abs_params(inputdev, ABS_X, 0, 2999, 0, 0);
+       input_set_abs_params(inputdev, ABS_Y, 0, 2249, 0, 0);
+       input_set_abs_params(inputdev, ABS_PRESSURE, 0, 511, 0, 0);
+       input_set_abs_params(inputdev, ABS_TILT_X, AIPTEK_TILT_MIN, AIPTEK_TILT_MAX, 0, 0);
+       input_set_abs_params(inputdev, ABS_TILT_Y, AIPTEK_TILT_MIN, AIPTEK_TILT_MAX, 0, 0);
+       input_set_abs_params(inputdev, ABS_WHEEL, AIPTEK_WHEEL_MIN, AIPTEK_WHEEL_MAX - 1, 0, 0);
+
+       endpoint = &intf->altsetting[0].endpoint[0].desc;
+
+       /* Go set up our URB, which is called when the tablet receives
+        * input.
+        */
+       usb_fill_int_urb(aiptek->urb,
+                        aiptek->usbdev,
+                        usb_rcvintpipe(aiptek->usbdev,
+                                       endpoint->bEndpointAddress),
+                        aiptek->data, 8, aiptek_irq, aiptek,
+                        endpoint->bInterval);
+
+       aiptek->urb->transfer_dma = aiptek->data_dma;
+       aiptek->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+       /* Program the tablet. This sets the tablet up in the mode
+        * specified in newSetting, and also queries the tablet's
+        * physical capacities.
+        *
+        * Sanity check: if a tablet doesn't like the slow programmatic
+        * delay, we often get sizes of 0x0. Let's use that as an indicator
+        * to try faster delays, up to 25 ms. If that logic fails, well, you'll
+        * have to explain to us how your tablet thinks it's 0x0, and yet that's
+        * not an error :-)
+        */
+
+       for (i = 0; i < ARRAY_SIZE(speeds); ++i) {
+               aiptek->curSetting.programmableDelay = speeds[i];
+               (void)aiptek_program_tablet(aiptek);
+               if (aiptek->inputdev->absmax[ABS_X] > 0) {
+                       info("input: Aiptek using %d ms programming speed\n",
+                            aiptek->curSetting.programmableDelay);
+                       break;
+               }
+       }
+
+       /* Register the tablet as an Input Device
+        */
+       err = input_register_device(aiptek->inputdev);
+       if (err)
+               goto fail2;
+
+       /* We now will look for the evdev device which is mapped to
+        * the tablet. The partial name is kept in the link list of
+        * input_handles associated with this input device.
+        * What identifies an evdev input_handler is that it begins
+        * with 'event', continues with a digit, and that in turn
+        * is mapped to input/eventN.
+        */
+       list_for_each_safe(node, next, &inputdev->h_list) {
+               inputhandle = to_handle(node);
+               if (strncmp(inputhandle->name, "event", 5) == 0) {
+                       strcpy(aiptek->features.inputPath, inputhandle->name);
+                       break;
+               }
+       }
+
+       /* Associate this driver's struct with the usb interface.
+        */
+       usb_set_intfdata(intf, aiptek);
+
+       /* Set up the sysfs files
+        */
+       aiptek_add_files(&intf->dev);
+
+       /* Make sure the evdev module is loaded. Assuming evdev IS a module :-)
+        */
+       if (request_module("evdev") != 0)
+               info("aiptek: error loading 'evdev' module");
+
+       return 0;
+
+ fail2:        usb_buffer_free(usbdev, AIPTEK_PACKET_LENGTH, aiptek->data,
+                       aiptek->data_dma);
+ fail1:        input_free_device(inputdev);
+       kfree(aiptek);
+       return err;
+}
+
+/***********************************************************************
+ * Deal with tablet disconnecting from the system.
+ */
+static void aiptek_disconnect(struct usb_interface *intf)
+{
+       struct aiptek *aiptek = usb_get_intfdata(intf);
+
+       /* Disassociate driver's struct with usb interface
+        */
+       usb_set_intfdata(intf, NULL);
+       if (aiptek != NULL) {
+               /* Free & unhook everything from the system.
+                */
+               usb_kill_urb(aiptek->urb);
+               input_unregister_device(aiptek->inputdev);
+               aiptek_delete_files(&intf->dev);
+               usb_free_urb(aiptek->urb);
+               usb_buffer_free(interface_to_usbdev(intf),
+                               AIPTEK_PACKET_LENGTH,
+                               aiptek->data, aiptek->data_dma);
+               kfree(aiptek);
+       }
+}
+
+static struct usb_driver aiptek_driver = {
+       .name = "aiptek",
+       .probe = aiptek_probe,
+       .disconnect = aiptek_disconnect,
+       .id_table = aiptek_ids,
+};
+
+static int __init aiptek_init(void)
+{
+       int result = usb_register(&aiptek_driver);
+       if (result == 0) {
+               info(DRIVER_VERSION ": " DRIVER_AUTHOR);
+               info(DRIVER_DESC);
+       }
+       return result;
+}
+
+static void __exit aiptek_exit(void)
+{
+       usb_deregister(&aiptek_driver);
+}
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+module_param(programmableDelay, int, 0);
+MODULE_PARM_DESC(programmableDelay, "delay used during tablet programming");
+module_param(jitterDelay, int, 0);
+MODULE_PARM_DESC(jitterDelay, "stylus/mouse settlement delay");
+
+module_init(aiptek_init);
+module_exit(aiptek_exit);
diff --git a/drivers/input/tablet/gtco.c b/drivers/input/tablet/gtco.c
new file mode 100644 (file)
index 0000000..b2ca10f
--- /dev/null
@@ -0,0 +1,1055 @@
+/*    -*- linux-c -*-
+
+GTCO digitizer USB driver
+
+Use the err(), dbg() and info() macros from usb.h for system logging
+
+TO CHECK:  Is pressure done right on report 5?
+
+Copyright (C) 2006  GTCO CalComp
+
+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; version 2
+of the License.
+
+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.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation, and that the name of GTCO-CalComp not be used in advertising
+or publicity pertaining to distribution of the software without specific,
+written prior permission. GTCO-CalComp makes no representations about the
+suitability of this software for any purpose.  It is provided "as is"
+without express or implied warranty.
+
+GTCO-CALCOMP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+EVENT SHALL GTCO-CALCOMP BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+TORTIOUS ACTIONS, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
+
+GTCO CalComp, Inc.
+7125 Riverwood Drive
+Columbia, MD 21046
+
+Jeremy Roberson jroberson@gtcocalcomp.com
+Scott Hill shill@gtcocalcomp.com
+*/
+
+
+
+/*#define DEBUG*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/usb.h>
+#include <asm/uaccess.h>
+#include <asm/unaligned.h>
+#include <asm/byteorder.h>
+
+
+#include <linux/version.h>
+#include <linux/usb/input.h>
+
+/* Version with a Major number of 2 is for kernel inclusion only. */
+#define  GTCO_VERSION   "2.00.0006"
+
+
+/*   MACROS  */
+
+#define VENDOR_ID_GTCO       0x078C
+#define PID_400               0x400
+#define PID_401               0x401
+#define PID_1000              0x1000
+#define PID_1001              0x1001
+#define PID_1002              0x1002
+
+/* Max size of a single report */
+#define REPORT_MAX_SIZE       10
+
+
+/* Bitmask whether pen is in range */
+#define MASK_INRANGE 0x20
+#define MASK_BUTTON  0x01F
+
+#define  PATHLENGTH     64
+
+/* DATA STRUCTURES */
+
+/* Device table */
+static struct usb_device_id gtco_usbid_table [] = {
+       { USB_DEVICE(VENDOR_ID_GTCO, PID_400) },
+       { USB_DEVICE(VENDOR_ID_GTCO, PID_401) },
+       { USB_DEVICE(VENDOR_ID_GTCO, PID_1000) },
+       { USB_DEVICE(VENDOR_ID_GTCO, PID_1001) },
+       { USB_DEVICE(VENDOR_ID_GTCO, PID_1002) },
+       { }
+};
+MODULE_DEVICE_TABLE (usb, gtco_usbid_table);
+
+
+/* Structure to hold all of our device specific stuff */
+struct gtco {
+
+       struct input_dev  *inputdevice; /* input device struct pointer  */
+       struct usb_device *usbdev; /* the usb device for this device */
+       struct urb        *urbinfo;      /* urb for incoming reports      */
+       dma_addr_t        buf_dma;  /* dma addr of the data buffer*/
+       unsigned char *   buffer;   /* databuffer for reports */
+
+       char  usbpath[PATHLENGTH];
+       int   openCount;
+
+       /* Information pulled from Report Descriptor */
+       u32  usage;
+       u32  min_X;
+       u32  max_X;
+       u32  min_Y;
+       u32  max_Y;
+       s8   mintilt_X;
+       s8   maxtilt_X;
+       s8   mintilt_Y;
+       s8   maxtilt_Y;
+       u32  maxpressure;
+       u32  minpressure;
+};
+
+
+
+/*   Code for parsing the HID REPORT DESCRIPTOR          */
+
+/* From HID1.11 spec */
+struct hid_descriptor
+{
+       struct usb_descriptor_header header;
+       __le16   bcdHID;
+       u8       bCountryCode;
+       u8       bNumDescriptors;
+       u8       bDescriptorType;
+       __le16   wDescriptorLength;
+} __attribute__ ((packed));
+
+
+#define HID_DESCRIPTOR_SIZE   9
+#define HID_DEVICE_TYPE       33
+#define REPORT_DEVICE_TYPE    34
+
+
+#define PREF_TAG(x)     ((x)>>4)
+#define PREF_TYPE(x)    ((x>>2)&0x03)
+#define PREF_SIZE(x)    ((x)&0x03)
+
+#define TYPE_MAIN       0
+#define TYPE_GLOBAL     1
+#define TYPE_LOCAL      2
+#define TYPE_RESERVED   3
+
+#define TAG_MAIN_INPUT        0x8
+#define TAG_MAIN_OUTPUT       0x9
+#define TAG_MAIN_FEATURE      0xB
+#define TAG_MAIN_COL_START    0xA
+#define TAG_MAIN_COL_END      0xC
+
+#define TAG_GLOB_USAGE        0
+#define TAG_GLOB_LOG_MIN      1
+#define TAG_GLOB_LOG_MAX      2
+#define TAG_GLOB_PHYS_MIN     3
+#define TAG_GLOB_PHYS_MAX     4
+#define TAG_GLOB_UNIT_EXP     5
+#define TAG_GLOB_UNIT         6
+#define TAG_GLOB_REPORT_SZ    7
+#define TAG_GLOB_REPORT_ID    8
+#define TAG_GLOB_REPORT_CNT   9
+#define TAG_GLOB_PUSH         10
+#define TAG_GLOB_POP          11
+
+#define TAG_GLOB_MAX          12
+
+#define DIGITIZER_USAGE_TIP_PRESSURE   0x30
+#define DIGITIZER_USAGE_TILT_X         0x3D
+#define DIGITIZER_USAGE_TILT_Y         0x3E
+
+
+/*
+ *   This is an abbreviated parser for the HID Report Descriptor.  We
+ *   know what devices we are talking to, so this is by no means meant
+ *   to be generic.  We can make some safe assumptions:
+ *
+ *   - We know there are no LONG tags, all short
+ *   - We know that we have no MAIN Feature and MAIN Output items
+ *   - We know what the IRQ reports are supposed to look like.
+ *
+ *   The main purpose of this is to use the HID report desc to figure
+ *   out the mins and maxs of the fields in the IRQ reports.  The IRQ
+ *   reports for 400/401 change slightly if the max X is bigger than 64K.
+ *
+ */
+static void parse_hid_report_descriptor(struct gtco *device, char * report,
+                                       int length)
+{
+       int   x, i = 0;
+
+       /* Tag primitive vars */
+       __u8   prefix;
+       __u8   size;
+       __u8   tag;
+       __u8   type;
+       __u8   data   = 0;
+       __u16  data16 = 0;
+       __u32  data32 = 0;
+
+       /* For parsing logic */
+       int   inputnum = 0;
+       __u32 usage = 0;
+
+       /* Global Values, indexed by TAG */
+       __u32 globalval[TAG_GLOB_MAX];
+       __u32 oldval[TAG_GLOB_MAX];
+
+       /* Debug stuff */
+       char  maintype = 'x';
+       char  globtype[12];
+       int   indent = 0;
+       char  indentstr[10] = "";
+
+
+       dbg("======>>>>>>PARSE<<<<<<======");
+
+       /* Walk  this report and pull out the info we need */
+       while (i < length) {
+               prefix = report[i];
+
+               /* Skip over prefix */
+               i++;
+
+               /* Determine data size and save the data in the proper variable */
+               size = PREF_SIZE(prefix);
+               switch (size) {
+               case 1:
+                       data = report[i];
+                       break;
+               case 2:
+                       data16 = le16_to_cpu(get_unaligned((__le16 *)&report[i]));
+                       break;
+               case 3:
+                       size = 4;
+                       data32 = le32_to_cpu(get_unaligned((__le32 *)&report[i]));
+                       break;
+               }
+
+               /* Skip size of data */
+               i += size;
+
+               /* What we do depends on the tag type */
+               tag  = PREF_TAG(prefix);
+               type = PREF_TYPE(prefix);
+               switch (type) {
+               case TYPE_MAIN:
+                       strcpy(globtype, "");
+                       switch (tag) {
+
+                       case TAG_MAIN_INPUT:
+                               /*
+                                * The INPUT MAIN tag signifies this is
+                                * information from a report.  We need to
+                                * figure out what it is and store the
+                                * min/max values
+                                */
+
+                               maintype = 'I';
+                               if (data == 2)
+                                       strcpy(globtype, "Variable");
+                               else if (data == 3)
+                                       strcpy(globtype, "Var|Const");
+
+                               dbg("::::: Saving Report: %d input #%d Max: 0x%X(%d) Min:0x%X(%d) of %d bits",
+                                   globalval[TAG_GLOB_REPORT_ID], inputnum,
+                                   globalval[TAG_GLOB_LOG_MAX], globalval[TAG_GLOB_LOG_MAX],
+                                   globalval[TAG_GLOB_LOG_MIN], globalval[TAG_GLOB_LOG_MIN],
+                                   globalval[TAG_GLOB_REPORT_SZ] * globalval[TAG_GLOB_REPORT_CNT]);
+
+
+                               /*
+                                 We can assume that the first two input items
+                                 are always the X and Y coordinates.  After
+                                 that, we look for everything else by
+                                 local usage value
+                                */
+                               switch (inputnum) {
+                               case 0:  /* X coord */
+                                       dbg("GER: X Usage: 0x%x", usage);
+                                       if (device->max_X == 0) {
+                                               device->max_X = globalval[TAG_GLOB_LOG_MAX];
+                                               device->min_X = globalval[TAG_GLOB_LOG_MIN];
+                                       }
+                                       break;
+
+                               case 1:  /* Y coord */
+                                       dbg("GER: Y Usage: 0x%x", usage);
+                                       if (device->max_Y == 0) {
+                                               device->max_Y = globalval[TAG_GLOB_LOG_MAX];
+                                               device->min_Y = globalval[TAG_GLOB_LOG_MIN];
+                                       }
+                                       break;
+
+                               default:
+                                       /* Tilt X */
+                                       if (usage == DIGITIZER_USAGE_TILT_X) {
+                                               if (device->maxtilt_X == 0) {
+                                                       device->maxtilt_X = globalval[TAG_GLOB_LOG_MAX];
+                                                       device->mintilt_X = globalval[TAG_GLOB_LOG_MIN];
+                                               }
+                                       }
+
+                                       /* Tilt Y */
+                                       if (usage == DIGITIZER_USAGE_TILT_Y) {
+                                               if (device->maxtilt_Y == 0) {
+                                                       device->maxtilt_Y = globalval[TAG_GLOB_LOG_MAX];
+                                                       device->mintilt_Y = globalval[TAG_GLOB_LOG_MIN];
+                                               }
+                                       }
+
+                                       /* Pressure */
+                                       if (usage == DIGITIZER_USAGE_TIP_PRESSURE) {
+                                               if (device->maxpressure == 0) {
+                                                       device->maxpressure = globalval[TAG_GLOB_LOG_MAX];
+                                                       device->minpressure = globalval[TAG_GLOB_LOG_MIN];
+                                               }
+                                       }
+
+                                       break;
+                               }
+
+                               inputnum++;
+                               break;
+
+                       case TAG_MAIN_OUTPUT:
+                               maintype = 'O';
+                               break;
+
+                       case TAG_MAIN_FEATURE:
+                               maintype = 'F';
+                               break;
+
+                       case TAG_MAIN_COL_START:
+                               maintype = 'S';
+
+                               if (data == 0) {
+                                       dbg("======>>>>>> Physical");
+                                       strcpy(globtype, "Physical");
+                               } else
+                                       dbg("======>>>>>>");
+
+                               /* Indent the debug output */
+                               indent++;
+                               for (x = 0; x < indent; x++)
+                                       indentstr[x] = '-';
+                               indentstr[x] = 0;
+
+                               /* Save global tags */
+                               for (x = 0; x < TAG_GLOB_MAX; x++)
+                                       oldval[x] = globalval[x];
+
+                               break;
+
+                       case TAG_MAIN_COL_END:
+                               dbg("<<<<<<======");
+                               maintype = 'E';
+                               indent--;
+                               for (x = 0; x < indent; x++)
+                                       indentstr[x] = '-';
+                               indentstr[x] = 0;
+
+                               /* Copy global tags back */
+                               for (x = 0; x < TAG_GLOB_MAX; x++)
+                                       globalval[x] = oldval[x];
+
+                               break;
+                       }
+
+                       switch (size) {
+                       case 1:
+                               dbg("%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x",
+                                   indentstr, tag, maintype, size, globtype, data);
+                               break;
+
+                       case 2:
+                               dbg("%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x",
+                                   indentstr, tag, maintype, size, globtype, data16);
+                               break;
+
+                       case 4:
+                               dbg("%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x",
+                                   indentstr, tag, maintype, size, globtype, data32);
+                               break;
+                       }
+                       break;
+
+               case TYPE_GLOBAL:
+                       switch (tag) {
+                       case TAG_GLOB_USAGE:
+                               /*
+                                * First time we hit the global usage tag,
+                                * it should tell us the type of device
+                                */
+                               if (device->usage == 0)
+                                       device->usage = data;
+
+                               strcpy(globtype, "USAGE");
+                               break;
+
+                       case TAG_GLOB_LOG_MIN:
+                               strcpy(globtype, "LOG_MIN");
+                               break;
+
+                       case TAG_GLOB_LOG_MAX:
+                               strcpy(globtype, "LOG_MAX");
+                               break;
+
+                       case TAG_GLOB_PHYS_MIN:
+                               strcpy(globtype, "PHYS_MIN");
+                               break;
+
+                       case TAG_GLOB_PHYS_MAX:
+                               strcpy(globtype, "PHYS_MAX");
+                               break;
+
+                       case TAG_GLOB_UNIT_EXP:
+                               strcpy(globtype, "EXP");
+                               break;
+
+                       case TAG_GLOB_UNIT:
+                               strcpy(globtype, "UNIT");
+                               break;
+
+                       case TAG_GLOB_REPORT_SZ:
+                               strcpy(globtype, "REPORT_SZ");
+                               break;
+
+                       case TAG_GLOB_REPORT_ID:
+                               strcpy(globtype, "REPORT_ID");
+                               /* New report, restart numbering */
+                               inputnum = 0;
+                               break;
+
+                       case TAG_GLOB_REPORT_CNT:
+                               strcpy(globtype, "REPORT_CNT");
+                               break;
+
+                       case TAG_GLOB_PUSH:
+                               strcpy(globtype, "PUSH");
+                               break;
+
+                       case TAG_GLOB_POP:
+                               strcpy(globtype, "POP");
+                               break;
+                       }
+
+                       /* Check to make sure we have a good tag number
+                          so we don't overflow array */
+                       if (tag < TAG_GLOB_MAX) {
+                               switch (size) {
+                               case 1:
+                                       dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",
+                                           indentstr, globtype, tag, size, data);
+                                       globalval[tag] = data;
+                                       break;
+
+                               case 2:
+                                       dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",
+                                           indentstr, globtype, tag, size, data16);
+                                       globalval[tag] = data16;
+                                       break;
+
+                               case 4:
+                                       dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",
+                                           indentstr, globtype, tag, size, data32);
+                                       globalval[tag] = data32;
+                                       break;
+                               }
+                       } else {
+                               dbg("%sGLOBALTAG: ILLEGAL TAG:%d SIZE: %d ",
+                                   indentstr, tag, size);
+                       }
+                       break;
+
+               case TYPE_LOCAL:
+                       switch (tag) {
+                       case TAG_GLOB_USAGE:
+                               strcpy(globtype, "USAGE");
+                               /* Always 1 byte */
+                               usage = data;
+                               break;
+
+                       case TAG_GLOB_LOG_MIN:
+                               strcpy(globtype, "MIN");
+                               break;
+
+                       case TAG_GLOB_LOG_MAX:
+                               strcpy(globtype, "MAX");
+                               break;
+
+                       default:
+                               strcpy(globtype, "UNKNOWN");
+                               break;
+                       }
+
+                       switch (size) {
+                       case 1:
+                               dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x",
+                                   indentstr, tag, globtype, size, data);
+                               break;
+
+                       case 2:
+                               dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x",
+                                   indentstr, tag, globtype, size, data16);
+                               break;
+
+                       case 4:
+                               dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x",
+                                   indentstr, tag, globtype, size, data32);
+                               break;
+                       }
+
+                       break;
+               }
+       }
+}
+
+/*   INPUT DRIVER Routines                               */
+
+/*
+ * Called when opening the input device.  This will submit the URB to
+ * the usb system so we start getting reports
+ */
+static int gtco_input_open(struct input_dev *inputdev)
+{
+       struct gtco *device = input_get_drvdata(inputdev);
+
+       device->urbinfo->dev = device->usbdev;
+       if (usb_submit_urb(device->urbinfo, GFP_KERNEL))
+               return -EIO;
+
+       return 0;
+}
+
+/*
+ * Called when closing the input device.  This will unlink the URB
+ */
+static void gtco_input_close(struct input_dev *inputdev)
+{
+       struct gtco *device = input_get_drvdata(inputdev);
+
+       usb_kill_urb(device->urbinfo);
+}
+
+
+/*
+ *  Setup input device capabilities.  Tell the input system what this
+ *  device is capable of generating.
+ *
+ *  This information is based on what is read from the HID report and
+ *  placed in the struct gtco structure
+ *
+ */
+static void gtco_setup_caps(struct input_dev *inputdev)
+{
+       struct gtco *device = input_get_drvdata(inputdev);
+
+       /* Which events */
+       inputdev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_MSC);
+
+       /* Misc event menu block */
+       inputdev->mscbit[0] = BIT(MSC_SCAN)|BIT(MSC_SERIAL)|BIT(MSC_RAW) ;
+
+       /* Absolute values based on HID report info */
+       input_set_abs_params(inputdev, ABS_X, device->min_X, device->max_X,
+                            0, 0);
+       input_set_abs_params(inputdev, ABS_Y, device->min_Y, device->max_Y,
+                            0, 0);
+
+       /* Proximity */
+       input_set_abs_params(inputdev, ABS_DISTANCE, 0, 1, 0, 0);
+
+       /* Tilt & pressure */
+       input_set_abs_params(inputdev, ABS_TILT_X, device->mintilt_X,
+                            device->maxtilt_X, 0, 0);
+       input_set_abs_params(inputdev, ABS_TILT_Y, device->mintilt_Y,
+                            device->maxtilt_Y, 0, 0);
+       input_set_abs_params(inputdev, ABS_PRESSURE, device->minpressure,
+                            device->maxpressure, 0, 0);
+
+       /* Transducer */
+       input_set_abs_params(inputdev, ABS_MISC, 0, 0xFF, 0, 0);
+}
+
+/*   USB Routines  */
+
+/*
+ * URB callback routine.  Called when we get IRQ reports from the
+ *  digitizer.
+ *
+ *  This bridges the USB and input device worlds.  It generates events
+ *  on the input device based on the USB reports.
+ */
+static void gtco_urb_callback(struct urb *urbinfo)
+{
+       struct gtco *device = urbinfo->context;
+       struct input_dev  *inputdev;
+       int               rc;
+       u32               val = 0;
+       s8                valsigned = 0;
+       char              le_buffer[2];
+
+       inputdev = device->inputdevice;
+
+       /* Was callback OK? */
+       if (urbinfo->status == -ECONNRESET ||
+           urbinfo->status == -ENOENT ||
+           urbinfo->status == -ESHUTDOWN) {
+
+               /* Shutdown is occurring. Return and don't queue up any more */
+               return;
+       }
+
+       if (urbinfo->status != 0) {
+               /*
+                * Some unknown error.  Hopefully temporary. Just go and
+                * requeue an URB
+                */
+               goto resubmit;
+       }
+
+       /*
+        * Good URB, now process
+        */
+
+       /* PID dependent when we interpret the report */
+       if (inputdev->id.product == PID_1000 ||
+           inputdev->id.product == PID_1001 ||
+           inputdev->id.product == PID_1002) {
+
+               /*
+                * Switch on the report ID
+                * Conveniently, the reports have more information, the higher
+                * the report number.  We can just fall through the case
+                * statements if we start with the highest number report
+                */
+               switch (device->buffer[0]) {
+               case 5:
+                       /* Pressure is 9 bits */
+                       val = ((u16)(device->buffer[8]) << 1);
+                       val |= (u16)(device->buffer[7] >> 7);
+                       input_report_abs(inputdev, ABS_PRESSURE,
+                                        device->buffer[8]);
+
+                       /* Mask out the Y tilt value used for pressure */
+                       device->buffer[7] = (u8)((device->buffer[7]) & 0x7F);
+
+                       /* Fall thru */
+               case 4:
+                       /* Tilt */
+
+                       /* Sign extend these 7 bit numbers.  */
+                       if (device->buffer[6] & 0x40)
+                               device->buffer[6] |= 0x80;
+
+                       if (device->buffer[7] & 0x40)
+                               device->buffer[7] |= 0x80;
+
+
+                       valsigned = (device->buffer[6]);
+                       input_report_abs(inputdev, ABS_TILT_X, (s32)valsigned);
+
+                       valsigned = (device->buffer[7]);
+                       input_report_abs(inputdev, ABS_TILT_Y, (s32)valsigned);
+
+                       /* Fall thru */
+               case 2:
+               case 3:
+                       /* Convert buttons, only 5 bits possible */
+                       val = (device->buffer[5]) & MASK_BUTTON;
+
+                       /* We don't apply any meaning to the bitmask,
+                          just report */
+                       input_event(inputdev, EV_MSC, MSC_SERIAL, val);
+
+                       /*  Fall thru */
+               case 1:
+                       /* All reports have X and Y coords in the same place */
+                       val = le16_to_cpu(get_unaligned((__le16 *)&device->buffer[1]));
+                       input_report_abs(inputdev, ABS_X, val);
+
+                       val = le16_to_cpu(get_unaligned((__le16 *)&device->buffer[3]));
+                       input_report_abs(inputdev, ABS_Y, val);
+
+                       /* Ditto for proximity bit */
+                       val = device->buffer[5] & MASK_INRANGE ? 1 : 0;
+                       input_report_abs(inputdev, ABS_DISTANCE, val);
+
+                       /* Report 1 is an exception to how we handle buttons */
+                       /* Buttons are an index, not a bitmask */
+                       if (device->buffer[0] == 1) {
+
+                               /*
+                                * Convert buttons, 5 bit index
+                                * Report value of index set as one,
+                                * the rest as 0
+                                */
+                               val = device->buffer[5] & MASK_BUTTON;
+                               dbg("======>>>>>>REPORT 1: val 0x%X(%d)",
+                                   val, val);
+
+                               /*
+                                * We don't apply any meaning to the button
+                                * index, just report it
+                                */
+                               input_event(inputdev, EV_MSC, MSC_SERIAL, val);
+                       }
+                       break;
+
+               case 7:
+                       /* Menu blocks */
+                       input_event(inputdev, EV_MSC, MSC_SCAN,
+                                   device->buffer[1]);
+                       break;
+               }
+       }
+
+       /* Other pid class */
+       if (inputdev->id.product == PID_400 ||
+           inputdev->id.product == PID_401) {
+
+               /* Report 2 */
+               if (device->buffer[0] == 2) {
+                       /* Menu blocks */
+                       input_event(inputdev, EV_MSC, MSC_SCAN, device->buffer[1]);
+               }
+
+               /*  Report 1 */
+               if (device->buffer[0] == 1) {
+                       char buttonbyte;
+
+                       /*  IF X max > 64K, we still a bit from the y report */
+                       if (device->max_X > 0x10000) {
+
+                               val = (u16)(((u16)(device->buffer[2] << 8)) | (u8)device->buffer[1]);
+                               val |= (u32)(((u8)device->buffer[3] & 0x1) << 16);
+
+                               input_report_abs(inputdev, ABS_X, val);
+
+                               le_buffer[0]  = (u8)((u8)(device->buffer[3]) >> 1);
+                               le_buffer[0] |= (u8)((device->buffer[3] & 0x1) << 7);
+
+                               le_buffer[1]  = (u8)(device->buffer[4] >> 1);
+                               le_buffer[1] |= (u8)((device->buffer[5] & 0x1) << 7);
+
+                               val = le16_to_cpu(get_unaligned((__le16 *)le_buffer));
+                               input_report_abs(inputdev, ABS_Y, val);
+
+                               /*
+                                * Shift the button byte right by one to
+                                * make it look like the standard report
+                                */
+                               buttonbyte = device->buffer[5] >> 1;
+                       } else {
+
+                               val = le16_to_cpu(get_unaligned((__le16 *)&device->buffer[1]));
+                               input_report_abs(inputdev, ABS_X, val);
+
+                               val = le16_to_cpu(get_unaligned((__le16 *)&device->buffer[3]));
+                               input_report_abs(inputdev, ABS_Y, val);
+
+                               buttonbyte = device->buffer[5];
+                       }
+
+                       /* BUTTONS and PROXIMITY */
+                       val = buttonbyte & MASK_INRANGE ? 1 : 0;
+                       input_report_abs(inputdev, ABS_DISTANCE, val);
+
+                       /* Convert buttons, only 4 bits possible */
+                       val = buttonbyte & 0x0F;
+#ifdef USE_BUTTONS
+                       for (i = 0; i < 5; i++)
+                               input_report_key(inputdev, BTN_DIGI + i, val & (1 << i));
+#else
+                       /* We don't apply any meaning to the bitmask, just report */
+                       input_event(inputdev, EV_MSC, MSC_SERIAL, val);
+#endif
+
+                       /* TRANSDUCER */
+                       input_report_abs(inputdev, ABS_MISC, device->buffer[6]);
+               }
+       }
+
+       /* Everybody gets report ID's */
+       input_event(inputdev, EV_MSC, MSC_RAW,  device->buffer[0]);
+
+       /* Sync it up */
+       input_sync(inputdev);
+
+ resubmit:
+       rc = usb_submit_urb(urbinfo, GFP_ATOMIC);
+       if (rc != 0)
+               err("usb_submit_urb failed rc=0x%x", rc);
+}
+
+/*
+ *  The probe routine.  This is called when the kernel find the matching USB
+ *   vendor/product.  We do the following:
+ *
+ *    - Allocate mem for a local structure to manage the device
+ *    - Request a HID Report Descriptor from the device and parse it to
+ *      find out the device parameters
+ *    - Create an input device and assign it attributes
+ *   - Allocate an URB so the device can talk to us when the input
+ *      queue is open
+ */
+static int gtco_probe(struct usb_interface *usbinterface,
+                     const struct usb_device_id *id)
+{
+
+       struct gtco             *gtco;
+       struct input_dev        *input_dev;
+       struct hid_descriptor   *hid_desc;
+       char                    *report = NULL;
+       int                     result = 0, retry;
+       int                     error;
+       struct usb_endpoint_descriptor *endpoint;
+
+       /* Allocate memory for device structure */
+       gtco = kzalloc(sizeof(struct gtco), GFP_KERNEL);
+       input_dev = input_allocate_device();
+       if (!gtco || !input_dev) {
+               err("No more memory");
+               error = -ENOMEM;
+               goto err_free_devs;
+       }
+
+       /* Set pointer to the input device */
+       gtco->inputdevice = input_dev;
+
+       /* Save interface information */
+       gtco->usbdev = usb_get_dev(interface_to_usbdev(usbinterface));
+
+       /* Allocate some data for incoming reports */
+       gtco->buffer = usb_buffer_alloc(gtco->usbdev, REPORT_MAX_SIZE,
+                                       GFP_KERNEL, &gtco->buf_dma);
+       if (!gtco->buffer) {
+               err("No more memory for us buffers");
+               error = -ENOMEM;
+               goto err_free_devs;
+       }
+
+       /* Allocate URB for reports */
+       gtco->urbinfo = usb_alloc_urb(0, GFP_KERNEL);
+       if (!gtco->urbinfo) {
+               err("Failed to allocate URB");
+               return -ENOMEM;
+               goto err_free_buf;
+       }
+
+       /*
+        * The endpoint is always altsetting 0, we know this since we know
+        * this device only has one interrupt endpoint
+        */
+       endpoint = &usbinterface->altsetting[0].endpoint[0].desc;
+
+       /* Some debug */
+       dbg("gtco # interfaces: %d", usbinterface->num_altsetting);
+       dbg("num endpoints:     %d", usbinterface->cur_altsetting->desc.bNumEndpoints);
+       dbg("interface class:   %d", usbinterface->cur_altsetting->desc.bInterfaceClass);
+       dbg("endpoint: attribute:0x%x type:0x%x", endpoint->bmAttributes, endpoint->bDescriptorType);
+       if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)
+               dbg("endpoint: we have interrupt endpoint\n");
+
+       dbg("endpoint extra len:%d ", usbinterface->altsetting[0].extralen);
+
+       /*
+        * Find the HID descriptor so we can find out the size of the
+        * HID report descriptor
+        */
+       if (usb_get_extra_descriptor(usbinterface->cur_altsetting,
+                                    HID_DEVICE_TYPE, &hid_desc) != 0){
+               err("Can't retrieve exta USB descriptor to get hid report descriptor length");
+               error = -EIO;
+               goto err_free_urb;
+       }
+
+       dbg("Extra descriptor success: type:%d  len:%d",
+           hid_desc->bDescriptorType,  hid_desc->wDescriptorLength);
+
+       report = kzalloc(hid_desc->wDescriptorLength, GFP_KERNEL);
+       if (!report) {
+               err("No more memory for report");
+               error = -ENOMEM;
+               goto err_free_urb;
+       }
+
+       /* Couple of tries to get reply */
+       for (retry = 0; retry < 3; retry++) {
+               result = usb_control_msg(gtco->usbdev,
+                                        usb_rcvctrlpipe(gtco->usbdev, 0),
+                                        USB_REQ_GET_DESCRIPTOR,
+                                        USB_RECIP_INTERFACE | USB_DIR_IN,
+                                        REPORT_DEVICE_TYPE << 8,
+                                        0, /* interface */
+                                        report,
+                                        hid_desc->wDescriptorLength,
+                                        5000); /* 5 secs */
+
+               if (result == hid_desc->wDescriptorLength)
+                       break;
+       }
+
+       /* If we didn't get the report, fail */
+       dbg("usb_control_msg result: :%d", result);
+       if (result != hid_desc->wDescriptorLength) {
+               err("Failed to get HID Report Descriptor of size: %d",
+                   hid_desc->wDescriptorLength);
+               error = -EIO;
+               goto err_free_urb;
+       }
+
+       /* Now we parse the report */
+       parse_hid_report_descriptor(gtco, report, result);
+
+       /* Now we delete it */
+       kfree(report);
+
+       /* Create a device file node */
+       usb_make_path(gtco->usbdev, gtco->usbpath, sizeof(gtco->usbpath));
+       strlcat(gtco->usbpath, "/input0", sizeof(gtco->usbpath));
+
+       /* Set Input device functions */
+       input_dev->open = gtco_input_open;
+       input_dev->close = gtco_input_close;
+
+       /* Set input device information */
+       input_dev->name = "GTCO_CalComp";
+       input_dev->phys = gtco->usbpath;
+
+       input_set_drvdata(input_dev, gtco);
+
+       /* Now set up all the input device capabilities */
+       gtco_setup_caps(input_dev);
+
+       /* Set input device required ID information */
+       usb_to_input_id(gtco->usbdev, &input_dev->id);
+       input_dev->dev.parent = &usbinterface->dev;
+
+       /* Setup the URB, it will be posted later on open of input device */
+       endpoint = &usbinterface->altsetting[0].endpoint[0].desc;
+
+       usb_fill_int_urb(gtco->urbinfo,
+                        gtco->usbdev,
+                        usb_rcvintpipe(gtco->usbdev,
+                                       endpoint->bEndpointAddress),
+                        gtco->buffer,
+                        REPORT_MAX_SIZE,
+                        gtco_urb_callback,
+                        gtco,
+                        endpoint->bInterval);
+
+       gtco->urbinfo->transfer_dma = gtco->buf_dma;
+       gtco->urbinfo->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+       /* Save gtco pointer in USB interface gtco */
+       usb_set_intfdata(usbinterface, gtco);
+
+       /* All done, now register the input device */
+       error = input_register_device(input_dev);
+       if (error)
+               goto err_free_urb;
+
+       return 0;
+
+ err_free_urb:
+       usb_free_urb(gtco->urbinfo);
+ err_free_buf:
+       usb_buffer_free(gtco->usbdev, REPORT_MAX_SIZE,
+                       gtco->buffer, gtco->buf_dma);
+ err_free_devs:
+       kfree(report);
+       input_free_device(input_dev);
+       kfree(gtco);
+       return error;
+}
+
+/*
+ *  This function is a standard USB function called when the USB device
+ *  is disconnected.  We will get rid of the URV, de-register the input
+ *  device, and free up allocated memory
+ */
+static void gtco_disconnect(struct usb_interface *interface)
+{
+       /* Grab private device ptr */
+       struct gtco *gtco = usb_get_intfdata(interface);
+
+       /* Now reverse all the registration stuff */
+       if (gtco) {
+               input_unregister_device(gtco->inputdevice);
+               usb_kill_urb(gtco->urbinfo);
+               usb_free_urb(gtco->urbinfo);
+               usb_buffer_free(gtco->usbdev, REPORT_MAX_SIZE,
+                               gtco->buffer, gtco->buf_dma);
+               kfree(gtco);
+       }
+
+       info("gtco driver disconnected");
+}
+
+/*   STANDARD MODULE LOAD ROUTINES  */
+
+static struct usb_driver gtco_driverinfo_table = {
+       .name           = "gtco",
+       .id_table       = gtco_usbid_table,
+       .probe          = gtco_probe,
+       .disconnect     = gtco_disconnect,
+};
+
+/*
+ *  Register this module with the USB subsystem
+ */
+static int __init gtco_init(void)
+{
+       int error;
+
+       error = usb_register(&gtco_driverinfo_table);
+       if (error) {
+               err("usb_register() failed rc=0x%x", error);
+               return error;
+       }
+
+       printk("GTCO usb driver version: %s", GTCO_VERSION);
+       return 0;
+}
+
+/*
+ *   Deregister this module with the USB subsystem
+ */
+static void __exit gtco_exit(void)
+{
+       usb_deregister(&gtco_driverinfo_table);
+}
+
+module_init(gtco_init);
+module_exit(gtco_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/tablet/kbtab.c b/drivers/input/tablet/kbtab.c
new file mode 100644 (file)
index 0000000..91e6d00
--- /dev/null
@@ -0,0 +1,226 @@
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/usb/input.h>
+#include <asm/unaligned.h>
+
+/*
+ * Version Information
+ * v0.0.1 - Original, extremely basic version, 2.4.xx only
+ * v0.0.2 - Updated, works with 2.5.62 and 2.4.20;
+ *           - added pressure-threshold modules param code from
+ *              Alex Perry <alex.perry@ieee.org>
+ */
+
+#define DRIVER_VERSION "v0.0.2"
+#define DRIVER_AUTHOR "Josh Myer <josh@joshisanerd.com>"
+#define DRIVER_DESC "USB KB Gear JamStudio Tablet driver"
+#define DRIVER_LICENSE "GPL"
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE(DRIVER_LICENSE);
+
+#define USB_VENDOR_ID_KBGEAR   0x084e
+
+static int kb_pressure_click = 0x10;
+module_param(kb_pressure_click, int, 0);
+MODULE_PARM_DESC(kb_pressure_click, "pressure threshold for clicks");
+
+struct kbtab {
+       unsigned char *data;
+       dma_addr_t data_dma;
+       struct input_dev *dev;
+       struct usb_device *usbdev;
+       struct urb *irq;
+       int x, y;
+       int button;
+       int pressure;
+       __u32 serial[2];
+       char phys[32];
+};
+
+static void kbtab_irq(struct urb *urb)
+{
+       struct kbtab *kbtab = urb->context;
+       unsigned char *data = kbtab->data;
+       struct input_dev *dev = kbtab->dev;
+       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;
+       }
+
+       kbtab->x = le16_to_cpu(get_unaligned((__le16 *) &data[1]));
+       kbtab->y = le16_to_cpu(get_unaligned((__le16 *) &data[3]));
+
+       kbtab->pressure = (data[5]);
+
+       input_report_key(dev, BTN_TOOL_PEN, 1);
+
+       input_report_abs(dev, ABS_X, kbtab->x);
+       input_report_abs(dev, ABS_Y, kbtab->y);
+
+       /*input_report_key(dev, BTN_TOUCH , data[0] & 0x01);*/
+       input_report_key(dev, BTN_RIGHT, data[0] & 0x02);
+
+       if (-1 == kb_pressure_click) {
+               input_report_abs(dev, ABS_PRESSURE, kbtab->pressure);
+       } else {
+               input_report_key(dev, BTN_LEFT, (kbtab->pressure > kb_pressure_click) ? 1 : 0);
+       };
+
+       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 usb_device_id kbtab_ids[] = {
+       { USB_DEVICE(USB_VENDOR_ID_KBGEAR, 0x1001), .driver_info = 0 },
+       { }
+};
+
+MODULE_DEVICE_TABLE(usb, kbtab_ids);
+
+static int kbtab_open(struct input_dev *dev)
+{
+       struct kbtab *kbtab = input_get_drvdata(dev);
+
+       kbtab->irq->dev = kbtab->usbdev;
+       if (usb_submit_urb(kbtab->irq, GFP_KERNEL))
+               return -EIO;
+
+       return 0;
+}
+
+static void kbtab_close(struct input_dev *dev)
+{
+       struct kbtab *kbtab = input_get_drvdata(dev);
+
+       usb_kill_urb(kbtab->irq);
+}
+
+static int kbtab_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+       struct usb_device *dev = interface_to_usbdev(intf);
+       struct usb_endpoint_descriptor *endpoint;
+       struct kbtab *kbtab;
+       struct input_dev *input_dev;
+       int error = -ENOMEM;
+
+       kbtab = kzalloc(sizeof(struct kbtab), GFP_KERNEL);
+       input_dev = input_allocate_device();
+       if (!kbtab || !input_dev)
+               goto fail1;
+
+       kbtab->data = usb_buffer_alloc(dev, 8, GFP_KERNEL, &kbtab->data_dma);
+       if (!kbtab->data)
+               goto fail1;
+
+       kbtab->irq = usb_alloc_urb(0, GFP_KERNEL);
+       if (!kbtab->irq)
+               goto fail2;
+
+       kbtab->usbdev = dev;
+       kbtab->dev = input_dev;
+
+       usb_make_path(dev, kbtab->phys, sizeof(kbtab->phys));
+       strlcat(kbtab->phys, "/input0", sizeof(kbtab->phys));
+
+       input_dev->name = "KB Gear Tablet";
+       input_dev->phys = kbtab->phys;
+       usb_to_input_id(dev, &input_dev->id);
+       input_dev->dev.parent = &intf->dev;
+
+       input_set_drvdata(input_dev, kbtab);
+
+       input_dev->open = kbtab_open;
+       input_dev->close = kbtab_close;
+
+       input_dev->evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_MSC);
+       input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
+       input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PEN) | BIT(BTN_TOUCH);
+       input_dev->mscbit[0] |= BIT(MSC_SERIAL);
+       input_set_abs_params(input_dev, ABS_X, 0, 0x2000, 4, 0);
+       input_set_abs_params(input_dev, ABS_Y, 0, 0x1750, 4, 0);
+       input_set_abs_params(input_dev, ABS_PRESSURE, 0, 0xff, 0, 0);
+
+       endpoint = &intf->cur_altsetting->endpoint[0].desc;
+
+       usb_fill_int_urb(kbtab->irq, dev,
+                        usb_rcvintpipe(dev, endpoint->bEndpointAddress),
+                        kbtab->data, 8,
+                        kbtab_irq, kbtab, endpoint->bInterval);
+       kbtab->irq->transfer_dma = kbtab->data_dma;
+       kbtab->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+       error = input_register_device(kbtab->dev);
+       if (error)
+               goto fail3;
+
+       usb_set_intfdata(intf, kbtab);
+
+       return 0;
+
+ fail3:        usb_free_urb(kbtab->irq);
+ fail2:        usb_buffer_free(dev, 10, kbtab->data, kbtab->data_dma);
+ fail1:        input_free_device(input_dev);
+       kfree(kbtab);
+       return error;
+}
+
+static void kbtab_disconnect(struct usb_interface *intf)
+{
+       struct kbtab *kbtab = usb_get_intfdata(intf);
+
+       usb_set_intfdata(intf, NULL);
+       if (kbtab) {
+               usb_kill_urb(kbtab->irq);
+               input_unregister_device(kbtab->dev);
+               usb_free_urb(kbtab->irq);
+               usb_buffer_free(interface_to_usbdev(intf), 10, kbtab->data, kbtab->data_dma);
+               kfree(kbtab);
+       }
+}
+
+static struct usb_driver kbtab_driver = {
+       .name =         "kbtab",
+       .probe =        kbtab_probe,
+       .disconnect =   kbtab_disconnect,
+       .id_table =     kbtab_ids,
+};
+
+static int __init kbtab_init(void)
+{
+       int retval;
+       retval = usb_register(&kbtab_driver);
+       if (retval)
+               goto out;
+       info(DRIVER_VERSION ":" DRIVER_DESC);
+out:
+       return retval;
+}
+
+static void __exit kbtab_exit(void)
+{
+       usb_deregister(&kbtab_driver);
+}
+
+module_init(kbtab_init);
+module_exit(kbtab_exit);
diff --git a/drivers/input/tablet/wacom.h b/drivers/input/tablet/wacom.h
new file mode 100644 (file)
index 0000000..ef01a80
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * drivers/input/tablet/wacom.h
+ *
+ *  USB Wacom Graphire and Wacom Intuos tablet support
+ *
+ *  Copyright (c) 2000-2004 Vojtech Pavlik     <vojtech@ucw.cz>
+ *  Copyright (c) 2000 Andreas Bach Aaen       <abach@stofanet.dk>
+ *  Copyright (c) 2000 Clifford Wolf           <clifford@clifford.at>
+ *  Copyright (c) 2000 Sam Mosel               <sam.mosel@computer.org>
+ *  Copyright (c) 2000 James E. Blair          <corvus@gnu.org>
+ *  Copyright (c) 2000 Daniel Egger            <egger@suse.de>
+ *  Copyright (c) 2001 Frederic Lepied         <flepied@mandrakesoft.com>
+ *  Copyright (c) 2004 Panagiotis Issaris      <panagiotis.issaris@mech.kuleuven.ac.be>
+ *  Copyright (c) 2002-2006 Ping Cheng         <pingc@wacom.com>
+ *
+ *  ChangeLog:
+ *      v0.1 (vp)  - Initial release
+ *      v0.2 (aba) - Support for all buttons / combinations
+ *      v0.3 (vp)  - Support for Intuos added
+ *     v0.4 (sm)  - Support for more Intuos models, menustrip
+ *                     relative mode, proximity.
+ *     v0.5 (vp)  - Big cleanup, nifty features removed,
+ *                     they belong in userspace
+ *     v1.8 (vp)  - Submit URB only when operating, moved to CVS,
+ *                     use input_report_key instead of report_btn and
+ *                     other cleanups
+ *     v1.11 (vp) - Add URB ->dev setting for new kernels
+ *     v1.11 (jb) - Add support for the 4D Mouse & Lens
+ *     v1.12 (de) - Add support for two more inking pen IDs
+ *     v1.14 (vp) - Use new USB device id probing scheme.
+ *                  Fix Wacom Graphire mouse wheel
+ *     v1.18 (vp) - Fix mouse wheel direction
+ *                  Make mouse relative
+ *      v1.20 (fl) - Report tool id for Intuos devices
+ *                 - Multi tools support
+ *                 - Corrected Intuos protocol decoding (airbrush, 4D mouse, lens cursor...)
+ *                 - Add PL models support
+ *                - Fix Wacom Graphire mouse wheel again
+ *     v1.21 (vp) - Removed protocol descriptions
+ *                - Added MISC_SERIAL for tool serial numbers
+ *           (gb) - Identify version on module load.
+ *    v1.21.1 (fl) - added Graphire2 support
+ *    v1.21.2 (fl) - added Intuos2 support
+ *                 - added all the PL ids
+ *    v1.21.3 (fl) - added another eraser id from Neil Okamoto
+ *                 - added smooth filter for Graphire from Peri Hankey
+ *                 - added PenPartner support from Olaf van Es
+ *                 - new tool ids from Ole Martin Bjoerndalen
+ *     v1.29 (pc) - Add support for more tablets
+ *                - Fix pressure reporting
+ *     v1.30 (vp) - Merge 2.4 and 2.5 drivers
+ *                - Since 2.5 now has input_sync(), remove MSC_SERIAL abuse
+ *                - Cleanups here and there
+ *    v1.30.1 (pi) - Added Graphire3 support
+ *     v1.40 (pc) - Add support for several new devices, fix eraser reporting, ...
+ *     v1.43 (pc) - Added support for Cintiq 21UX
+ *                - Fixed a Graphire bug
+ *                - Merged wacom_intuos3_irq into wacom_intuos_irq
+ *     v1.44 (pc) - Added support for Graphire4, Cintiq 710, Intuos3 6x11, etc.
+ *                - Report Device IDs
+ *      v1.45 (pc) - Added support for DTF 521, Intuos3 12x12 and 12x19
+ *                 - Minor data report fix
+ *      v1.46 (pc) - Split wacom.c into wacom_sys.c and wacom_wac.c,
+ *                - where wacom_sys.c deals with system specific code,
+ *                - and wacom_wac.c deals with Wacom specific code
+ *                - Support Intuos3 4x6
+ */
+
+/*
+ * 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.
+ */
+#ifndef WACOM_H
+#define WACOM_H
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/usb/input.h>
+#include <asm/unaligned.h>
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v1.46"
+#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>"
+#define DRIVER_DESC "USB Wacom Graphire and Wacom Intuos tablet driver"
+#define DRIVER_LICENSE "GPL"
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE(DRIVER_LICENSE);
+
+#define USB_VENDOR_ID_WACOM    0x056a
+
+struct wacom {
+       dma_addr_t data_dma;
+       struct input_dev *dev;
+       struct usb_device *usbdev;
+       struct urb *irq;
+       struct wacom_wac * wacom_wac;
+       char phys[32];
+};
+
+struct wacom_combo {
+       struct wacom * wacom;
+       struct urb * urb;
+};
+
+extern int wacom_wac_irq(struct wacom_wac * wacom_wac, void * wcombo);
+extern void wacom_report_abs(void *wcombo, unsigned int abs_type, int abs_data);
+extern void wacom_report_rel(void *wcombo, unsigned int rel_type, int rel_data);
+extern void wacom_report_key(void *wcombo, unsigned int key_type, int key_data);
+extern void wacom_input_event(void *wcombo, unsigned int type, unsigned int code, int value);
+extern void wacom_input_sync(void *wcombo);
+extern void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
+extern void input_dev_g4(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
+extern void input_dev_g(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
+extern void input_dev_i3s(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
+extern void input_dev_i3(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
+extern void input_dev_i(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
+extern void input_dev_pl(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
+extern void input_dev_pt(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
+extern __u16 wacom_le16_to_cpu(unsigned char *data);
+extern __u16 wacom_be16_to_cpu(unsigned char *data);
+extern struct wacom_features * get_wacom_feature(const struct usb_device_id *id);
+extern const struct usb_device_id * get_device_table(void);
+
+#endif
diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c
new file mode 100644 (file)
index 0000000..83bddef
--- /dev/null
@@ -0,0 +1,318 @@
+/*
+ * drivers/input/tablet/wacom_sys.c
+ *
+ *  USB Wacom Graphire and Wacom Intuos tablet support - system specific code
+ */
+
+/*
+ * 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 "wacom.h"
+#include "wacom_wac.h"
+
+#define USB_REQ_GET_REPORT     0x01
+#define USB_REQ_SET_REPORT     0x09
+
+static int usb_get_report(struct usb_interface *intf, unsigned char type,
+                               unsigned char id, void *buf, int size)
+{
+       return usb_control_msg(interface_to_usbdev(intf),
+               usb_rcvctrlpipe(interface_to_usbdev(intf), 0),
+               USB_REQ_GET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+               (type << 8) + id, intf->altsetting[0].desc.bInterfaceNumber,
+               buf, size, 100);
+}
+
+static int usb_set_report(struct usb_interface *intf, unsigned char type,
+                               unsigned char id, void *buf, int size)
+{
+       return usb_control_msg(interface_to_usbdev(intf),
+               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, 1000);
+}
+
+static struct input_dev * get_input_dev(struct wacom_combo *wcombo)
+{
+       return wcombo->wacom->dev;
+}
+
+static void wacom_sys_irq(struct urb *urb)
+{
+       struct wacom *wacom = urb->context;
+       struct wacom_combo wcombo;
+       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;
+       }
+
+       wcombo.wacom = wacom;
+       wcombo.urb = urb;
+
+       if (wacom_wac_irq(wacom->wacom_wac, (void *)&wcombo))
+               input_sync(get_input_dev(&wcombo));
+
+ exit:
+       retval = usb_submit_urb (urb, GFP_ATOMIC);
+       if (retval)
+               err ("%s - usb_submit_urb failed with result %d",
+                    __FUNCTION__, retval);
+}
+
+void wacom_report_key(void *wcombo, unsigned int key_type, int key_data)
+{
+       input_report_key(get_input_dev((struct wacom_combo *)wcombo), key_type, key_data);
+       return;
+}
+
+void wacom_report_abs(void *wcombo, unsigned int abs_type, int abs_data)
+{
+       input_report_abs(get_input_dev((struct wacom_combo *)wcombo), abs_type, abs_data);
+       return;
+}
+
+void wacom_report_rel(void *wcombo, unsigned int rel_type, int rel_data)
+{
+       input_report_rel(get_input_dev((struct wacom_combo *)wcombo), rel_type, rel_data);
+       return;
+}
+
+void wacom_input_event(void *wcombo, unsigned int type, unsigned int code, int value)
+{
+       input_event(get_input_dev((struct wacom_combo *)wcombo), type, code, value);
+       return;
+}
+
+__u16 wacom_be16_to_cpu(unsigned char *data)
+{
+       __u16 value;
+       value = be16_to_cpu(*(__be16 *) data);
+       return value;
+}
+
+__u16 wacom_le16_to_cpu(unsigned char *data)
+{
+       __u16 value;
+       value = le16_to_cpu(*(__le16 *) data);
+       return value;
+}
+
+void wacom_input_sync(void *wcombo)
+{
+       input_sync(get_input_dev((struct wacom_combo *)wcombo));
+       return;
+}
+
+static int wacom_open(struct input_dev *dev)
+{
+       struct wacom *wacom = input_get_drvdata(dev);
+
+       wacom->irq->dev = wacom->usbdev;
+       if (usb_submit_urb(wacom->irq, GFP_KERNEL))
+               return -EIO;
+
+       return 0;
+}
+
+static void wacom_close(struct input_dev *dev)
+{
+       struct wacom *wacom = input_get_drvdata(dev);
+
+       usb_kill_urb(wacom->irq);
+}
+
+void input_dev_g4(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
+{
+       input_dev->evbit[0] |= BIT(EV_MSC);
+       input_dev->mscbit[0] |= BIT(MSC_SERIAL);
+       input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_FINGER);
+       input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_0) | BIT(BTN_4);
+}
+
+void input_dev_g(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
+{
+       input_dev->evbit[0] |= BIT(EV_REL);
+       input_dev->relbit[0] |= BIT(REL_WHEEL);
+       input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
+       input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE) | BIT(BTN_STYLUS2);
+       input_set_abs_params(input_dev, ABS_DISTANCE, 0, wacom_wac->features->distance_max, 0, 0);
+}
+
+void input_dev_i3s(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
+{
+       input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_FINGER);
+       input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_0) | BIT(BTN_1) | BIT(BTN_2) | BIT(BTN_3);
+       input_set_abs_params(input_dev, ABS_RX, 0, 4096, 0, 0);
+}
+
+void input_dev_i3(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
+{
+       input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_4) | BIT(BTN_5) | BIT(BTN_6) | BIT(BTN_7);
+       input_set_abs_params(input_dev, ABS_RY, 0, 4096, 0, 0);
+}
+
+void input_dev_i(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
+{
+       input_dev->evbit[0] |= BIT(EV_MSC) | BIT(EV_REL);
+       input_dev->mscbit[0] |= BIT(MSC_SERIAL);
+       input_dev->relbit[0] |= BIT(REL_WHEEL);
+       input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE) | BIT(BTN_SIDE) | BIT(BTN_EXTRA);
+       input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE) | BIT(BTN_TOOL_BRUSH)
+               | BIT(BTN_TOOL_PENCIL) | BIT(BTN_TOOL_AIRBRUSH) | BIT(BTN_TOOL_LENS) | BIT(BTN_STYLUS2);
+       input_set_abs_params(input_dev, ABS_DISTANCE, 0, wacom_wac->features->distance_max, 0, 0);
+       input_set_abs_params(input_dev, ABS_WHEEL, 0, 1023, 0, 0);
+       input_set_abs_params(input_dev, ABS_TILT_X, 0, 127, 0, 0);
+       input_set_abs_params(input_dev, ABS_TILT_Y, 0, 127, 0, 0);
+       input_set_abs_params(input_dev, ABS_RZ, -900, 899, 0, 0);
+       input_set_abs_params(input_dev, ABS_THROTTLE, -1023, 1023, 0, 0);
+}
+
+void input_dev_pl(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
+{
+       input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_STYLUS2) | BIT(BTN_TOOL_RUBBER);
+}
+
+void input_dev_pt(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
+{
+       input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER);
+}
+
+static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+       struct usb_device *dev = interface_to_usbdev(intf);
+       struct usb_endpoint_descriptor *endpoint;
+       struct wacom *wacom;
+       struct wacom_wac *wacom_wac;
+       struct input_dev *input_dev;
+       int error = -ENOMEM;
+       char rep_data[2], limit = 0;
+
+       wacom = kzalloc(sizeof(struct wacom), GFP_KERNEL);
+       wacom_wac = kzalloc(sizeof(struct wacom_wac), GFP_KERNEL);
+       input_dev = input_allocate_device();
+       if (!wacom || !input_dev || !wacom_wac)
+               goto fail1;
+
+       wacom_wac->data = usb_buffer_alloc(dev, 10, GFP_KERNEL, &wacom->data_dma);
+       if (!wacom_wac->data)
+               goto fail1;
+
+       wacom->irq = usb_alloc_urb(0, GFP_KERNEL);
+       if (!wacom->irq)
+               goto fail2;
+
+       wacom->usbdev = dev;
+       wacom->dev = input_dev;
+       usb_make_path(dev, wacom->phys, sizeof(wacom->phys));
+       strlcat(wacom->phys, "/input0", sizeof(wacom->phys));
+
+       wacom_wac->features = get_wacom_feature(id);
+       BUG_ON(wacom_wac->features->pktlen > 10);
+
+       input_dev->name = wacom_wac->features->name;
+       wacom->wacom_wac = wacom_wac;
+       usb_to_input_id(dev, &input_dev->id);
+
+       input_dev->dev.parent = &intf->dev;
+
+       input_set_drvdata(input_dev, wacom);
+
+       input_dev->open = wacom_open;
+       input_dev->close = wacom_close;
+
+       input_dev->evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS);
+       input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PEN) | BIT(BTN_TOUCH) | BIT(BTN_STYLUS);
+       input_set_abs_params(input_dev, ABS_X, 0, wacom_wac->features->x_max, 4, 0);
+       input_set_abs_params(input_dev, ABS_Y, 0, wacom_wac->features->y_max, 4, 0);
+       input_set_abs_params(input_dev, ABS_PRESSURE, 0, wacom_wac->features->pressure_max, 0, 0);
+       input_dev->absbit[LONG(ABS_MISC)] |= BIT(ABS_MISC);
+
+       wacom_init_input_dev(input_dev, wacom_wac);
+
+       endpoint = &intf->cur_altsetting->endpoint[0].desc;
+
+       usb_fill_int_urb(wacom->irq, dev,
+                        usb_rcvintpipe(dev, endpoint->bEndpointAddress),
+                        wacom_wac->data, wacom_wac->features->pktlen,
+                        wacom_sys_irq, wacom, endpoint->bInterval);
+       wacom->irq->transfer_dma = wacom->data_dma;
+       wacom->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+       error = input_register_device(wacom->dev);
+       if (error)
+               goto fail3;
+
+       /* Ask the tablet to report tablet data. Repeat until it succeeds */
+       do {
+               rep_data[0] = 2;
+               rep_data[1] = 2;
+               usb_set_report(intf, 3, 2, rep_data, 2);
+               usb_get_report(intf, 3, 2, rep_data, 2);
+       } while (rep_data[1] != 2 && limit++ < 5);
+
+       usb_set_intfdata(intf, wacom);
+       return 0;
+
+ fail3:        usb_free_urb(wacom->irq);
+ fail2:        usb_buffer_free(dev, 10, wacom_wac->data, wacom->data_dma);
+ fail1:        input_free_device(input_dev);
+       kfree(wacom);
+       kfree(wacom_wac);
+       return error;
+}
+
+static void wacom_disconnect(struct usb_interface *intf)
+{
+       struct wacom *wacom = usb_get_intfdata (intf);
+
+       usb_set_intfdata(intf, NULL);
+       if (wacom) {
+               usb_kill_urb(wacom->irq);
+               input_unregister_device(wacom->dev);
+               usb_free_urb(wacom->irq);
+               usb_buffer_free(interface_to_usbdev(intf), 10, wacom->wacom_wac->data, wacom->data_dma);
+               kfree(wacom->wacom_wac);
+               kfree(wacom);
+       }
+}
+
+static struct usb_driver wacom_driver = {
+       .name =         "wacom",
+       .probe =        wacom_probe,
+       .disconnect =   wacom_disconnect,
+};
+
+static int __init wacom_init(void)
+{
+       int result;
+       wacom_driver.id_table = get_device_table();
+       result = usb_register(&wacom_driver);
+       if (result == 0)
+               info(DRIVER_VERSION ":" DRIVER_DESC);
+       return result;
+}
+
+static void __exit wacom_exit(void)
+{
+       usb_deregister(&wacom_driver);
+}
+
+module_init(wacom_init);
+module_exit(wacom_exit);
diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c
new file mode 100644 (file)
index 0000000..7661f03
--- /dev/null
@@ -0,0 +1,675 @@
+/*
+ * drivers/input/tablet/wacom_wac.c
+ *
+ *  USB Wacom Graphire and Wacom Intuos tablet support - Wacom specific code
+ *
+ */
+
+/*
+ * 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 "wacom.h"
+#include "wacom_wac.h"
+
+static int wacom_penpartner_irq(struct wacom_wac *wacom, void *wcombo)
+{
+       unsigned char *data = wacom->data;
+
+       switch (data[0]) {
+               case 1:
+                       if (data[5] & 0x80) {
+                               wacom->tool[0] = (data[5] & 0x20) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
+                               wacom->id[0] = (data[5] & 0x20) ? ERASER_DEVICE_ID : STYLUS_DEVICE_ID;
+                               wacom_report_key(wcombo, wacom->tool[0], 1);
+                               wacom_report_abs(wcombo, ABS_MISC, wacom->id[0]); /* report tool id */
+                               wacom_report_abs(wcombo, ABS_X, wacom_le16_to_cpu(&data[1]));
+                               wacom_report_abs(wcombo, ABS_Y, wacom_le16_to_cpu(&data[3]));
+                               wacom_report_abs(wcombo, ABS_PRESSURE, (signed char)data[6] + 127);
+                               wacom_report_key(wcombo, BTN_TOUCH, ((signed char)data[6] > -127));
+                               wacom_report_key(wcombo, BTN_STYLUS, (data[5] & 0x40));
+                       } else {
+                               wacom_report_key(wcombo, wacom->tool[0], 0);
+                               wacom_report_abs(wcombo, ABS_MISC, 0); /* report tool id */
+                               wacom_report_abs(wcombo, ABS_PRESSURE, -1);
+                               wacom_report_key(wcombo, BTN_TOUCH, 0);
+                       }
+                       break;
+               case 2:
+                       wacom_report_key(wcombo, BTN_TOOL_PEN, 1);
+                       wacom_report_abs(wcombo, ABS_MISC, STYLUS_DEVICE_ID); /* report tool id */
+                       wacom_report_abs(wcombo, ABS_X, wacom_le16_to_cpu(&data[1]));
+                       wacom_report_abs(wcombo, ABS_Y, wacom_le16_to_cpu(&data[3]));
+                       wacom_report_abs(wcombo, ABS_PRESSURE, (signed char)data[6] + 127);
+                       wacom_report_key(wcombo, BTN_TOUCH, ((signed char)data[6] > -80) && !(data[5] & 0x20));
+                       wacom_report_key(wcombo, BTN_STYLUS, (data[5] & 0x40));
+                       break;
+               default:
+                       printk(KERN_INFO "wacom_penpartner_irq: received unknown report #%d\n", data[0]);
+                       return 0;
+        }
+       return 1;
+}
+
+static int wacom_pl_irq(struct wacom_wac *wacom, void *wcombo)
+{
+       unsigned char *data = wacom->data;
+       int prox, id, pressure;
+
+       if (data[0] != 2) {
+               dbg("wacom_pl_irq: received unknown report #%d", data[0]);
+               return 0;
+       }
+
+       prox = data[1] & 0x40;
+
+       id = ERASER_DEVICE_ID;
+       if (prox) {
+
+               pressure = (signed char)((data[7] << 1) | ((data[4] >> 2) & 1));
+               if (wacom->features->pressure_max > 255)
+                       pressure = (pressure << 1) | ((data[4] >> 6) & 1);
+               pressure += (wacom->features->pressure_max + 1) / 2;
+
+               /*
+                * if going from out of proximity into proximity select between the eraser
+                * and the pen based on the state of the stylus2 button, choose eraser if
+                * pressed else choose pen. if not a proximity change from out to in, send
+                * an out of proximity for previous tool then a in for new tool.
+                */
+               if (!wacom->tool[0]) {
+                       /* Eraser bit set for DTF */
+                       if (data[1] & 0x10)
+                               wacom->tool[1] = BTN_TOOL_RUBBER;
+                       else
+                               /* Going into proximity select tool */
+                               wacom->tool[1] = (data[4] & 0x20) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
+               } else {
+                       /* was entered with stylus2 pressed */
+                       if (wacom->tool[1] == BTN_TOOL_RUBBER && !(data[4] & 0x20)) {
+                               /* report out proximity for previous tool */
+                               wacom_report_key(wcombo, wacom->tool[1], 0);
+                               wacom_input_sync(wcombo);
+                               wacom->tool[1] = BTN_TOOL_PEN;
+                               return 0;
+                       }
+               }
+               if (wacom->tool[1] != BTN_TOOL_RUBBER) {
+                       /* Unknown tool selected default to pen tool */
+                       wacom->tool[1] = BTN_TOOL_PEN;
+                       id = STYLUS_DEVICE_ID;
+               }
+               wacom_report_key(wcombo, wacom->tool[1], prox); /* report in proximity for tool */
+               wacom_report_abs(wcombo, ABS_MISC, id); /* report tool id */
+               wacom_report_abs(wcombo, ABS_X, data[3] | (data[2] << 7) | ((data[1] & 0x03) << 14));
+               wacom_report_abs(wcombo, ABS_Y, data[6] | (data[5] << 7) | ((data[4] & 0x03) << 14));
+               wacom_report_abs(wcombo, ABS_PRESSURE, pressure);
+
+               wacom_report_key(wcombo, BTN_TOUCH, data[4] & 0x08);
+               wacom_report_key(wcombo, BTN_STYLUS, data[4] & 0x10);
+               /* Only allow the stylus2 button to be reported for the pen tool. */
+               wacom_report_key(wcombo, BTN_STYLUS2, (wacom->tool[1] == BTN_TOOL_PEN) && (data[4] & 0x20));
+       } else {
+               /* report proximity-out of a (valid) tool */
+               if (wacom->tool[1] != BTN_TOOL_RUBBER) {
+                       /* Unknown tool selected default to pen tool */
+                       wacom->tool[1] = BTN_TOOL_PEN;
+               }
+               wacom_report_key(wcombo, wacom->tool[1], prox);
+       }
+
+       wacom->tool[0] = prox; /* Save proximity state */
+       return 1;
+}
+
+static int wacom_ptu_irq(struct wacom_wac *wacom, void *wcombo)
+{
+       unsigned char *data = wacom->data;
+       int id;
+
+       if (data[0] != 2) {
+               printk(KERN_INFO "wacom_ptu_irq: received unknown report #%d\n", data[0]);
+               return 0;
+       }
+
+       if (data[1] & 0x04) {
+               wacom_report_key(wcombo, BTN_TOOL_RUBBER, data[1] & 0x20);
+               wacom_report_key(wcombo, BTN_TOUCH, data[1] & 0x08);
+               id = ERASER_DEVICE_ID;
+       } else {
+               wacom_report_key(wcombo, BTN_TOOL_PEN, data[1] & 0x20);
+               wacom_report_key(wcombo, BTN_TOUCH, data[1] & 0x01);
+               id = STYLUS_DEVICE_ID;
+       }
+       wacom_report_abs(wcombo, ABS_MISC, id); /* report tool id */
+       wacom_report_abs(wcombo, ABS_X, wacom_le16_to_cpu(&data[2]));
+       wacom_report_abs(wcombo, ABS_Y, wacom_le16_to_cpu(&data[4]));
+       wacom_report_abs(wcombo, ABS_PRESSURE, wacom_le16_to_cpu(&data[6]));
+       wacom_report_key(wcombo, BTN_STYLUS, data[1] & 0x02);
+       wacom_report_key(wcombo, BTN_STYLUS2, data[1] & 0x10);
+       return 1;
+}
+
+static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo)
+{
+       unsigned char *data = wacom->data;
+       int x, y, id, rw;
+
+       if (data[0] != 2) {
+               dbg("wacom_graphire_irq: received unknown report #%d", data[0]);
+               return 0;
+       }
+
+       id = STYLUS_DEVICE_ID;
+       if (data[1] & 0x80) { /* in prox */
+
+               switch ((data[1] >> 5) & 3) {
+
+                       case 0: /* Pen */
+                               wacom->tool[0] = BTN_TOOL_PEN;
+                               break;
+
+                       case 1: /* Rubber */
+                               wacom->tool[0] = BTN_TOOL_RUBBER;
+                               id = ERASER_DEVICE_ID;
+                               break;
+
+                       case 2: /* Mouse with wheel */
+                               wacom_report_key(wcombo, BTN_MIDDLE, data[1] & 0x04);
+                               if (wacom->features->type == WACOM_G4) {
+                                       rw = data[7] & 0x04 ? (data[7] & 0x03)-4 : (data[7] & 0x03);
+                                       wacom_report_rel(wcombo, REL_WHEEL, -rw);
+                               } else
+                                       wacom_report_rel(wcombo, REL_WHEEL, -(signed char) data[6]);
+                               /* fall through */
+
+                       case 3: /* Mouse without wheel */
+                               wacom->tool[0] = BTN_TOOL_MOUSE;
+                               id = CURSOR_DEVICE_ID;
+                               wacom_report_key(wcombo, BTN_LEFT, data[1] & 0x01);
+                               wacom_report_key(wcombo, BTN_RIGHT, data[1] & 0x02);
+                               if (wacom->features->type == WACOM_G4)
+                                       wacom_report_abs(wcombo, ABS_DISTANCE, data[6] & 0x3f);
+                               else
+                                       wacom_report_abs(wcombo, ABS_DISTANCE, data[7] & 0x3f);
+                               break;
+               }
+               x = wacom_le16_to_cpu(&data[2]);
+               y = wacom_le16_to_cpu(&data[4]);
+               wacom_report_abs(wcombo, ABS_X, x);
+               wacom_report_abs(wcombo, ABS_Y, y);
+               if (wacom->tool[0] != BTN_TOOL_MOUSE) {
+                       wacom_report_abs(wcombo, ABS_PRESSURE, data[6] | ((data[7] & 0x01) << 8));
+                       wacom_report_key(wcombo, BTN_TOUCH, data[1] & 0x01);
+                       wacom_report_key(wcombo, BTN_STYLUS, data[1] & 0x02);
+                       wacom_report_key(wcombo, BTN_STYLUS2, data[1] & 0x04);
+               }
+               wacom_report_abs(wcombo, ABS_MISC, id); /* report tool id */
+               wacom_report_key(wcombo, wacom->tool[0], 1);
+       } else if (!(data[1] & 0x90)) {
+               wacom_report_abs(wcombo, ABS_X, 0);
+               wacom_report_abs(wcombo, ABS_Y, 0);
+               if (wacom->tool[0] == BTN_TOOL_MOUSE) {
+                       wacom_report_key(wcombo, BTN_LEFT, 0);
+                       wacom_report_key(wcombo, BTN_RIGHT, 0);
+                       wacom_report_abs(wcombo, ABS_DISTANCE, 0);
+               } else {
+                       wacom_report_abs(wcombo, ABS_PRESSURE, 0);
+                       wacom_report_key(wcombo, BTN_TOUCH, 0);
+                       wacom_report_key(wcombo, BTN_STYLUS, 0);
+                       wacom_report_key(wcombo, BTN_STYLUS2, 0);
+               }
+               wacom_report_abs(wcombo, ABS_MISC, 0); /* reset tool id */
+               wacom_report_key(wcombo, wacom->tool[0], 0);
+       }
+
+       /* send pad data */
+       if (wacom->features->type == WACOM_G4) {
+               if (data[7] & 0xf8) {
+                       wacom_input_sync(wcombo); /* sync last event */
+                       wacom->id[1] = 1;
+                       wacom->serial[1] = (data[7] & 0xf8);
+                       wacom_report_key(wcombo, BTN_0, (data[7] & 0x40));
+                       wacom_report_key(wcombo, BTN_4, (data[7] & 0x80));
+                       rw = ((data[7] & 0x18) >> 3) - ((data[7] & 0x20) >> 3);
+                       wacom_report_rel(wcombo, REL_WHEEL, rw);
+                       wacom_report_key(wcombo, BTN_TOOL_FINGER, 0xf0);
+                       wacom_report_abs(wcombo, ABS_MISC, PAD_DEVICE_ID);
+                       wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xf0);
+               } else if (wacom->id[1]) {
+                       wacom_input_sync(wcombo); /* sync last event */
+                       wacom->id[1] = 0;
+                       wacom_report_key(wcombo, BTN_0, (data[7] & 0x40));
+                       wacom_report_key(wcombo, BTN_4, (data[7] & 0x80));
+                       wacom_report_key(wcombo, BTN_TOOL_FINGER, 0);
+                       wacom_report_abs(wcombo, ABS_MISC, 0);
+                       wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xf0);
+               }
+       }
+       return 1;
+}
+
+static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo)
+{
+       unsigned char *data = wacom->data;
+       int idx;
+
+       /* tool number */
+       idx = data[1] & 0x01;
+
+       /* Enter report */
+       if ((data[1] & 0xfc) == 0xc0) {
+               /* serial number of the tool */
+               wacom->serial[idx] = ((data[3] & 0x0f) << 28) +
+                       (data[4] << 20) + (data[5] << 12) +
+                       (data[6] << 4) + (data[7] >> 4);
+
+               wacom->id[idx] = (data[2] << 4) | (data[3] >> 4);
+               switch (wacom->id[idx]) {
+                       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 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:
+                       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:
+                       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:
+                       case 0x913: /* Intuos3 Airbrush */
+                               wacom->tool[idx] = BTN_TOOL_AIRBRUSH;
+                               break;
+                       default: /* Unknown tool */
+                               wacom->tool[idx] = BTN_TOOL_PEN;
+               }
+               return 1;
+       }
+
+       /* Exit report */
+       if ((data[1] & 0xfe) == 0x80) {
+               wacom_report_abs(wcombo, ABS_X, 0);
+               wacom_report_abs(wcombo, ABS_Y, 0);
+               wacom_report_abs(wcombo, ABS_DISTANCE, 0);
+               if (wacom->tool[idx] >= BTN_TOOL_MOUSE) {
+                       wacom_report_key(wcombo, BTN_LEFT, 0);
+                       wacom_report_key(wcombo, BTN_MIDDLE, 0);
+                       wacom_report_key(wcombo, BTN_RIGHT, 0);
+                       wacom_report_key(wcombo, BTN_SIDE, 0);
+                       wacom_report_key(wcombo, BTN_EXTRA, 0);
+                       wacom_report_abs(wcombo, ABS_THROTTLE, 0);
+                       wacom_report_abs(wcombo, ABS_RZ, 0);
+               } else {
+                       wacom_report_abs(wcombo, ABS_PRESSURE, 0);
+                       wacom_report_abs(wcombo, ABS_TILT_X, 0);
+                       wacom_report_abs(wcombo, ABS_TILT_Y, 0);
+                       wacom_report_key(wcombo, BTN_STYLUS, 0);
+                       wacom_report_key(wcombo, BTN_STYLUS2, 0);
+                       wacom_report_key(wcombo, BTN_TOUCH, 0);
+                       wacom_report_abs(wcombo, ABS_WHEEL, 0);
+               }
+               wacom_report_key(wcombo, wacom->tool[idx], 0);
+               wacom_report_abs(wcombo, ABS_MISC, 0); /* reset tool id */
+               wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
+               return 2;
+       }
+       return 0;
+}
+
+static void wacom_intuos_general(struct wacom_wac *wacom, void *wcombo)
+{
+       unsigned char *data = wacom->data;
+       unsigned int t;
+
+       /* general pen packet */
+       if ((data[1] & 0xb8) == 0xa0) {
+               t = (data[6] << 2) | ((data[7] >> 6) & 3);
+               wacom_report_abs(wcombo, ABS_PRESSURE, t);
+               wacom_report_abs(wcombo, ABS_TILT_X,
+                               ((data[7] << 1) & 0x7e) | (data[8] >> 7));
+               wacom_report_abs(wcombo, ABS_TILT_Y, data[8] & 0x7f);
+               wacom_report_key(wcombo, BTN_STYLUS, data[1] & 2);
+               wacom_report_key(wcombo, BTN_STYLUS2, data[1] & 4);
+               wacom_report_key(wcombo, BTN_TOUCH, t > 10);
+       }
+
+       /* airbrush second packet */
+       if ((data[1] & 0xbc) == 0xb4) {
+               wacom_report_abs(wcombo, ABS_WHEEL,
+                               (data[6] << 2) | ((data[7] >> 6) & 3));
+               wacom_report_abs(wcombo, ABS_TILT_X,
+                               ((data[7] << 1) & 0x7e) | (data[8] >> 7));
+               wacom_report_abs(wcombo, ABS_TILT_Y, data[8] & 0x7f);
+       }
+       return;
+}
+
+static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
+{
+       unsigned char *data = wacom->data;
+       unsigned int t;
+       int idx, result;
+
+       if (data[0] != 2 && data[0] != 5 && data[0] != 6 && data[0] != 12) {
+               dbg("wacom_intuos_irq: received unknown report #%d", data[0]);
+                return 0;
+       }
+
+       /* tool number */
+       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;
+
+               wacom_report_key(wcombo, BTN_0, (data[5] & 0x01));
+               wacom_report_key(wcombo, BTN_1, (data[5] & 0x02));
+               wacom_report_key(wcombo, BTN_2, (data[5] & 0x04));
+               wacom_report_key(wcombo, BTN_3, (data[5] & 0x08));
+               wacom_report_key(wcombo, BTN_4, (data[6] & 0x01));
+               wacom_report_key(wcombo, BTN_5, (data[6] & 0x02));
+               wacom_report_key(wcombo, BTN_6, (data[6] & 0x04));
+               wacom_report_key(wcombo, BTN_7, (data[6] & 0x08));
+               wacom_report_abs(wcombo, ABS_RX, ((data[1] & 0x1f) << 8) | data[2]);
+               wacom_report_abs(wcombo, ABS_RY, ((data[3] & 0x1f) << 8) | data[4]);
+
+               if((data[5] & 0x0f) | (data[6] & 0x0f) | (data[1] & 0x1f) |
+                       data[2] | (data[3] & 0x1f) | data[4])
+                       wacom_report_key(wcombo, wacom->tool[1], 1);
+               else
+                       wacom_report_key(wcombo, wacom->tool[1], 0);
+               wacom_report_abs(wcombo, ABS_MISC, PAD_DEVICE_ID);
+               wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xffffffff);
+                return 1;
+       }
+
+       /* process in/out prox events */
+       result = wacom_intuos_inout(wacom, wcombo);
+       if (result)
+                return result-1;
+
+       /* Only large I3 and I1 & I2 support Lense Cursor */
+       if((wacom->tool[idx] == BTN_TOOL_LENS)
+                       && ((wacom->features->type == INTUOS3)
+                       || (wacom->features->type == INTUOS3S)))
+               return 0;
+
+       /* Cintiq doesn't send data when RDY bit isn't set */
+       if ((wacom->features->type == CINTIQ) && !(data[1] & 0x40))
+                 return 0;
+
+       if (wacom->features->type >= INTUOS3S) {
+               wacom_report_abs(wcombo, ABS_X, (data[2] << 9) | (data[3] << 1) | ((data[9] >> 1) & 1));
+               wacom_report_abs(wcombo, ABS_Y, (data[4] << 9) | (data[5] << 1) | (data[9] & 1));
+               wacom_report_abs(wcombo, ABS_DISTANCE, ((data[9] >> 2) & 0x3f));
+       } else {
+               wacom_report_abs(wcombo, ABS_X, wacom_be16_to_cpu(&data[2]));
+               wacom_report_abs(wcombo, ABS_Y, wacom_be16_to_cpu(&data[4]));
+               wacom_report_abs(wcombo, ABS_DISTANCE, ((data[9] >> 3) & 0x1f));
+       }
+
+       /* process general packets */
+       wacom_intuos_general(wacom, wcombo);
+
+       /* 4D mouse, 2D mouse, marker pen rotation, or Lens cursor packets */
+       if ((data[1] & 0xbc) == 0xa8 || (data[1] & 0xbe) == 0xb0) {
+
+               if (data[1] & 0x02) {
+                       /* Rotation packet */
+                       if (wacom->features->type >= INTUOS3S) {
+                               /* I3 marker pen rotation reported as wheel
+                                * due to valuator limitation
+                                */
+                               t = (data[6] << 3) | ((data[7] >> 5) & 7);
+                               t = (data[7] & 0x20) ? ((t > 900) ? ((t-1) / 2 - 1350) :
+                                       ((t-1) / 2 + 450)) : (450 - t / 2) ;
+                               wacom_report_abs(wcombo, ABS_WHEEL, t);
+                       } else {
+                               /* 4D mouse rotation packet */
+                               t = (data[6] << 3) | ((data[7] >> 5) & 7);
+                               wacom_report_abs(wcombo, ABS_RZ, (data[7] & 0x20) ?
+                                       ((t - 1) / 2) : -t / 2);
+                       }
+
+               } else if (!(data[1] & 0x10) && wacom->features->type < INTUOS3S) {
+                       /* 4D mouse packet */
+                       wacom_report_key(wcombo, BTN_LEFT,   data[8] & 0x01);
+                       wacom_report_key(wcombo, BTN_MIDDLE, data[8] & 0x02);
+                       wacom_report_key(wcombo, BTN_RIGHT,  data[8] & 0x04);
+
+                       wacom_report_key(wcombo, BTN_SIDE,   data[8] & 0x20);
+                       wacom_report_key(wcombo, BTN_EXTRA,  data[8] & 0x10);
+                       t = (data[6] << 2) | ((data[7] >> 6) & 3);
+                       wacom_report_abs(wcombo, ABS_THROTTLE, (data[8] & 0x08) ? -t : t);
+
+               } else if (wacom->tool[idx] == BTN_TOOL_MOUSE) {
+                       /* 2D mouse packet */
+                       wacom_report_key(wcombo, BTN_LEFT,   data[8] & 0x04);
+                       wacom_report_key(wcombo, BTN_MIDDLE, data[8] & 0x08);
+                       wacom_report_key(wcombo, BTN_RIGHT,  data[8] & 0x10);
+                       wacom_report_rel(wcombo, REL_WHEEL, (data[8] & 0x01)
+                                                - ((data[8] & 0x02) >> 1));
+
+                       /* I3 2D mouse side buttons */
+                       if (wacom->features->type >= INTUOS3S && wacom->features->type <= INTUOS3L) {
+                               wacom_report_key(wcombo, BTN_SIDE,   data[8] & 0x40);
+                               wacom_report_key(wcombo, BTN_EXTRA,  data[8] & 0x20);
+                       }
+
+               } else if (wacom->features->type < INTUOS3S || wacom->features->type == INTUOS3L) {
+                       /* Lens cursor packets */
+                       wacom_report_key(wcombo, BTN_LEFT,   data[8] & 0x01);
+                       wacom_report_key(wcombo, BTN_MIDDLE, data[8] & 0x02);
+                       wacom_report_key(wcombo, BTN_RIGHT,  data[8] & 0x04);
+                       wacom_report_key(wcombo, BTN_SIDE,   data[8] & 0x10);
+                       wacom_report_key(wcombo, BTN_EXTRA,  data[8] & 0x08);
+               }
+       }
+
+       wacom_report_abs(wcombo, ABS_MISC, wacom->id[idx]); /* report tool id */
+       wacom_report_key(wcombo, wacom->tool[idx], 1);
+       wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
+       return 1;
+}
+
+int wacom_wac_irq(struct wacom_wac *wacom_wac, void *wcombo)
+{
+       switch (wacom_wac->features->type) {
+               case PENPARTNER:
+                       return (wacom_penpartner_irq(wacom_wac, wcombo));
+                       break;
+               case PL:
+                       return (wacom_pl_irq(wacom_wac, wcombo));
+                       break;
+               case WACOM_G4:
+               case GRAPHIRE:
+                       return (wacom_graphire_irq(wacom_wac, wcombo));
+                       break;
+               case PTU:
+                       return (wacom_ptu_irq(wacom_wac, wcombo));
+                       break;
+               case INTUOS:
+               case INTUOS3S:
+               case INTUOS3:
+               case INTUOS3L:
+               case CINTIQ:
+                       return (wacom_intuos_irq(wacom_wac, wcombo));
+                       break;
+               default:
+                       return 0;
+       }
+       return 0;
+}
+
+void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
+{
+       switch (wacom_wac->features->type) {
+               case WACOM_G4:
+                       input_dev_g4(input_dev, wacom_wac);
+                       /* fall through */
+               case GRAPHIRE:
+                       input_dev_g(input_dev, wacom_wac);
+                       break;
+               case INTUOS3:
+               case INTUOS3L:
+               case CINTIQ:
+                       input_dev_i3(input_dev, wacom_wac);
+                       /* fall through */
+               case INTUOS3S:
+                       input_dev_i3s(input_dev, wacom_wac);
+               case INTUOS:
+                       input_dev_i(input_dev, wacom_wac);
+                       break;
+               case PL:
+               case PTU:
+                       input_dev_pl(input_dev, wacom_wac);
+                       break;
+               case PENPARTNER:
+                       input_dev_pt(input_dev, wacom_wac);
+                       break;
+       }
+       return;
+}
+
+static struct wacom_features wacom_features[] = {
+       { "Wacom Penpartner",    7,   5040,  3780,  255,  0, PENPARTNER },
+        { "Wacom Graphire",      8,  10206,  7422,  511, 63, GRAPHIRE },
+       { "Wacom Graphire2 4x5", 8,  10206,  7422,  511, 63, GRAPHIRE },
+       { "Wacom Graphire2 5x7", 8,  13918, 10206,  511, 63, GRAPHIRE },
+       { "Wacom Graphire3",     8,  10208,  7424,  511, 63, GRAPHIRE },
+       { "Wacom Graphire3 6x8", 8,  16704, 12064,  511, 63, GRAPHIRE },
+       { "Wacom Graphire4 4x5", 8,  10208,  7424,  511, 63, WACOM_G4 },
+       { "Wacom Graphire4 6x8", 8,  16704, 12064,  511, 63, WACOM_G4 },
+       { "Wacom Volito",        8,   5104,  3712,  511, 63, GRAPHIRE },
+       { "Wacom PenStation2",   8,   3250,  2320,  255, 63, GRAPHIRE },
+       { "Wacom Volito2 4x5",   8,   5104,  3712,  511, 63, GRAPHIRE },
+       { "Wacom Volito2 2x3",   8,   3248,  2320,  511, 63, GRAPHIRE },
+       { "Wacom PenPartner2",   8,   3250,  2320,  255, 63, GRAPHIRE },
+       { "Wacom Intuos 4x5",   10,  12700, 10600, 1023, 31, INTUOS },
+       { "Wacom Intuos 6x8",   10,  20320, 16240, 1023, 31, INTUOS },
+       { "Wacom Intuos 9x12",  10,  30480, 24060, 1023, 31, INTUOS },
+       { "Wacom Intuos 12x12", 10,  30480, 31680, 1023, 31, INTUOS },
+       { "Wacom Intuos 12x18", 10,  45720, 31680, 1023, 31, INTUOS },
+       { "Wacom PL400",         8,   5408,  4056,  255,  0, PL },
+       { "Wacom PL500",         8,   6144,  4608,  255,  0, PL },
+       { "Wacom PL600",         8,   6126,  4604,  255,  0, PL },
+       { "Wacom PL600SX",       8,   6260,  5016,  255,  0, PL },
+       { "Wacom PL550",         8,   6144,  4608,  511,  0, PL },
+       { "Wacom PL800",         8,   7220,  5780,  511,  0, PL },
+       { "Wacom PL700",         8,   6758,  5406,  511,  0, PL },
+       { "Wacom PL510",         8,   6282,  4762,  511,  0, PL },
+       { "Wacom DTU710",        8,  34080, 27660,  511,  0, PL },
+       { "Wacom DTF521",        8,   6282,  4762,  511,  0, PL },
+       { "Wacom DTF720",        8,   6858,  5506,  511,  0, PL },
+       { "Wacom Cintiq Partner",8,  20480, 15360,  511,  0, PTU },
+       { "Wacom Intuos2 4x5",   10, 12700, 10600, 1023, 31, INTUOS },
+       { "Wacom Intuos2 6x8",   10, 20320, 16240, 1023, 31, INTUOS },
+       { "Wacom Intuos2 9x12",  10, 30480, 24060, 1023, 31, INTUOS },
+       { "Wacom Intuos2 12x12", 10, 30480, 31680, 1023, 31, INTUOS },
+       { "Wacom Intuos2 12x18", 10, 45720, 31680, 1023, 31, INTUOS },
+       { "Wacom Intuos3 4x5",   10, 25400, 20320, 1023, 63, INTUOS3S },
+       { "Wacom Intuos3 6x8",   10, 40640, 30480, 1023, 63, INTUOS3 },
+       { "Wacom Intuos3 9x12",  10, 60960, 45720, 1023, 63, INTUOS3 },
+       { "Wacom Intuos3 12x12", 10, 60960, 60960, 1023, 63, INTUOS3L },
+       { "Wacom Intuos3 12x19", 10, 97536, 60960, 1023, 63, INTUOS3L },
+       { "Wacom Intuos3 6x11",  10, 54204, 31750, 1023, 63, INTUOS3 },
+       { "Wacom Intuos3 4x6",   10, 31496, 19685, 1023, 63, INTUOS3S },
+       { "Wacom Cintiq 21UX",   10, 87200, 65600, 1023, 63, CINTIQ },
+       { "Wacom Intuos2 6x8",   10, 20320, 16240, 1023, 31, INTUOS },
+       { }
+};
+
+static struct usb_device_id wacom_ids[] = {
+       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x00) },
+       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x10) },
+       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x11) },
+       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x12) },
+       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x13) },
+       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x14) },
+       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x15) },
+       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x16) },
+       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x60) },
+       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x61) },
+       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x62) },
+       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x63) },
+       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x64) },
+       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x20) },
+       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x21) },
+       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x22) },
+       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x23) },
+       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x24) },
+       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x30) },
+       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x31) },
+       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x32) },
+       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x33) },
+       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x34) },
+       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x35) },
+       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x37) },
+       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x38) },
+       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x39) },
+       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC0) },
+       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC4) },
+       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x03) },
+       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x41) },
+       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x42) },
+       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x43) },
+       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x44) },
+       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x45) },
+       { 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, 0xB3) },
+       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB4) },
+       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB5) },
+       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB7) },
+       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x3F) },
+       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x47) },
+       { }
+};
+
+const struct usb_device_id * get_device_table(void) {
+        const struct usb_device_id * id_table = wacom_ids;
+        return id_table;
+}
+
+struct wacom_features * get_wacom_feature(const struct usb_device_id * id) {
+        int index = id - wacom_ids;
+        struct wacom_features *wf = &wacom_features[index];
+        return wf;
+}
+
+MODULE_DEVICE_TABLE(usb, wacom_ids);
diff --git a/drivers/input/tablet/wacom_wac.h b/drivers/input/tablet/wacom_wac.h
new file mode 100644 (file)
index 0000000..a5e12e8
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * drivers/input/tablet/wacom_wac.h
+ *
+ * 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.
+ */
+#ifndef WACOM_WAC_H
+#define WACOM_WAC_H
+
+#define STYLUS_DEVICE_ID       0x02
+#define CURSOR_DEVICE_ID       0x06
+#define ERASER_DEVICE_ID       0x0A
+#define PAD_DEVICE_ID          0x0F
+
+enum {
+       PENPARTNER = 0,
+       GRAPHIRE,
+       WACOM_G4,
+       PTU,
+       PL,
+       INTUOS,
+       INTUOS3S,
+       INTUOS3,
+       INTUOS3L,
+       CINTIQ,
+       MAX_TYPE
+};
+
+struct wacom_features {
+       char *name;
+       int pktlen;
+       int x_max;
+       int y_max;
+       int pressure_max;
+       int distance_max;
+       int type;
+};
+
+struct wacom_wac {
+       unsigned char *data;
+        int tool[2];
+        int id[2];
+        __u32 serial[2];
+       struct wacom_features *features;
+};
+
+#endif
index f5de58a63f2bfdac82319fad26e6d616a77c441a..f7865669de3590b484fa95b188c51626cb23a972 100644 (file)
@@ -23,13 +23,9 @@ obj-$(CONFIG_USB_PRINTER)    += class/
 obj-$(CONFIG_USB_STORAGE)      += storage/
 obj-$(CONFIG_USB)              += storage/
 
-obj-$(CONFIG_USB_ACECAD)       += input/
-obj-$(CONFIG_USB_AIPTEK)       += input/
 obj-$(CONFIG_USB_ATI_REMOTE)   += input/
-obj-$(CONFIG_USB_KBTAB)                += input/
 obj-$(CONFIG_USB_MTOUCH)       += input/
 obj-$(CONFIG_USB_POWERMATE)    += input/
-obj-$(CONFIG_USB_WACOM)                += input/
 obj-$(CONFIG_USB_XPAD)         += input/
 
 obj-$(CONFIG_USB_CATC)         += net/
index a792e42f58afbe4baf53c34c56f59f79fd97ea48..86cad900c65969274be417729f4fbbf39c4e91dd 100644 (file)
@@ -4,54 +4,6 @@
 comment "USB Input Devices"
        depends on USB
 
-config USB_AIPTEK
-       tristate "Aiptek 6000U/8000U tablet support"
-       depends on USB && INPUT
-       help
-         Say Y here if you want to use the USB version of the Aiptek 6000U
-         or Aiptek 8000U tablet.  Make sure to say Y to "Mouse support"
-         (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support"
-         (CONFIG_INPUT_EVDEV) as well.
-
-         To compile this driver as a module, choose M here: the
-         module will be called aiptek.
-
-config USB_WACOM
-       tristate "Wacom Intuos/Graphire tablet support"
-       depends on USB && INPUT
-       help
-         Say Y here if you want to use the USB version of the Wacom Intuos
-         or Graphire tablet.  Make sure to say Y to "Mouse support"
-         (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support"
-         (CONFIG_INPUT_EVDEV) as well.
-
-         To compile this driver as a module, choose M here: the
-         module will be called wacom.
-
-config USB_ACECAD
-       tristate "Acecad Flair tablet support"
-       depends on USB && INPUT
-       help
-         Say Y here if you want to use the USB version of the Acecad Flair
-         tablet.  Make sure to say Y to "Mouse support"
-         (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support"
-         (CONFIG_INPUT_EVDEV) as well.
-
-         To compile this driver as a module, choose M here: the
-         module will be called acecad.
-
-config USB_KBTAB
-       tristate "KB Gear JamStudio tablet support"
-       depends on USB && INPUT
-       help
-         Say Y here if you want to use the USB version of the KB Gear
-         JamStudio tablet.  Make sure to say Y to "Mouse support"
-         (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support"
-         (CONFIG_INPUT_EVDEV) as well.
-
-         To compile this driver as a module, choose M here: the
-         module will be called kbtab.
-
 config USB_POWERMATE
        tristate "Griffin PowerMate and Contour Jog support"
        depends on USB && INPUT
@@ -211,15 +163,3 @@ config USB_APPLETOUCH
 
          To compile this driver as a module, choose M here: the
          module will be called appletouch.
-
-config USB_GTCO
-        tristate "GTCO CalComp/InterWrite USB Support"
-        depends on USB && INPUT
-        ---help---
-          Say Y here if you want to use the USB version of the GTCO
-          CalComp/InterWrite Tablet.  Make sure to say Y to "Mouse support"
-          (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support"
-          (CONFIG_INPUT_EVDEV) as well.
-
-          To compile this driver as a module, choose M here: the
-          module will be called gtco.
index 284a0734e0cd6180f6237dc6b2a59bd74ccdc77c..a9e9b2fc5e724dff14bb85614548ce9b42780c2b 100644 (file)
@@ -2,22 +2,14 @@
 # Makefile for the USB input drivers
 #
 
-# Multipart objects.
-wacom-objs     := wacom_wac.o wacom_sys.o
-
-obj-$(CONFIG_USB_AIPTEK)       += aiptek.o
 obj-$(CONFIG_USB_ATI_REMOTE)   += ati_remote.o
 obj-$(CONFIG_USB_ATI_REMOTE2)  += ati_remote2.o
-obj-$(CONFIG_USB_KBTAB)                += kbtab.o
 obj-$(CONFIG_USB_KEYSPAN_REMOTE)       += keyspan_remote.o
 obj-$(CONFIG_USB_TOUCHSCREEN)  += usbtouchscreen.o
 obj-$(CONFIG_USB_POWERMATE)    += powermate.o
-obj-$(CONFIG_USB_WACOM)                += wacom.o
-obj-$(CONFIG_USB_ACECAD)       += acecad.o
 obj-$(CONFIG_USB_YEALINK)      += yealink.o
 obj-$(CONFIG_USB_XPAD)         += xpad.o
 obj-$(CONFIG_USB_APPLETOUCH)   += appletouch.o
-obj-$(CONFIG_USB_GTCO)         += gtco.o
 
 ifeq ($(CONFIG_USB_DEBUG),y)
 EXTRA_CFLAGS += -DDEBUG
diff --git a/drivers/usb/input/acecad.c b/drivers/usb/input/acecad.c
deleted file mode 100644 (file)
index dd23104..0000000
+++ /dev/null
@@ -1,289 +0,0 @@
-/*
- *  Copyright (c) 2001-2005 Edouard TISSERANT   <edouard.tisserant@wanadoo.fr>
- *  Copyright (c) 2004-2005 Stephane VOLTZ      <svoltz@numericable.fr>
- *
- *  USB Acecad "Acecad Flair" tablet support
- *
- *  Changelog:
- *      v3.2 - Added sysfs support
- */
-
-/*
- * 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.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/usb/input.h>
-
-/*
- * Version Information
- */
-#define DRIVER_VERSION "v3.2"
-#define DRIVER_DESC    "USB Acecad Flair tablet driver"
-#define DRIVER_LICENSE "GPL"
-#define DRIVER_AUTHOR  "Edouard TISSERANT <edouard.tisserant@wanadoo.fr>"
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE(DRIVER_LICENSE);
-
-#define USB_VENDOR_ID_ACECAD   0x0460
-#define USB_DEVICE_ID_FLAIR    0x0004
-#define USB_DEVICE_ID_302      0x0008
-
-struct usb_acecad {
-       char name[128];
-       char phys[64];
-       struct usb_device *usbdev;
-       struct input_dev *input;
-       struct urb *irq;
-
-       unsigned char *data;
-       dma_addr_t data_dma;
-};
-
-static void usb_acecad_irq(struct urb *urb)
-{
-       struct usb_acecad *acecad = urb->context;
-       unsigned char *data = acecad->data;
-       struct input_dev *dev = acecad->input;
-       int prox, status;
-
-       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 resubmit;
-       }
-
-       prox = (data[0] & 0x04) >> 2;
-       input_report_key(dev, BTN_TOOL_PEN, prox);
-
-       if (prox) {
-               int x = data[1] | (data[2] << 8);
-               int y = data[3] | (data[4] << 8);
-               /* Pressure should compute the same way for flair and 302 */
-               int pressure = data[5] | (data[6] << 8);
-               int touch = data[0] & 0x01;
-               int stylus = (data[0] & 0x10) >> 4;
-               int stylus2 = (data[0] & 0x20) >> 5;
-               input_report_abs(dev, ABS_X, x);
-               input_report_abs(dev, ABS_Y, y);
-               input_report_abs(dev, ABS_PRESSURE, pressure);
-               input_report_key(dev, BTN_TOUCH, touch);
-               input_report_key(dev, BTN_STYLUS, stylus);
-               input_report_key(dev, BTN_STYLUS2, stylus2);
-       }
-
-       /* event termination */
-       input_sync(dev);
-
-resubmit:
-       status = usb_submit_urb(urb, GFP_ATOMIC);
-       if (status)
-               err("can't resubmit intr, %s-%s/input0, status %d",
-                       acecad->usbdev->bus->bus_name, acecad->usbdev->devpath, status);
-}
-
-static int usb_acecad_open(struct input_dev *dev)
-{
-       struct usb_acecad *acecad = input_get_drvdata(dev);
-
-       acecad->irq->dev = acecad->usbdev;
-       if (usb_submit_urb(acecad->irq, GFP_KERNEL))
-               return -EIO;
-
-       return 0;
-}
-
-static void usb_acecad_close(struct input_dev *dev)
-{
-       struct usb_acecad *acecad = input_get_drvdata(dev);
-
-       usb_kill_urb(acecad->irq);
-}
-
-static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_id *id)
-{
-       struct usb_device *dev = interface_to_usbdev(intf);
-       struct usb_host_interface *interface = intf->cur_altsetting;
-       struct usb_endpoint_descriptor *endpoint;
-       struct usb_acecad *acecad;
-       struct input_dev *input_dev;
-       int pipe, maxp;
-       int err = -ENOMEM;
-
-       if (interface->desc.bNumEndpoints != 1)
-               return -ENODEV;
-
-       endpoint = &interface->endpoint[0].desc;
-
-       if (!usb_endpoint_is_int_in(endpoint))
-               return -ENODEV;
-
-       pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
-       maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
-
-       acecad = kzalloc(sizeof(struct usb_acecad), GFP_KERNEL);
-       input_dev = input_allocate_device();
-       if (!acecad || !input_dev) {
-               err = -ENOMEM;
-               goto fail1;
-       }
-
-       acecad->data = usb_buffer_alloc(dev, 8, GFP_KERNEL, &acecad->data_dma);
-       if (!acecad->data) {
-               err= -ENOMEM;
-               goto fail1;
-       }
-
-       acecad->irq = usb_alloc_urb(0, GFP_KERNEL);
-       if (!acecad->irq) {
-               err = -ENOMEM;
-               goto fail2;
-       }
-
-       acecad->usbdev = dev;
-       acecad->input = input_dev;
-
-       if (dev->manufacturer)
-               strlcpy(acecad->name, dev->manufacturer, sizeof(acecad->name));
-
-       if (dev->product) {
-               if (dev->manufacturer)
-                       strlcat(acecad->name, " ", sizeof(acecad->name));
-               strlcat(acecad->name, dev->product, sizeof(acecad->name));
-       }
-
-       usb_make_path(dev, acecad->phys, sizeof(acecad->phys));
-       strlcat(acecad->phys, "/input0", sizeof(acecad->phys));
-
-       input_dev->name = acecad->name;
-       input_dev->phys = acecad->phys;
-       usb_to_input_id(dev, &input_dev->id);
-       input_dev->dev.parent = &intf->dev;
-
-       input_set_drvdata(input_dev, acecad);
-
-       input_dev->open = usb_acecad_open;
-       input_dev->close = usb_acecad_close;
-
-       input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
-       input_dev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE);
-       input_dev->keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
-       input_dev->keybit[LONG(BTN_DIGI)] = BIT(BTN_TOOL_PEN) |BIT(BTN_TOUCH) | BIT(BTN_STYLUS) | BIT(BTN_STYLUS2);
-
-       switch (id->driver_info) {
-               case 0:
-                       input_dev->absmax[ABS_X] = 5000;
-                       input_dev->absmax[ABS_Y] = 3750;
-                       input_dev->absmax[ABS_PRESSURE] = 512;
-                       if (!strlen(acecad->name))
-                               snprintf(acecad->name, sizeof(acecad->name),
-                                       "USB Acecad Flair Tablet %04x:%04x",
-                                       le16_to_cpu(dev->descriptor.idVendor),
-                                       le16_to_cpu(dev->descriptor.idProduct));
-                       break;
-               case 1:
-                       input_dev->absmax[ABS_X] = 3000;
-                       input_dev->absmax[ABS_Y] = 2250;
-                       input_dev->absmax[ABS_PRESSURE] = 1024;
-                       if (!strlen(acecad->name))
-                               snprintf(acecad->name, sizeof(acecad->name),
-                                       "USB Acecad 302 Tablet %04x:%04x",
-                                       le16_to_cpu(dev->descriptor.idVendor),
-                                       le16_to_cpu(dev->descriptor.idProduct));
-                       break;
-       }
-
-       input_dev->absfuzz[ABS_X] = 4;
-       input_dev->absfuzz[ABS_Y] = 4;
-
-       usb_fill_int_urb(acecad->irq, dev, pipe,
-                       acecad->data, maxp > 8 ? 8 : maxp,
-                       usb_acecad_irq, acecad, endpoint->bInterval);
-       acecad->irq->transfer_dma = acecad->data_dma;
-       acecad->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-
-       err = input_register_device(acecad->input);
-       if (err)
-               goto fail2;
-
-       usb_set_intfdata(intf, acecad);
-
-       return 0;
-
- fail2:        usb_buffer_free(dev, 8, acecad->data, acecad->data_dma);
- fail1: input_free_device(input_dev);
-       kfree(acecad);
-       return err;
-}
-
-static void usb_acecad_disconnect(struct usb_interface *intf)
-{
-       struct usb_acecad *acecad = usb_get_intfdata(intf);
-
-       usb_set_intfdata(intf, NULL);
-       if (acecad) {
-               usb_kill_urb(acecad->irq);
-               input_unregister_device(acecad->input);
-               usb_free_urb(acecad->irq);
-               usb_buffer_free(interface_to_usbdev(intf), 10, acecad->data, acecad->data_dma);
-               kfree(acecad);
-       }
-}
-
-static struct usb_device_id usb_acecad_id_table [] = {
-       { USB_DEVICE(USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_FLAIR), .driver_info = 0 },
-       { USB_DEVICE(USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_302),   .driver_info = 1 },
-       { }
-};
-
-MODULE_DEVICE_TABLE(usb, usb_acecad_id_table);
-
-static struct usb_driver usb_acecad_driver = {
-       .name =         "usb_acecad",
-       .probe =        usb_acecad_probe,
-       .disconnect =   usb_acecad_disconnect,
-       .id_table =     usb_acecad_id_table,
-};
-
-static int __init usb_acecad_init(void)
-{
-       int result = usb_register(&usb_acecad_driver);
-       if (result == 0)
-               info(DRIVER_VERSION ":" DRIVER_DESC);
-       return result;
-}
-
-static void __exit usb_acecad_exit(void)
-{
-       usb_deregister(&usb_acecad_driver);
-}
-
-module_init(usb_acecad_init);
-module_exit(usb_acecad_exit);
diff --git a/drivers/usb/input/aiptek.c b/drivers/usb/input/aiptek.c
deleted file mode 100644 (file)
index cc0a498..0000000
+++ /dev/null
@@ -1,2236 +0,0 @@
-/*
- *  Native support for the Aiptek HyperPen USB Tablets
- *  (4000U/5000U/6000U/8000U/12000U)
- *
- *  Copyright (c) 2001      Chris Atenasio   <chris@crud.net>
- *  Copyright (c) 2002-2004 Bryan W. Headley <bwheadley@earthlink.net>
- *
- *  based on wacom.c by
- *     Vojtech Pavlik      <vojtech@suse.cz>
- *     Andreas Bach Aaen   <abach@stofanet.dk>
- *     Clifford Wolf       <clifford@clifford.at>
- *     Sam Mosel           <sam.mosel@computer.org>
- *     James E. Blair      <corvus@gnu.org>
- *     Daniel Egger        <egger@suse.de>
- *
- *  Many thanks to Oliver Kuechemann for his support.
- *
- *  ChangeLog:
- *      v0.1 - Initial release
- *      v0.2 - Hack to get around fake event 28's. (Bryan W. Headley)
- *      v0.3 - Make URB dynamic (Bryan W. Headley, Jun-8-2002)
- *             Released to Linux 2.4.19 and 2.5.x
- *      v0.4 - Rewrote substantial portions of the code to deal with
- *             corrected control sequences, timing, dynamic configuration,
- *             support of 6000U - 12000U, procfs, and macro key support
- *             (Jan-1-2003 - Feb-5-2003, Bryan W. Headley)
- *      v1.0 - Added support for diagnostic messages, count of messages
- *             received from URB - Mar-8-2003, Bryan W. Headley
- *      v1.1 - added support for tablet resolution, changed DV and proximity
- *             some corrections - Jun-22-2003, martin schneebacher
- *           - Added support for the sysfs interface, deprecating the
- *             procfs interface for 2.5.x kernel. Also added support for
- *             Wheel command. Bryan W. Headley July-15-2003.
- *      v1.2 - Reworked jitter timer as a kernel thread.
- *             Bryan W. Headley November-28-2003/Jan-10-2004.
- *      v1.3 - Repaired issue of kernel thread going nuts on single-processor
- *             machines, introduced programmableDelay as a command line
- *             parameter. Feb 7 2004, Bryan W. Headley.
- *      v1.4 - Re-wire jitter so it does not require a thread. Courtesy of
- *             Rene van Paassen. Added reporting of physical pointer device
- *             (e.g., stylus, mouse in reports 2, 3, 4, 5. We don't know
- *             for reports 1, 6.)
- *             what physical device reports for reports 1, 6.) Also enabled
- *             MOUSE and LENS tool button modes. Renamed "rubber" to "eraser".
- *             Feb 20, 2004, Bryan W. Headley.
- *      v1.5 - Added previousJitterable, so we don't do jitter delay when the
- *             user is holding a button down for periods of time.
- *
- * NOTE:
- *      This kernel driver is augmented by the "Aiptek" XFree86 input
- *      driver for your X server, as well as the Gaiptek GUI Front-end
- *      "Tablet Manager".
- *      These three products are highly interactive with one another,
- *      so therefore it's easier to document them all as one subsystem.
- *      Please visit the project's "home page", located at,
- *      http://aiptektablet.sourceforge.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.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <linux/jiffies.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/usb/input.h>
-#include <asm/uaccess.h>
-#include <asm/unaligned.h>
-
-/*
- * Version Information
- */
-#define DRIVER_VERSION "v1.5 (May-15-2004)"
-#define DRIVER_AUTHOR  "Bryan W. Headley/Chris Atenasio"
-#define DRIVER_DESC    "Aiptek HyperPen USB Tablet Driver (Linux 2.6.x)"
-
-/*
- * Aiptek status packet:
- *
- * (returned as Report 1 - relative coordinates from mouse and stylus)
- *
- *        bit7  bit6  bit5  bit4  bit3  bit2  bit1  bit0
- * byte0   0     0     0     0     0     0     0     1
- * byte1   0     0     0     0     0    BS2   BS    Tip
- * byte2  X7    X6    X5    X4    X3    X2    X1    X0
- * byte3  Y7    Y6    Y5    Y4    Y3    Y2    Y1    Y0
- *
- * (returned as Report 2 - absolute coordinates from the stylus)
- *
- *        bit7  bit6  bit5  bit4  bit3  bit2  bit1  bit0
- * byte0   0     0     0     0     0     0     1     0
- * byte1  X7    X6    X5    X4    X3    X2    X1    X0
- * byte2  X15   X14   X13   X12   X11   X10   X9    X8
- * byte3  Y7    Y6    Y5    Y4    Y3    Y2    Y1    Y0
- * byte4  Y15   Y14   Y13   Y12   Y11   Y10   Y9    Y8
- * byte5   *     *     *    BS2   BS1   Tip   IR    DV
- * byte6  P7    P6    P5    P4    P3    P2    P1    P0
- * byte7  P15   P14   P13   P12   P11   P10   P9    P8
- *
- * (returned as Report 3 - absolute coordinates from the mouse)
- *
- *        bit7  bit6  bit5  bit4  bit3  bit2  bit1  bit0
- * byte0   0     0     0     0     0     0     1     0
- * byte1  X7    X6    X5    X4    X3    X2    X1    X0
- * byte2  X15   X14   X13   X12   X11   X10   X9    X8
- * byte3  Y7    Y6    Y5    Y4    Y3    Y2    Y1    Y0
- * byte4  Y15   Y14   Y13   Y12   Y11   Y10   Y9    Y8
- * byte5   *     *     *    BS2   BS1   Tip   IR    DV
- * byte6  P7    P6    P5    P4    P3    P2    P1    P0
- * byte7  P15   P14   P13   P12   P11   P10   P9    P8
- *
- * (returned as Report 4 - macrokeys from the stylus)
- *
- *        bit7  bit6  bit5  bit4  bit3  bit2  bit1  bit0
- * byte0   0     0     0     0     0     1     0     0
- * byte1   0     0     0    BS2   BS    Tip   IR    DV
- * byte2   0     0     0     0     0     0     1     0
- * byte3   0     0     0    K4    K3    K2    K1    K0
- * byte4  P7    P6    P5    P4    P3    P2    P1    P0
- * byte5  P15   P14   P13   P12   P11   P10   P9    P8
- *
- * (returned as Report 5 - macrokeys from the mouse)
- *
- *        bit7  bit6  bit5  bit4  bit3  bit2  bit1  bit0
- * byte0   0     0     0     0     0     1     0     0
- * byte1   0     0     0    BS2   BS    Tip   IR    DV
- * byte2   0     0     0     0     0     0     1     0
- * byte3   0     0     0    K4    K3    K2    K1    K0
- * byte4  P7    P6    P5    P4    P3    P2    P1    P0
- * byte5  P15   P14   P13   P12   P11   P10   P9    P8
- *
- * IR: In Range = Proximity on
- * DV = Data Valid
- * BS = Barrel Switch (as in, macro keys)
- * BS2 also referred to as Tablet Pick
- *
- * Command Summary:
- *
- * Use report_type CONTROL (3)
- * Use report_id   2
- *
- * Command/Data    Description     Return Bytes    Return Value
- * 0x10/0x00       SwitchToMouse       0
- * 0x10/0x01       SwitchToTablet      0
- * 0x18/0x04       SetResolution       0
- * 0x12/0xFF       AutoGainOn          0
- * 0x17/0x00       FilterOn            0
- * 0x01/0x00       GetXExtension       2           MaxX
- * 0x01/0x01       GetYExtension       2           MaxY
- * 0x02/0x00       GetModelCode        2           ModelCode = LOBYTE
- * 0x03/0x00       GetODMCode          2           ODMCode
- * 0x08/0x00       GetPressureLevels   2           =512
- * 0x04/0x00       GetFirmwareVersion  2           Firmware Version
- * 0x11/0x02       EnableMacroKeys     0
- *
- * To initialize the tablet:
- *
- * (1) Send Resolution500LPI (Command)
- * (2) Query for Model code (Option Report)
- * (3) Query for ODM code (Option Report)
- * (4) Query for firmware (Option Report)
- * (5) Query for GetXExtension (Option Report)
- * (6) Query for GetYExtension (Option Report)
- * (7) Query for GetPressureLevels (Option Report)
- * (8) SwitchToTablet for Absolute coordinates, or
- *     SwitchToMouse for Relative coordinates (Command)
- * (9) EnableMacroKeys (Command)
- * (10) FilterOn (Command)
- * (11) AutoGainOn (Command)
- *
- * (Step 9 can be omitted, but you'll then have no function keys.)
- */
-
-#define USB_VENDOR_ID_AIPTEK                           0x08ca
-#define USB_REQ_GET_REPORT                             0x01
-#define USB_REQ_SET_REPORT                             0x09
-
-       /* PointerMode codes
-        */
-#define AIPTEK_POINTER_ONLY_MOUSE_MODE                 0
-#define AIPTEK_POINTER_ONLY_STYLUS_MODE                        1
-#define AIPTEK_POINTER_EITHER_MODE                     2
-
-#define AIPTEK_POINTER_ALLOW_MOUSE_MODE(a)             \
-       (a == AIPTEK_POINTER_ONLY_MOUSE_MODE ||         \
-        a == AIPTEK_POINTER_EITHER_MODE)
-#define AIPTEK_POINTER_ALLOW_STYLUS_MODE(a)            \
-       (a == AIPTEK_POINTER_ONLY_STYLUS_MODE ||        \
-        a == AIPTEK_POINTER_EITHER_MODE)
-
-       /* CoordinateMode code
-        */
-#define AIPTEK_COORDINATE_RELATIVE_MODE                        0
-#define AIPTEK_COORDINATE_ABSOLUTE_MODE                        1
-
-       /* XTilt and YTilt values
-        */
-#define AIPTEK_TILT_MIN                                        (-128)
-#define AIPTEK_TILT_MAX                                        127
-#define AIPTEK_TILT_DISABLE                            (-10101)
-
-       /* Wheel values
-        */
-#define AIPTEK_WHEEL_MIN                               0
-#define AIPTEK_WHEEL_MAX                               1024
-#define AIPTEK_WHEEL_DISABLE                           (-10101)
-
-       /* ToolCode values, which BTW are 0x140 .. 0x14f
-        * We have things set up such that if TOOL_BUTTON_FIRED_BIT is
-        * not set, we'll send one instance of AIPTEK_TOOL_BUTTON_xxx.
-        *
-        * Whenever the user resets the value, TOOL_BUTTON_FIRED_BIT will
-        * get reset.
-        */
-#define TOOL_BUTTON(x)                                 ((x) & 0x14f)
-#define TOOL_BUTTON_FIRED(x)                           ((x) & 0x200)
-#define TOOL_BUTTON_FIRED_BIT                          0x200
-       /* toolMode codes
-        */
-#define AIPTEK_TOOL_BUTTON_PEN_MODE                    BTN_TOOL_PEN
-#define AIPTEK_TOOL_BUTTON_PEN_MODE                    BTN_TOOL_PEN
-#define AIPTEK_TOOL_BUTTON_PENCIL_MODE                 BTN_TOOL_PENCIL
-#define AIPTEK_TOOL_BUTTON_BRUSH_MODE                  BTN_TOOL_BRUSH
-#define AIPTEK_TOOL_BUTTON_AIRBRUSH_MODE               BTN_TOOL_AIRBRUSH
-#define AIPTEK_TOOL_BUTTON_ERASER_MODE                 BTN_TOOL_RUBBER
-#define AIPTEK_TOOL_BUTTON_MOUSE_MODE                  BTN_TOOL_MOUSE
-#define AIPTEK_TOOL_BUTTON_LENS_MODE                   BTN_TOOL_LENS
-
-       /* Diagnostic message codes
-        */
-#define AIPTEK_DIAGNOSTIC_NA                           0
-#define AIPTEK_DIAGNOSTIC_SENDING_RELATIVE_IN_ABSOLUTE 1
-#define AIPTEK_DIAGNOSTIC_SENDING_ABSOLUTE_IN_RELATIVE 2
-#define AIPTEK_DIAGNOSTIC_TOOL_DISALLOWED              3
-
-       /* Time to wait (in ms) to help mask hand jittering
-        * when pressing the stylus buttons.
-        */
-#define AIPTEK_JITTER_DELAY_DEFAULT                    50
-
-       /* Time to wait (in ms) in-between sending the tablet
-        * a command and beginning the process of reading the return
-        * sequence from the tablet.
-        */
-#define AIPTEK_PROGRAMMABLE_DELAY_25           25
-#define AIPTEK_PROGRAMMABLE_DELAY_50           50
-#define AIPTEK_PROGRAMMABLE_DELAY_100          100
-#define AIPTEK_PROGRAMMABLE_DELAY_200          200
-#define AIPTEK_PROGRAMMABLE_DELAY_300          300
-#define AIPTEK_PROGRAMMABLE_DELAY_400          400
-#define AIPTEK_PROGRAMMABLE_DELAY_DEFAULT      AIPTEK_PROGRAMMABLE_DELAY_400
-
-       /* Mouse button programming
-        */
-#define AIPTEK_MOUSE_LEFT_BUTTON               0x01
-#define AIPTEK_MOUSE_RIGHT_BUTTON              0x02
-#define AIPTEK_MOUSE_MIDDLE_BUTTON             0x04
-
-       /* Stylus button programming
-        */
-#define AIPTEK_STYLUS_LOWER_BUTTON             0x08
-#define AIPTEK_STYLUS_UPPER_BUTTON             0x10
-
-       /* Length of incoming packet from the tablet
-        */
-#define AIPTEK_PACKET_LENGTH                   8
-
-       /* We report in EV_MISC both the proximity and
-        * whether the report came from the stylus, tablet mouse
-        * or "unknown" -- Unknown when the tablet is in relative
-        * mode, because we only get report 1's.
-        */
-#define AIPTEK_REPORT_TOOL_UNKNOWN             0x10
-#define AIPTEK_REPORT_TOOL_STYLUS              0x20
-#define AIPTEK_REPORT_TOOL_MOUSE               0x40
-
-static int programmableDelay = AIPTEK_PROGRAMMABLE_DELAY_DEFAULT;
-static int jitterDelay = AIPTEK_JITTER_DELAY_DEFAULT;
-
-struct aiptek_features {
-       int odmCode;            /* Tablet manufacturer code       */
-       int modelCode;          /* Tablet model code (not unique) */
-       int firmwareCode;       /* prom/eeprom version            */
-       char usbPath[64 + 1];   /* device's physical usb path     */
-       char inputPath[64 + 1]; /* input device path              */
-};
-
-struct aiptek_settings {
-       int pointerMode;        /* stylus-, mouse-only or either */
-       int coordinateMode;     /* absolute/relative coords      */
-       int toolMode;           /* pen, pencil, brush, etc. tool */
-       int xTilt;              /* synthetic xTilt amount        */
-       int yTilt;              /* synthetic yTilt amount        */
-       int wheel;              /* synthetic wheel amount        */
-       int stylusButtonUpper;  /* stylus upper btn delivers...  */
-       int stylusButtonLower;  /* stylus lower btn delivers...  */
-       int mouseButtonLeft;    /* mouse left btn delivers...    */
-       int mouseButtonMiddle;  /* mouse middle btn delivers...  */
-       int mouseButtonRight;   /* mouse right btn delivers...   */
-       int programmableDelay;  /* delay for tablet programming  */
-       int jitterDelay;        /* delay for hand jittering      */
-};
-
-struct aiptek {
-       struct input_dev *inputdev;             /* input device struct           */
-       struct usb_device *usbdev;              /* usb device struct             */
-       struct urb *urb;                        /* urb for incoming reports      */
-       dma_addr_t data_dma;                    /* our dma stuffage              */
-       struct aiptek_features features;        /* tablet's array of features    */
-       struct aiptek_settings curSetting;      /* tablet's current programmable */
-       struct aiptek_settings newSetting;      /* ... and new param settings    */
-       unsigned int ifnum;                     /* interface number for IO       */
-       int diagnostic;                         /* tablet diagnostic codes       */
-       unsigned long eventCount;               /* event count                   */
-       int inDelay;                            /* jitter: in jitter delay?      */
-       unsigned long endDelay;                 /* jitter: time when delay ends  */
-       int previousJitterable;                 /* jitterable prev value     */
-       unsigned char *data;                    /* incoming packet data          */
-};
-
-/*
- * Permit easy lookup of keyboard events to send, versus
- * the bitmap which comes from the tablet. This hides the
- * issue that the F_keys are not sequentially numbered.
- */
-static const int macroKeyEvents[] = {
-       KEY_ESC, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5,
-       KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_F11,
-       KEY_F12, KEY_F13, KEY_F14, KEY_F15, KEY_F16, KEY_F17,
-       KEY_F18, KEY_F19, KEY_F20, KEY_F21, KEY_F22, KEY_F23,
-       KEY_F24, KEY_STOP, KEY_AGAIN, KEY_PROPS, KEY_UNDO,
-       KEY_FRONT, KEY_COPY, KEY_OPEN, KEY_PASTE, 0
-};
-
-/***********************************************************************
- * Relative reports deliver values in 2's complement format to
- * deal with negative offsets.
- */
-static int aiptek_convert_from_2s_complement(unsigned char c)
-{
-       int ret;
-       unsigned char b = c;
-       int negate = 0;
-
-       if ((b & 0x80) != 0) {
-               b = ~b;
-               b--;
-               negate = 1;
-       }
-       ret = b;
-       ret = (negate == 1) ? -ret : ret;
-       return ret;
-}
-
-/***********************************************************************
- * aiptek_irq can receive one of six potential reports.
- * The documentation for each is in the body of the function.
- *
- * The tablet reports on several attributes per invocation of
- * aiptek_irq. Because the Linux Input Event system allows the
- * transmission of ONE attribute per input_report_xxx() call,
- * collation has to be done on the other end to reconstitute
- * a complete tablet report. Further, the number of Input Event reports
- * submitted varies, depending on what USB report type, and circumstance.
- * To deal with this, EV_MSC is used to indicate an 'end-of-report'
- * message. This has been an undocumented convention understood by the kernel
- * tablet driver and clients such as gpm and XFree86's tablet drivers.
- *
- * Of the information received from the tablet, the one piece I
- * cannot transmit is the proximity bit (without resorting to an EV_MSC
- * convention above.) I therefore have taken over REL_MISC and ABS_MISC
- * (for relative and absolute reports, respectively) for communicating
- * Proximity. Why two events? I thought it interesting to know if the
- * Proximity event occurred while the tablet was in absolute or relative
- * mode.
- *
- * Other tablets use the notion of a certain minimum stylus pressure
- * to infer proximity. While that could have been done, that is yet
- * another 'by convention' behavior, the documentation for which
- * would be spread between two (or more) pieces of software.
- *
- * EV_MSC usage was terminated for this purpose in Linux 2.5.x, and
- * replaced with the input_sync() method (which emits EV_SYN.)
- */
-
-static void aiptek_irq(struct urb *urb)
-{
-       struct aiptek *aiptek = urb->context;
-       unsigned char *data = aiptek->data;
-       struct input_dev *inputdev = aiptek->inputdev;
-       int jitterable = 0;
-       int retval, macro, x, y, z, left, right, middle, p, dv, tip, bs, pck;
-
-       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;
-       }
-
-       /* See if we are in a delay loop -- throw out report if true.
-        */
-       if (aiptek->inDelay == 1 && time_after(aiptek->endDelay, jiffies)) {
-               goto exit;
-       }
-
-       aiptek->inDelay = 0;
-       aiptek->eventCount++;
-
-       /* Report 1 delivers relative coordinates with either a stylus
-        * or the mouse. You do not know, however, which input
-        * tool generated the event.
-        */
-       if (data[0] == 1) {
-               if (aiptek->curSetting.coordinateMode ==
-                   AIPTEK_COORDINATE_ABSOLUTE_MODE) {
-                       aiptek->diagnostic =
-                           AIPTEK_DIAGNOSTIC_SENDING_RELATIVE_IN_ABSOLUTE;
-               } else {
-                       x = aiptek_convert_from_2s_complement(data[2]);
-                       y = aiptek_convert_from_2s_complement(data[3]);
-
-                       /* jitterable keeps track of whether any button has been pressed.
-                        * We're also using it to remap the physical mouse button mask
-                        * to pseudo-settings. (We don't specifically care about it's
-                        * value after moving/transposing mouse button bitmasks, except
-                        * that a non-zero value indicates that one or more
-                        * mouse button was pressed.)
-                        */
-                       jitterable = data[5] & 0x07;
-
-                       left = (data[5] & aiptek->curSetting.mouseButtonLeft) != 0 ? 1 : 0;
-                       right = (data[5] & aiptek->curSetting.mouseButtonRight) != 0 ? 1 : 0;
-                       middle = (data[5] & aiptek->curSetting.mouseButtonMiddle) != 0 ? 1 : 0;
-
-                       input_report_key(inputdev, BTN_LEFT, left);
-                       input_report_key(inputdev, BTN_MIDDLE, middle);
-                       input_report_key(inputdev, BTN_RIGHT, right);
-                       input_report_rel(inputdev, REL_X, x);
-                       input_report_rel(inputdev, REL_Y, y);
-                       input_report_rel(inputdev, REL_MISC, 1 | AIPTEK_REPORT_TOOL_UNKNOWN);
-
-                       /* Wheel support is in the form of a single-event
-                        * firing.
-                        */
-                       if (aiptek->curSetting.wheel != AIPTEK_WHEEL_DISABLE) {
-                               input_report_rel(inputdev, REL_WHEEL,
-                                                aiptek->curSetting.wheel);
-                               aiptek->curSetting.wheel = AIPTEK_WHEEL_DISABLE;
-                       }
-                       input_sync(inputdev);
-               }
-       }
-       /* Report 2 is delivered only by the stylus, and delivers
-        * absolute coordinates.
-        */
-       else if (data[0] == 2) {
-               if (aiptek->curSetting.coordinateMode == AIPTEK_COORDINATE_RELATIVE_MODE) {
-                       aiptek->diagnostic = AIPTEK_DIAGNOSTIC_SENDING_ABSOLUTE_IN_RELATIVE;
-               } else if (!AIPTEK_POINTER_ALLOW_STYLUS_MODE
-                           (aiptek->curSetting.pointerMode)) {
-                               aiptek->diagnostic = AIPTEK_DIAGNOSTIC_TOOL_DISALLOWED;
-               } else {
-                       x = le16_to_cpu(get_unaligned((__le16 *) (data + 1)));
-                       y = le16_to_cpu(get_unaligned((__le16 *) (data + 3)));
-                       z = le16_to_cpu(get_unaligned((__le16 *) (data + 6)));
-
-                       p = (data[5] & 0x01) != 0 ? 1 : 0;
-                       dv = (data[5] & 0x02) != 0 ? 1 : 0;
-                       tip = (data[5] & 0x04) != 0 ? 1 : 0;
-
-                       /* Use jitterable to re-arrange button masks
-                        */
-                       jitterable = data[5] & 0x18;
-
-                       bs = (data[5] & aiptek->curSetting.stylusButtonLower) != 0 ? 1 : 0;
-                       pck = (data[5] & aiptek->curSetting.stylusButtonUpper) != 0 ? 1 : 0;
-
-                       /* dv indicates 'data valid' (e.g., the tablet is in sync
-                        * and has delivered a "correct" report) We will ignore
-                        * all 'bad' reports...
-                        */
-                       if (dv != 0) {
-                               /* If we've not already sent a tool_button_?? code, do
-                                * so now. Then set FIRED_BIT so it won't be resent unless
-                                * the user forces FIRED_BIT off.
-                                */
-                               if (TOOL_BUTTON_FIRED
-                                   (aiptek->curSetting.toolMode) == 0) {
-                                       input_report_key(inputdev,
-                                                        TOOL_BUTTON(aiptek->curSetting.toolMode),
-                                                        1);
-                                       aiptek->curSetting.toolMode |= TOOL_BUTTON_FIRED_BIT;
-                               }
-
-                               if (p != 0) {
-                                       input_report_abs(inputdev, ABS_X, x);
-                                       input_report_abs(inputdev, ABS_Y, y);
-                                       input_report_abs(inputdev, ABS_PRESSURE, z);
-
-                                       input_report_key(inputdev, BTN_TOUCH, tip);
-                                       input_report_key(inputdev, BTN_STYLUS, bs);
-                                       input_report_key(inputdev, BTN_STYLUS2, pck);
-
-                                       if (aiptek->curSetting.xTilt !=
-                                           AIPTEK_TILT_DISABLE) {
-                                               input_report_abs(inputdev,
-                                                                ABS_TILT_X,
-                                                                aiptek->curSetting.xTilt);
-                                       }
-                                       if (aiptek->curSetting.yTilt != AIPTEK_TILT_DISABLE) {
-                                               input_report_abs(inputdev,
-                                                                ABS_TILT_Y,
-                                                                aiptek->curSetting.yTilt);
-                                       }
-
-                                       /* Wheel support is in the form of a single-event
-                                        * firing.
-                                        */
-                                       if (aiptek->curSetting.wheel !=
-                                           AIPTEK_WHEEL_DISABLE) {
-                                               input_report_abs(inputdev,
-                                                                ABS_WHEEL,
-                                                                aiptek->curSetting.wheel);
-                                               aiptek->curSetting.wheel = AIPTEK_WHEEL_DISABLE;
-                                       }
-                               }
-                               input_report_abs(inputdev, ABS_MISC, p | AIPTEK_REPORT_TOOL_STYLUS);
-                               input_sync(inputdev);
-                       }
-               }
-       }
-       /* Report 3's come from the mouse in absolute mode.
-        */
-       else if (data[0] == 3) {
-               if (aiptek->curSetting.coordinateMode == AIPTEK_COORDINATE_RELATIVE_MODE) {
-                       aiptek->diagnostic = AIPTEK_DIAGNOSTIC_SENDING_ABSOLUTE_IN_RELATIVE;
-               } else if (!AIPTEK_POINTER_ALLOW_MOUSE_MODE
-                       (aiptek->curSetting.pointerMode)) {
-                       aiptek->diagnostic = AIPTEK_DIAGNOSTIC_TOOL_DISALLOWED;
-               } else {
-                       x = le16_to_cpu(get_unaligned((__le16 *) (data + 1)));
-                       y = le16_to_cpu(get_unaligned((__le16 *) (data + 3)));
-
-                       jitterable = data[5] & 0x1c;
-
-                       p = (data[5] & 0x01) != 0 ? 1 : 0;
-                       dv = (data[5] & 0x02) != 0 ? 1 : 0;
-                       left = (data[5] & aiptek->curSetting.mouseButtonLeft) != 0 ? 1 : 0;
-                       right = (data[5] & aiptek->curSetting.mouseButtonRight) != 0 ? 1 : 0;
-                       middle = (data[5] & aiptek->curSetting.mouseButtonMiddle) != 0 ? 1 : 0;
-
-                       if (dv != 0) {
-                               /* If we've not already sent a tool_button_?? code, do
-                                * so now. Then set FIRED_BIT so it won't be resent unless
-                                * the user forces FIRED_BIT off.
-                                */
-                               if (TOOL_BUTTON_FIRED
-                                   (aiptek->curSetting.toolMode) == 0) {
-                                       input_report_key(inputdev,
-                                                        TOOL_BUTTON(aiptek->curSetting.toolMode),
-                                                        1);
-                                       aiptek->curSetting.toolMode |= TOOL_BUTTON_FIRED_BIT;
-                               }
-
-                               if (p != 0) {
-                                       input_report_abs(inputdev, ABS_X, x);
-                                       input_report_abs(inputdev, ABS_Y, y);
-
-                                       input_report_key(inputdev, BTN_LEFT, left);
-                                       input_report_key(inputdev, BTN_MIDDLE, middle);
-                                       input_report_key(inputdev, BTN_RIGHT, right);
-
-                                       /* Wheel support is in the form of a single-event
-                                        * firing.
-                                        */
-                                       if (aiptek->curSetting.wheel != AIPTEK_WHEEL_DISABLE) {
-                                               input_report_abs(inputdev,
-                                                                ABS_WHEEL,
-                                                                aiptek->curSetting.wheel);
-                                               aiptek->curSetting.wheel = AIPTEK_WHEEL_DISABLE;
-                                       }
-                               }
-                               input_report_rel(inputdev, REL_MISC, p | AIPTEK_REPORT_TOOL_MOUSE);
-                               input_sync(inputdev);
-                       }
-               }
-       }
-       /* Report 4s come from the macro keys when pressed by stylus
-        */
-       else if (data[0] == 4) {
-               jitterable = data[1] & 0x18;
-
-               p = (data[1] & 0x01) != 0 ? 1 : 0;
-               dv = (data[1] & 0x02) != 0 ? 1 : 0;
-               tip = (data[1] & 0x04) != 0 ? 1 : 0;
-               bs = (data[1] & aiptek->curSetting.stylusButtonLower) != 0 ? 1 : 0;
-               pck = (data[1] & aiptek->curSetting.stylusButtonUpper) != 0 ? 1 : 0;
-
-               macro = data[3];
-               z = le16_to_cpu(get_unaligned((__le16 *) (data + 4)));
-
-               if (dv != 0) {
-                       /* If we've not already sent a tool_button_?? code, do
-                        * so now. Then set FIRED_BIT so it won't be resent unless
-                        * the user forces FIRED_BIT off.
-                        */
-                       if (TOOL_BUTTON_FIRED(aiptek->curSetting.toolMode) == 0) {
-                               input_report_key(inputdev,
-                                                TOOL_BUTTON(aiptek->curSetting.toolMode),
-                                                1);
-                               aiptek->curSetting.toolMode |= TOOL_BUTTON_FIRED_BIT;
-                       }
-
-                       if (p != 0) {
-                               input_report_key(inputdev, BTN_TOUCH, tip);
-                               input_report_key(inputdev, BTN_STYLUS, bs);
-                               input_report_key(inputdev, BTN_STYLUS2, pck);
-                               input_report_abs(inputdev, ABS_PRESSURE, z);
-                       }
-
-                       /* For safety, we're sending key 'break' codes for the
-                        * neighboring macro keys.
-                        */
-                       if (macro > 0) {
-                               input_report_key(inputdev,
-                                                macroKeyEvents[macro - 1], 0);
-                       }
-                       if (macro < 25) {
-                               input_report_key(inputdev,
-                                                macroKeyEvents[macro + 1], 0);
-                       }
-                       input_report_key(inputdev, macroKeyEvents[macro], p);
-                       input_report_abs(inputdev, ABS_MISC,
-                                        p | AIPTEK_REPORT_TOOL_STYLUS);
-                       input_sync(inputdev);
-               }
-       }
-       /* Report 5s come from the macro keys when pressed by mouse
-        */
-       else if (data[0] == 5) {
-               jitterable = data[1] & 0x1c;
-
-               p = (data[1] & 0x01) != 0 ? 1 : 0;
-               dv = (data[1] & 0x02) != 0 ? 1 : 0;
-               left = (data[1]& aiptek->curSetting.mouseButtonLeft) != 0 ? 1 : 0;
-               right = (data[1] & aiptek->curSetting.mouseButtonRight) != 0 ? 1 : 0;
-               middle = (data[1] & aiptek->curSetting.mouseButtonMiddle) != 0 ? 1 : 0;
-               macro = data[3];
-
-               if (dv != 0) {
-                       /* If we've not already sent a tool_button_?? code, do
-                        * so now. Then set FIRED_BIT so it won't be resent unless
-                        * the user forces FIRED_BIT off.
-                        */
-                       if (TOOL_BUTTON_FIRED(aiptek->curSetting.toolMode) == 0) {
-                               input_report_key(inputdev,
-                                                TOOL_BUTTON(aiptek->curSetting.toolMode),
-                                                1);
-                               aiptek->curSetting.toolMode |= TOOL_BUTTON_FIRED_BIT;
-                       }
-
-                       if (p != 0) {
-                               input_report_key(inputdev, BTN_LEFT, left);
-                               input_report_key(inputdev, BTN_MIDDLE, middle);
-                               input_report_key(inputdev, BTN_RIGHT, right);
-                       }
-
-                       /* For safety, we're sending key 'break' codes for the
-                        * neighboring macro keys.
-                        */
-                       if (macro > 0) {
-                               input_report_key(inputdev,
-                                                macroKeyEvents[macro - 1], 0);
-                       }
-                       if (macro < 25) {
-                               input_report_key(inputdev,
-                                                macroKeyEvents[macro + 1], 0);
-                       }
-
-                       input_report_key(inputdev, macroKeyEvents[macro], 1);
-                       input_report_rel(inputdev, ABS_MISC,
-                                        p | AIPTEK_REPORT_TOOL_MOUSE);
-                       input_sync(inputdev);
-               }
-       }
-       /* We have no idea which tool can generate a report 6. Theoretically,
-        * neither need to, having been given reports 4 & 5 for such use.
-        * However, report 6 is the 'official-looking' report for macroKeys;
-        * reports 4 & 5 supposively are used to support unnamed, unknown
-        * hat switches (which just so happen to be the macroKeys.)
-        */
-       else if (data[0] == 6) {
-               macro = le16_to_cpu(get_unaligned((__le16 *) (data + 1)));
-               if (macro > 0) {
-                       input_report_key(inputdev, macroKeyEvents[macro - 1],
-                                        0);
-               }
-               if (macro < 25) {
-                       input_report_key(inputdev, macroKeyEvents[macro + 1],
-                                        0);
-               }
-
-               /* If we've not already sent a tool_button_?? code, do
-                * so now. Then set FIRED_BIT so it won't be resent unless
-                * the user forces FIRED_BIT off.
-                */
-               if (TOOL_BUTTON_FIRED(aiptek->curSetting.toolMode) == 0) {
-                       input_report_key(inputdev,
-                                        TOOL_BUTTON(aiptek->curSetting.
-                                                    toolMode), 1);
-                       aiptek->curSetting.toolMode |= TOOL_BUTTON_FIRED_BIT;
-               }
-
-               input_report_key(inputdev, macroKeyEvents[macro], 1);
-               input_report_abs(inputdev, ABS_MISC,
-                                1 | AIPTEK_REPORT_TOOL_UNKNOWN);
-               input_sync(inputdev);
-       } else {
-               dbg("Unknown report %d", data[0]);
-       }
-
-       /* Jitter may occur when the user presses a button on the stlyus
-        * or the mouse. What we do to prevent that is wait 'x' milliseconds
-        * following a 'jitterable' event, which should give the hand some time
-        * stabilize itself.
-        *
-        * We just introduced aiptek->previousJitterable to carry forth the
-        * notion that jitter occurs when the button state changes from on to off:
-        * a person drawing, holding a button down is not subject to jittering.
-        * With that in mind, changing from upper button depressed to lower button
-        * WILL transition through a jitter delay.
-        */
-
-       if (aiptek->previousJitterable != jitterable &&
-           aiptek->curSetting.jitterDelay != 0 && aiptek->inDelay != 1) {
-               aiptek->endDelay = jiffies +
-                   ((aiptek->curSetting.jitterDelay * HZ) / 1000);
-               aiptek->inDelay = 1;
-       }
-       aiptek->previousJitterable = jitterable;
-
-exit:
-       retval = usb_submit_urb(urb, GFP_ATOMIC);
-       if (retval != 0) {
-               err("%s - usb_submit_urb failed with result %d",
-                   __FUNCTION__, retval);
-       }
-}
-
-/***********************************************************************
- * These are the USB id's known so far. We do not identify them to
- * specific Aiptek model numbers, because there has been overlaps,
- * use, and reuse of id's in existing models. Certain models have
- * been known to use more than one ID, indicative perhaps of
- * manufacturing revisions. In any event, we consider these
- * IDs to not be model-specific nor unique.
- */
-static const struct usb_device_id aiptek_ids[] = {
-       {USB_DEVICE(USB_VENDOR_ID_AIPTEK, 0x01)},
-       {USB_DEVICE(USB_VENDOR_ID_AIPTEK, 0x10)},
-       {USB_DEVICE(USB_VENDOR_ID_AIPTEK, 0x20)},
-       {USB_DEVICE(USB_VENDOR_ID_AIPTEK, 0x21)},
-       {USB_DEVICE(USB_VENDOR_ID_AIPTEK, 0x22)},
-       {USB_DEVICE(USB_VENDOR_ID_AIPTEK, 0x23)},
-       {USB_DEVICE(USB_VENDOR_ID_AIPTEK, 0x24)},
-       {}
-};
-
-MODULE_DEVICE_TABLE(usb, aiptek_ids);
-
-/***********************************************************************
- * Open an instance of the tablet driver.
- */
-static int aiptek_open(struct input_dev *inputdev)
-{
-       struct aiptek *aiptek = input_get_drvdata(inputdev);
-
-       aiptek->urb->dev = aiptek->usbdev;
-       if (usb_submit_urb(aiptek->urb, GFP_KERNEL) != 0)
-               return -EIO;
-
-       return 0;
-}
-
-/***********************************************************************
- * Close an instance of the tablet driver.
- */
-static void aiptek_close(struct input_dev *inputdev)
-{
-       struct aiptek *aiptek = input_get_drvdata(inputdev);
-
-       usb_kill_urb(aiptek->urb);
-}
-
-/***********************************************************************
- * aiptek_set_report and aiptek_get_report() are borrowed from Linux 2.4.x,
- * where they were known as usb_set_report and usb_get_report.
- */
-static int
-aiptek_set_report(struct aiptek *aiptek,
-                 unsigned char report_type,
-                 unsigned char report_id, void *buffer, int size)
-{
-       return usb_control_msg(aiptek->usbdev,
-                              usb_sndctrlpipe(aiptek->usbdev, 0),
-                              USB_REQ_SET_REPORT,
-                              USB_TYPE_CLASS | USB_RECIP_INTERFACE |
-                              USB_DIR_OUT, (report_type << 8) + report_id,
-                              aiptek->ifnum, buffer, size, 5000);
-}
-
-static int
-aiptek_get_report(struct aiptek *aiptek,
-                 unsigned char report_type,
-                 unsigned char report_id, void *buffer, int size)
-{
-       return usb_control_msg(aiptek->usbdev,
-                              usb_rcvctrlpipe(aiptek->usbdev, 0),
-                              USB_REQ_GET_REPORT,
-                              USB_TYPE_CLASS | USB_RECIP_INTERFACE |
-                              USB_DIR_IN, (report_type << 8) + report_id,
-                              aiptek->ifnum, buffer, size, 5000);
-}
-
-/***********************************************************************
- * Send a command to the tablet.
- */
-static int
-aiptek_command(struct aiptek *aiptek, unsigned char command, unsigned char data)
-{
-       const int sizeof_buf = 3 * sizeof(u8);
-       int ret;
-       u8 *buf;
-
-       buf = kmalloc(sizeof_buf, GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-
-       buf[0] = 2;
-       buf[1] = command;
-       buf[2] = data;
-
-       if ((ret =
-            aiptek_set_report(aiptek, 3, 2, buf, sizeof_buf)) != sizeof_buf) {
-               dbg("aiptek_program: failed, tried to send: 0x%02x 0x%02x",
-                   command, data);
-       }
-       kfree(buf);
-       return ret < 0 ? ret : 0;
-}
-
-/***********************************************************************
- * Retrieve information from the tablet. Querying info is defined as first
- * sending the {command,data} sequence as a command, followed by a wait
- * (aka, "programmaticDelay") and then a "read" request.
- */
-static int
-aiptek_query(struct aiptek *aiptek, unsigned char command, unsigned char data)
-{
-       const int sizeof_buf = 3 * sizeof(u8);
-       int ret;
-       u8 *buf;
-
-       buf = kmalloc(sizeof_buf, GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-
-       buf[0] = 2;
-       buf[1] = command;
-       buf[2] = data;
-
-       if (aiptek_command(aiptek, command, data) != 0) {
-               kfree(buf);
-               return -EIO;
-       }
-       msleep(aiptek->curSetting.programmableDelay);
-
-       if ((ret =
-            aiptek_get_report(aiptek, 3, 2, buf, sizeof_buf)) != sizeof_buf) {
-               dbg("aiptek_query failed: returned 0x%02x 0x%02x 0x%02x",
-                   buf[0], buf[1], buf[2]);
-               ret = -EIO;
-       } else {
-               ret = le16_to_cpu(get_unaligned((__le16 *) (buf + 1)));
-       }
-       kfree(buf);
-       return ret;
-}
-
-/***********************************************************************
- * Program the tablet into either absolute or relative mode.
- * We also get information about the tablet's size.
- */
-static int aiptek_program_tablet(struct aiptek *aiptek)
-{
-       int ret;
-       /* Execute Resolution500LPI */
-       if ((ret = aiptek_command(aiptek, 0x18, 0x04)) < 0)
-               return ret;
-
-       /* Query getModelCode */
-       if ((ret = aiptek_query(aiptek, 0x02, 0x00)) < 0)
-               return ret;
-       aiptek->features.modelCode = ret & 0xff;
-
-       /* Query getODMCode */
-       if ((ret = aiptek_query(aiptek, 0x03, 0x00)) < 0)
-               return ret;
-       aiptek->features.odmCode = ret;
-
-       /* Query getFirmwareCode */
-       if ((ret = aiptek_query(aiptek, 0x04, 0x00)) < 0)
-               return ret;
-       aiptek->features.firmwareCode = ret;
-
-       /* Query getXextension */
-       if ((ret = aiptek_query(aiptek, 0x01, 0x00)) < 0)
-               return ret;
-       aiptek->inputdev->absmin[ABS_X] = 0;
-       aiptek->inputdev->absmax[ABS_X] = ret - 1;
-
-       /* Query getYextension */
-       if ((ret = aiptek_query(aiptek, 0x01, 0x01)) < 0)
-               return ret;
-       aiptek->inputdev->absmin[ABS_Y] = 0;
-       aiptek->inputdev->absmax[ABS_Y] = ret - 1;
-
-       /* Query getPressureLevels */
-       if ((ret = aiptek_query(aiptek, 0x08, 0x00)) < 0)
-               return ret;
-       aiptek->inputdev->absmin[ABS_PRESSURE] = 0;
-       aiptek->inputdev->absmax[ABS_PRESSURE] = ret - 1;
-
-       /* Depending on whether we are in absolute or relative mode, we will
-        * do a switchToTablet(absolute) or switchToMouse(relative) command.
-        */
-       if (aiptek->curSetting.coordinateMode ==
-           AIPTEK_COORDINATE_ABSOLUTE_MODE) {
-               /* Execute switchToTablet */
-               if ((ret = aiptek_command(aiptek, 0x10, 0x01)) < 0) {
-                       return ret;
-               }
-       } else {
-               /* Execute switchToMouse */
-               if ((ret = aiptek_command(aiptek, 0x10, 0x00)) < 0) {
-                       return ret;
-               }
-       }
-
-       /* Enable the macro keys */
-       if ((ret = aiptek_command(aiptek, 0x11, 0x02)) < 0)
-               return ret;
-#if 0
-       /* Execute FilterOn */
-       if ((ret = aiptek_command(aiptek, 0x17, 0x00)) < 0)
-               return ret;
-#endif
-
-       /* Execute AutoGainOn */
-       if ((ret = aiptek_command(aiptek, 0x12, 0xff)) < 0)
-               return ret;
-
-       /* Reset the eventCount, so we track events from last (re)programming
-        */
-       aiptek->diagnostic = AIPTEK_DIAGNOSTIC_NA;
-       aiptek->eventCount = 0;
-
-       return 0;
-}
-
-/***********************************************************************
- * Sysfs functions. Sysfs prefers that individually-tunable parameters
- * exist in their separate pseudo-files. Summary data that is immutable
- * may exist in a singular file so long as you don't define a writeable
- * interface.
- */
-
-/***********************************************************************
- * support the 'size' file -- display support
- */
-static ssize_t show_tabletSize(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct aiptek *aiptek = dev_get_drvdata(dev);
-
-       if (aiptek == NULL)
-               return 0;
-
-       return snprintf(buf, PAGE_SIZE, "%dx%d\n",
-                       aiptek->inputdev->absmax[ABS_X] + 1,
-                       aiptek->inputdev->absmax[ABS_Y] + 1);
-}
-
-/* These structs define the sysfs files, param #1 is the name of the
- * file, param 2 is the file permissions, param 3 & 4 are to the
- * output generator and input parser routines. Absence of a routine is
- * permitted -- it only means can't either 'cat' the file, or send data
- * to it.
- */
-static DEVICE_ATTR(size, S_IRUGO, show_tabletSize, NULL);
-
-/***********************************************************************
- * support routines for the 'product_id' file
- */
-static ssize_t show_tabletProductId(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct aiptek *aiptek = dev_get_drvdata(dev);
-
-       if (aiptek == NULL)
-               return 0;
-
-       return snprintf(buf, PAGE_SIZE, "0x%04x\n",
-                       aiptek->inputdev->id.product);
-}
-
-static DEVICE_ATTR(product_id, S_IRUGO, show_tabletProductId, NULL);
-
-/***********************************************************************
- * support routines for the 'vendor_id' file
- */
-static ssize_t show_tabletVendorId(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct aiptek *aiptek = dev_get_drvdata(dev);
-
-       if (aiptek == NULL)
-               return 0;
-
-       return snprintf(buf, PAGE_SIZE, "0x%04x\n", aiptek->inputdev->id.vendor);
-}
-
-static DEVICE_ATTR(vendor_id, S_IRUGO, show_tabletVendorId, NULL);
-
-/***********************************************************************
- * support routines for the 'vendor' file
- */
-static ssize_t show_tabletManufacturer(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct aiptek *aiptek = dev_get_drvdata(dev);
-       int retval;
-
-       if (aiptek == NULL)
-               return 0;
-
-       retval = snprintf(buf, PAGE_SIZE, "%s\n", aiptek->usbdev->manufacturer);
-       return retval;
-}
-
-static DEVICE_ATTR(vendor, S_IRUGO, show_tabletManufacturer, NULL);
-
-/***********************************************************************
- * support routines for the 'product' file
- */
-static ssize_t show_tabletProduct(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct aiptek *aiptek = dev_get_drvdata(dev);
-       int retval;
-
-       if (aiptek == NULL)
-               return 0;
-
-       retval = snprintf(buf, PAGE_SIZE, "%s\n", aiptek->usbdev->product);
-       return retval;
-}
-
-static DEVICE_ATTR(product, S_IRUGO, show_tabletProduct, NULL);
-
-/***********************************************************************
- * support routines for the 'pointer_mode' file. Note that this file
- * both displays current setting and allows reprogramming.
- */
-static ssize_t show_tabletPointerMode(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct aiptek *aiptek = dev_get_drvdata(dev);
-       char *s;
-
-       if (aiptek == NULL)
-               return 0;
-
-       switch (aiptek->curSetting.pointerMode) {
-       case AIPTEK_POINTER_ONLY_STYLUS_MODE:
-               s = "stylus";
-               break;
-
-       case AIPTEK_POINTER_ONLY_MOUSE_MODE:
-               s = "mouse";
-               break;
-
-       case AIPTEK_POINTER_EITHER_MODE:
-               s = "either";
-               break;
-
-       default:
-               s = "unknown";
-               break;
-       }
-       return snprintf(buf, PAGE_SIZE, "%s\n", s);
-}
-
-static ssize_t
-store_tabletPointerMode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-       struct aiptek *aiptek = dev_get_drvdata(dev);
-       if (aiptek == NULL)
-               return 0;
-
-       if (strcmp(buf, "stylus") == 0) {
-               aiptek->newSetting.pointerMode =
-                   AIPTEK_POINTER_ONLY_STYLUS_MODE;
-       } else if (strcmp(buf, "mouse") == 0) {
-               aiptek->newSetting.pointerMode = AIPTEK_POINTER_ONLY_MOUSE_MODE;
-       } else if (strcmp(buf, "either") == 0) {
-               aiptek->newSetting.pointerMode = AIPTEK_POINTER_EITHER_MODE;
-       }
-       return count;
-}
-
-static DEVICE_ATTR(pointer_mode,
-                  S_IRUGO | S_IWUGO,
-                  show_tabletPointerMode, store_tabletPointerMode);
-
-/***********************************************************************
- * support routines for the 'coordinate_mode' file. Note that this file
- * both displays current setting and allows reprogramming.
- */
-static ssize_t show_tabletCoordinateMode(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct aiptek *aiptek = dev_get_drvdata(dev);
-       char *s;
-
-       if (aiptek == NULL)
-               return 0;
-
-       switch (aiptek->curSetting.coordinateMode) {
-       case AIPTEK_COORDINATE_ABSOLUTE_MODE:
-               s = "absolute";
-               break;
-
-       case AIPTEK_COORDINATE_RELATIVE_MODE:
-               s = "relative";
-               break;
-
-       default:
-               s = "unknown";
-               break;
-       }
-       return snprintf(buf, PAGE_SIZE, "%s\n", s);
-}
-
-static ssize_t
-store_tabletCoordinateMode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-       struct aiptek *aiptek = dev_get_drvdata(dev);
-       if (aiptek == NULL)
-               return 0;
-
-       if (strcmp(buf, "absolute") == 0) {
-               aiptek->newSetting.pointerMode =
-                   AIPTEK_COORDINATE_ABSOLUTE_MODE;
-       } else if (strcmp(buf, "relative") == 0) {
-               aiptek->newSetting.pointerMode =
-                   AIPTEK_COORDINATE_RELATIVE_MODE;
-       }
-       return count;
-}
-
-static DEVICE_ATTR(coordinate_mode,
-                  S_IRUGO | S_IWUGO,
-                  show_tabletCoordinateMode, store_tabletCoordinateMode);
-
-/***********************************************************************
- * support routines for the 'tool_mode' file. Note that this file
- * both displays current setting and allows reprogramming.
- */
-static ssize_t show_tabletToolMode(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct aiptek *aiptek = dev_get_drvdata(dev);
-       char *s;
-
-       if (aiptek == NULL)
-               return 0;
-
-       switch (TOOL_BUTTON(aiptek->curSetting.toolMode)) {
-       case AIPTEK_TOOL_BUTTON_MOUSE_MODE:
-               s = "mouse";
-               break;
-
-       case AIPTEK_TOOL_BUTTON_ERASER_MODE:
-               s = "eraser";
-               break;
-
-       case AIPTEK_TOOL_BUTTON_PENCIL_MODE:
-               s = "pencil";
-               break;
-
-       case AIPTEK_TOOL_BUTTON_PEN_MODE:
-               s = "pen";
-               break;
-
-       case AIPTEK_TOOL_BUTTON_BRUSH_MODE:
-               s = "brush";
-               break;
-
-       case AIPTEK_TOOL_BUTTON_AIRBRUSH_MODE:
-               s = "airbrush";
-               break;
-
-       case AIPTEK_TOOL_BUTTON_LENS_MODE:
-               s = "lens";
-               break;
-
-       default:
-               s = "unknown";
-               break;
-       }
-       return snprintf(buf, PAGE_SIZE, "%s\n", s);
-}
-
-static ssize_t
-store_tabletToolMode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-       struct aiptek *aiptek = dev_get_drvdata(dev);
-       if (aiptek == NULL)
-               return 0;
-
-       if (strcmp(buf, "mouse") == 0) {
-               aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_MOUSE_MODE;
-       } else if (strcmp(buf, "eraser") == 0) {
-               aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_ERASER_MODE;
-       } else if (strcmp(buf, "pencil") == 0) {
-               aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_PENCIL_MODE;
-       } else if (strcmp(buf, "pen") == 0) {
-               aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_PEN_MODE;
-       } else if (strcmp(buf, "brush") == 0) {
-               aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_BRUSH_MODE;
-       } else if (strcmp(buf, "airbrush") == 0) {
-               aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_AIRBRUSH_MODE;
-       } else if (strcmp(buf, "lens") == 0) {
-               aiptek->newSetting.toolMode = AIPTEK_TOOL_BUTTON_LENS_MODE;
-       }
-
-       return count;
-}
-
-static DEVICE_ATTR(tool_mode,
-                  S_IRUGO | S_IWUGO,
-                  show_tabletToolMode, store_tabletToolMode);
-
-/***********************************************************************
- * support routines for the 'xtilt' file. Note that this file
- * both displays current setting and allows reprogramming.
- */
-static ssize_t show_tabletXtilt(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct aiptek *aiptek = dev_get_drvdata(dev);
-
-       if (aiptek == NULL)
-               return 0;
-
-       if (aiptek->curSetting.xTilt == AIPTEK_TILT_DISABLE) {
-               return snprintf(buf, PAGE_SIZE, "disable\n");
-       } else {
-               return snprintf(buf, PAGE_SIZE, "%d\n",
-                               aiptek->curSetting.xTilt);
-       }
-}
-
-static ssize_t
-store_tabletXtilt(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-       struct aiptek *aiptek = dev_get_drvdata(dev);
-       int x;
-
-       if (aiptek == NULL)
-               return 0;
-
-       if (strcmp(buf, "disable") == 0) {
-               aiptek->newSetting.xTilt = AIPTEK_TILT_DISABLE;
-       } else {
-               x = (int)simple_strtol(buf, NULL, 10);
-               if (x >= AIPTEK_TILT_MIN && x <= AIPTEK_TILT_MAX) {
-                       aiptek->newSetting.xTilt = x;
-               }
-       }
-       return count;
-}
-
-static DEVICE_ATTR(xtilt,
-                  S_IRUGO | S_IWUGO, show_tabletXtilt, store_tabletXtilt);
-
-/***********************************************************************
- * support routines for the 'ytilt' file. Note that this file
- * both displays current setting and allows reprogramming.
- */
-static ssize_t show_tabletYtilt(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct aiptek *aiptek = dev_get_drvdata(dev);
-
-       if (aiptek == NULL)
-               return 0;
-
-       if (aiptek->curSetting.yTilt == AIPTEK_TILT_DISABLE) {
-               return snprintf(buf, PAGE_SIZE, "disable\n");
-       } else {
-               return snprintf(buf, PAGE_SIZE, "%d\n",
-                               aiptek->curSetting.yTilt);
-       }
-}
-
-static ssize_t
-store_tabletYtilt(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-       struct aiptek *aiptek = dev_get_drvdata(dev);
-       int y;
-
-       if (aiptek == NULL)
-               return 0;
-
-       if (strcmp(buf, "disable") == 0) {
-               aiptek->newSetting.yTilt = AIPTEK_TILT_DISABLE;
-       } else {
-               y = (int)simple_strtol(buf, NULL, 10);
-               if (y >= AIPTEK_TILT_MIN && y <= AIPTEK_TILT_MAX) {
-                       aiptek->newSetting.yTilt = y;
-               }
-       }
-       return count;
-}
-
-static DEVICE_ATTR(ytilt,
-                  S_IRUGO | S_IWUGO, show_tabletYtilt, store_tabletYtilt);
-
-/***********************************************************************
- * support routines for the 'jitter' file. Note that this file
- * both displays current setting and allows reprogramming.
- */
-static ssize_t show_tabletJitterDelay(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct aiptek *aiptek = dev_get_drvdata(dev);
-
-       if (aiptek == NULL)
-               return 0;
-
-       return snprintf(buf, PAGE_SIZE, "%d\n", aiptek->curSetting.jitterDelay);
-}
-
-static ssize_t
-store_tabletJitterDelay(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-       struct aiptek *aiptek = dev_get_drvdata(dev);
-
-       if (aiptek == NULL)
-               return 0;
-
-       aiptek->newSetting.jitterDelay = (int)simple_strtol(buf, NULL, 10);
-       return count;
-}
-
-static DEVICE_ATTR(jitter,
-                  S_IRUGO | S_IWUGO,
-                  show_tabletJitterDelay, store_tabletJitterDelay);
-
-/***********************************************************************
- * support routines for the 'delay' file. Note that this file
- * both displays current setting and allows reprogramming.
- */
-static ssize_t show_tabletProgrammableDelay(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct aiptek *aiptek = dev_get_drvdata(dev);
-
-       if (aiptek == NULL)
-               return 0;
-
-       return snprintf(buf, PAGE_SIZE, "%d\n",
-                       aiptek->curSetting.programmableDelay);
-}
-
-static ssize_t
-store_tabletProgrammableDelay(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-       struct aiptek *aiptek = dev_get_drvdata(dev);
-
-       if (aiptek == NULL)
-               return 0;
-
-       aiptek->newSetting.programmableDelay = (int)simple_strtol(buf, NULL, 10);
-       return count;
-}
-
-static DEVICE_ATTR(delay,
-                  S_IRUGO | S_IWUGO,
-                  show_tabletProgrammableDelay, store_tabletProgrammableDelay);
-
-/***********************************************************************
- * support routines for the 'input_path' file. Note that this file
- * only displays current setting.
- */
-static ssize_t show_tabletInputDevice(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct aiptek *aiptek = dev_get_drvdata(dev);
-
-       if (aiptek == NULL)
-               return 0;
-
-       return snprintf(buf, PAGE_SIZE, "/dev/input/%s\n",
-                       aiptek->features.inputPath);
-}
-
-static DEVICE_ATTR(input_path, S_IRUGO, show_tabletInputDevice, NULL);
-
-/***********************************************************************
- * support routines for the 'event_count' file. Note that this file
- * only displays current setting.
- */
-static ssize_t show_tabletEventsReceived(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct aiptek *aiptek = dev_get_drvdata(dev);
-
-       if (aiptek == NULL)
-               return 0;
-
-       return snprintf(buf, PAGE_SIZE, "%ld\n", aiptek->eventCount);
-}
-
-static DEVICE_ATTR(event_count, S_IRUGO, show_tabletEventsReceived, NULL);
-
-/***********************************************************************
- * support routines for the 'diagnostic' file. Note that this file
- * only displays current setting.
- */
-static ssize_t show_tabletDiagnosticMessage(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct aiptek *aiptek = dev_get_drvdata(dev);
-       char *retMsg;
-
-       if (aiptek == NULL)
-               return 0;
-
-       switch (aiptek->diagnostic) {
-       case AIPTEK_DIAGNOSTIC_NA:
-               retMsg = "no errors\n";
-               break;
-
-       case AIPTEK_DIAGNOSTIC_SENDING_RELATIVE_IN_ABSOLUTE:
-               retMsg = "Error: receiving relative reports\n";
-               break;
-
-       case AIPTEK_DIAGNOSTIC_SENDING_ABSOLUTE_IN_RELATIVE:
-               retMsg = "Error: receiving absolute reports\n";
-               break;
-
-       case AIPTEK_DIAGNOSTIC_TOOL_DISALLOWED:
-               if (aiptek->curSetting.pointerMode ==
-                   AIPTEK_POINTER_ONLY_MOUSE_MODE) {
-                       retMsg = "Error: receiving stylus reports\n";
-               } else {
-                       retMsg = "Error: receiving mouse reports\n";
-               }
-               break;
-
-       default:
-               return 0;
-       }
-       return snprintf(buf, PAGE_SIZE, retMsg);
-}
-
-static DEVICE_ATTR(diagnostic, S_IRUGO, show_tabletDiagnosticMessage, NULL);
-
-/***********************************************************************
- * support routines for the 'stylus_upper' file. Note that this file
- * both displays current setting and allows for setting changing.
- */
-static ssize_t show_tabletStylusUpper(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct aiptek *aiptek = dev_get_drvdata(dev);
-       char *s;
-
-       if (aiptek == NULL)
-               return 0;
-
-       switch (aiptek->curSetting.stylusButtonUpper) {
-       case AIPTEK_STYLUS_UPPER_BUTTON:
-               s = "upper";
-               break;
-
-       case AIPTEK_STYLUS_LOWER_BUTTON:
-               s = "lower";
-               break;
-
-       default:
-               s = "unknown";
-               break;
-       }
-       return snprintf(buf, PAGE_SIZE, "%s\n", s);
-}
-
-static ssize_t
-store_tabletStylusUpper(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-       struct aiptek *aiptek = dev_get_drvdata(dev);
-
-       if (aiptek == NULL)
-               return 0;
-
-       if (strcmp(buf, "upper") == 0) {
-               aiptek->newSetting.stylusButtonUpper =
-                   AIPTEK_STYLUS_UPPER_BUTTON;
-       } else if (strcmp(buf, "lower") == 0) {
-               aiptek->newSetting.stylusButtonUpper =
-                   AIPTEK_STYLUS_LOWER_BUTTON;
-       }
-       return count;
-}
-
-static DEVICE_ATTR(stylus_upper,
-                  S_IRUGO | S_IWUGO,
-                  show_tabletStylusUpper, store_tabletStylusUpper);
-
-/***********************************************************************
- * support routines for the 'stylus_lower' file. Note that this file
- * both displays current setting and allows for setting changing.
- */
-static ssize_t show_tabletStylusLower(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct aiptek *aiptek = dev_get_drvdata(dev);
-       char *s;
-
-       if (aiptek == NULL)
-               return 0;
-
-       switch (aiptek->curSetting.stylusButtonLower) {
-       case AIPTEK_STYLUS_UPPER_BUTTON:
-               s = "upper";
-               break;
-
-       case AIPTEK_STYLUS_LOWER_BUTTON:
-               s = "lower";
-               break;
-
-       default:
-               s = "unknown";
-               break;
-       }
-       return snprintf(buf, PAGE_SIZE, "%s\n", s);
-}
-
-static ssize_t
-store_tabletStylusLower(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-       struct aiptek *aiptek = dev_get_drvdata(dev);
-
-       if (aiptek == NULL)
-               return 0;
-
-       if (strcmp(buf, "upper") == 0) {
-               aiptek->newSetting.stylusButtonLower =
-                   AIPTEK_STYLUS_UPPER_BUTTON;
-       } else if (strcmp(buf, "lower") == 0) {
-               aiptek->newSetting.stylusButtonLower =
-                   AIPTEK_STYLUS_LOWER_BUTTON;
-       }
-       return count;
-}
-
-static DEVICE_ATTR(stylus_lower,
-                  S_IRUGO | S_IWUGO,
-                  show_tabletStylusLower, store_tabletStylusLower);
-
-/***********************************************************************
- * support routines for the 'mouse_left' file. Note that this file
- * both displays current setting and allows for setting changing.
- */
-static ssize_t show_tabletMouseLeft(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct aiptek *aiptek = dev_get_drvdata(dev);
-       char *s;
-
-       if (aiptek == NULL)
-               return 0;
-
-       switch (aiptek->curSetting.mouseButtonLeft) {
-       case AIPTEK_MOUSE_LEFT_BUTTON:
-               s = "left";
-               break;
-
-       case AIPTEK_MOUSE_MIDDLE_BUTTON:
-               s = "middle";
-               break;
-
-       case AIPTEK_MOUSE_RIGHT_BUTTON:
-               s = "right";
-               break;
-
-       default:
-               s = "unknown";
-               break;
-       }
-       return snprintf(buf, PAGE_SIZE, "%s\n", s);
-}
-
-static ssize_t
-store_tabletMouseLeft(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-       struct aiptek *aiptek = dev_get_drvdata(dev);
-
-       if (aiptek == NULL)
-               return 0;
-
-       if (strcmp(buf, "left") == 0) {
-               aiptek->newSetting.mouseButtonLeft = AIPTEK_MOUSE_LEFT_BUTTON;
-       } else if (strcmp(buf, "middle") == 0) {
-               aiptek->newSetting.mouseButtonLeft = AIPTEK_MOUSE_MIDDLE_BUTTON;
-       } else if (strcmp(buf, "right") == 0) {
-               aiptek->newSetting.mouseButtonLeft = AIPTEK_MOUSE_RIGHT_BUTTON;
-       }
-       return count;
-}
-
-static DEVICE_ATTR(mouse_left,
-                  S_IRUGO | S_IWUGO,
-                  show_tabletMouseLeft, store_tabletMouseLeft);
-
-/***********************************************************************
- * support routines for the 'mouse_middle' file. Note that this file
- * both displays current setting and allows for setting changing.
- */
-static ssize_t show_tabletMouseMiddle(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct aiptek *aiptek = dev_get_drvdata(dev);
-       char *s;
-
-       if (aiptek == NULL)
-               return 0;
-
-       switch (aiptek->curSetting.mouseButtonMiddle) {
-       case AIPTEK_MOUSE_LEFT_BUTTON:
-               s = "left";
-               break;
-
-       case AIPTEK_MOUSE_MIDDLE_BUTTON:
-               s = "middle";
-               break;
-
-       case AIPTEK_MOUSE_RIGHT_BUTTON:
-               s = "right";
-               break;
-
-       default:
-               s = "unknown";
-               break;
-       }
-       return snprintf(buf, PAGE_SIZE, "%s\n", s);
-}
-
-static ssize_t
-store_tabletMouseMiddle(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-       struct aiptek *aiptek = dev_get_drvdata(dev);
-
-       if (aiptek == NULL)
-               return 0;
-
-       if (strcmp(buf, "left") == 0) {
-               aiptek->newSetting.mouseButtonMiddle = AIPTEK_MOUSE_LEFT_BUTTON;
-       } else if (strcmp(buf, "middle") == 0) {
-               aiptek->newSetting.mouseButtonMiddle =
-                   AIPTEK_MOUSE_MIDDLE_BUTTON;
-       } else if (strcmp(buf, "right") == 0) {
-               aiptek->newSetting.mouseButtonMiddle =
-                   AIPTEK_MOUSE_RIGHT_BUTTON;
-       }
-       return count;
-}
-
-static DEVICE_ATTR(mouse_middle,
-                  S_IRUGO | S_IWUGO,
-                  show_tabletMouseMiddle, store_tabletMouseMiddle);
-
-/***********************************************************************
- * support routines for the 'mouse_right' file. Note that this file
- * both displays current setting and allows for setting changing.
- */
-static ssize_t show_tabletMouseRight(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct aiptek *aiptek = dev_get_drvdata(dev);
-       char *s;
-
-       if (aiptek == NULL)
-               return 0;
-
-       switch (aiptek->curSetting.mouseButtonRight) {
-       case AIPTEK_MOUSE_LEFT_BUTTON:
-               s = "left";
-               break;
-
-       case AIPTEK_MOUSE_MIDDLE_BUTTON:
-               s = "middle";
-               break;
-
-       case AIPTEK_MOUSE_RIGHT_BUTTON:
-               s = "right";
-               break;
-
-       default:
-               s = "unknown";
-               break;
-       }
-       return snprintf(buf, PAGE_SIZE, "%s\n", s);
-}
-
-static ssize_t
-store_tabletMouseRight(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-       struct aiptek *aiptek = dev_get_drvdata(dev);
-
-       if (aiptek == NULL)
-               return 0;
-
-       if (strcmp(buf, "left") == 0) {
-               aiptek->newSetting.mouseButtonRight = AIPTEK_MOUSE_LEFT_BUTTON;
-       } else if (strcmp(buf, "middle") == 0) {
-               aiptek->newSetting.mouseButtonRight =
-                   AIPTEK_MOUSE_MIDDLE_BUTTON;
-       } else if (strcmp(buf, "right") == 0) {
-               aiptek->newSetting.mouseButtonRight = AIPTEK_MOUSE_RIGHT_BUTTON;
-       }
-       return count;
-}
-
-static DEVICE_ATTR(mouse_right,
-                  S_IRUGO | S_IWUGO,
-                  show_tabletMouseRight, store_tabletMouseRight);
-
-/***********************************************************************
- * support routines for the 'wheel' file. Note that this file
- * both displays current setting and allows for setting changing.
- */
-static ssize_t show_tabletWheel(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct aiptek *aiptek = dev_get_drvdata(dev);
-
-       if (aiptek == NULL)
-               return 0;
-
-       if (aiptek->curSetting.wheel == AIPTEK_WHEEL_DISABLE) {
-               return snprintf(buf, PAGE_SIZE, "disable\n");
-       } else {
-               return snprintf(buf, PAGE_SIZE, "%d\n",
-                               aiptek->curSetting.wheel);
-       }
-}
-
-static ssize_t
-store_tabletWheel(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-       struct aiptek *aiptek = dev_get_drvdata(dev);
-
-       if (aiptek == NULL)
-               return 0;
-
-       aiptek->newSetting.wheel = (int)simple_strtol(buf, NULL, 10);
-       return count;
-}
-
-static DEVICE_ATTR(wheel,
-                  S_IRUGO | S_IWUGO, show_tabletWheel, store_tabletWheel);
-
-/***********************************************************************
- * support routines for the 'execute' file. Note that this file
- * both displays current setting and allows for setting changing.
- */
-static ssize_t show_tabletExecute(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct aiptek *aiptek = dev_get_drvdata(dev);
-
-       if (aiptek == NULL)
-               return 0;
-
-       /* There is nothing useful to display, so a one-line manual
-        * is in order...
-        */
-       return snprintf(buf, PAGE_SIZE,
-                       "Write anything to this file to program your tablet.\n");
-}
-
-static ssize_t
-store_tabletExecute(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
-       struct aiptek *aiptek = dev_get_drvdata(dev);
-
-       if (aiptek == NULL)
-               return 0;
-
-       /* We do not care what you write to this file. Merely the action
-        * of writing to this file triggers a tablet reprogramming.
-        */
-       memcpy(&aiptek->curSetting, &aiptek->newSetting,
-              sizeof(struct aiptek_settings));
-
-       if (aiptek_program_tablet(aiptek) < 0)
-               return -EIO;
-
-       return count;
-}
-
-static DEVICE_ATTR(execute,
-                  S_IRUGO | S_IWUGO, show_tabletExecute, store_tabletExecute);
-
-/***********************************************************************
- * support routines for the 'odm_code' file. Note that this file
- * only displays current setting.
- */
-static ssize_t show_tabletODMCode(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct aiptek *aiptek = dev_get_drvdata(dev);
-
-       if (aiptek == NULL)
-               return 0;
-
-       return snprintf(buf, PAGE_SIZE, "0x%04x\n", aiptek->features.odmCode);
-}
-
-static DEVICE_ATTR(odm_code, S_IRUGO, show_tabletODMCode, NULL);
-
-/***********************************************************************
- * support routines for the 'model_code' file. Note that this file
- * only displays current setting.
- */
-static ssize_t show_tabletModelCode(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct aiptek *aiptek = dev_get_drvdata(dev);
-
-       if (aiptek == NULL)
-               return 0;
-
-       return snprintf(buf, PAGE_SIZE, "0x%04x\n", aiptek->features.modelCode);
-}
-
-static DEVICE_ATTR(model_code, S_IRUGO, show_tabletModelCode, NULL);
-
-/***********************************************************************
- * support routines for the 'firmware_code' file. Note that this file
- * only displays current setting.
- */
-static ssize_t show_firmwareCode(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct aiptek *aiptek = dev_get_drvdata(dev);
-
-       if (aiptek == NULL)
-               return 0;
-
-       return snprintf(buf, PAGE_SIZE, "%04x\n",
-                       aiptek->features.firmwareCode);
-}
-
-static DEVICE_ATTR(firmware_code, S_IRUGO, show_firmwareCode, NULL);
-
-/***********************************************************************
- * This routine removes all existing sysfs files managed by this device
- * driver.
- */
-static void aiptek_delete_files(struct device *dev)
-{
-       device_remove_file(dev, &dev_attr_size);
-       device_remove_file(dev, &dev_attr_product_id);
-       device_remove_file(dev, &dev_attr_vendor_id);
-       device_remove_file(dev, &dev_attr_vendor);
-       device_remove_file(dev, &dev_attr_product);
-       device_remove_file(dev, &dev_attr_pointer_mode);
-       device_remove_file(dev, &dev_attr_coordinate_mode);
-       device_remove_file(dev, &dev_attr_tool_mode);
-       device_remove_file(dev, &dev_attr_xtilt);
-       device_remove_file(dev, &dev_attr_ytilt);
-       device_remove_file(dev, &dev_attr_jitter);
-       device_remove_file(dev, &dev_attr_delay);
-       device_remove_file(dev, &dev_attr_input_path);
-       device_remove_file(dev, &dev_attr_event_count);
-       device_remove_file(dev, &dev_attr_diagnostic);
-       device_remove_file(dev, &dev_attr_odm_code);
-       device_remove_file(dev, &dev_attr_model_code);
-       device_remove_file(dev, &dev_attr_firmware_code);
-       device_remove_file(dev, &dev_attr_stylus_lower);
-       device_remove_file(dev, &dev_attr_stylus_upper);
-       device_remove_file(dev, &dev_attr_mouse_left);
-       device_remove_file(dev, &dev_attr_mouse_middle);
-       device_remove_file(dev, &dev_attr_mouse_right);
-       device_remove_file(dev, &dev_attr_wheel);
-       device_remove_file(dev, &dev_attr_execute);
-}
-
-/***********************************************************************
- * This routine creates the sysfs files managed by this device
- * driver.
- */
-static int aiptek_add_files(struct device *dev)
-{
-       int ret;
-
-       if ((ret = device_create_file(dev, &dev_attr_size)) ||
-           (ret = device_create_file(dev, &dev_attr_product_id)) ||
-           (ret = device_create_file(dev, &dev_attr_vendor_id)) ||
-           (ret = device_create_file(dev, &dev_attr_vendor)) ||
-           (ret = device_create_file(dev, &dev_attr_product)) ||
-           (ret = device_create_file(dev, &dev_attr_pointer_mode)) ||
-           (ret = device_create_file(dev, &dev_attr_coordinate_mode)) ||
-           (ret = device_create_file(dev, &dev_attr_tool_mode)) ||
-           (ret = device_create_file(dev, &dev_attr_xtilt)) ||
-           (ret = device_create_file(dev, &dev_attr_ytilt)) ||
-           (ret = device_create_file(dev, &dev_attr_jitter)) ||
-           (ret = device_create_file(dev, &dev_attr_delay)) ||
-           (ret = device_create_file(dev, &dev_attr_input_path)) ||
-           (ret = device_create_file(dev, &dev_attr_event_count)) ||
-           (ret = device_create_file(dev, &dev_attr_diagnostic)) ||
-           (ret = device_create_file(dev, &dev_attr_odm_code)) ||
-           (ret = device_create_file(dev, &dev_attr_model_code)) ||
-           (ret = device_create_file(dev, &dev_attr_firmware_code)) ||
-           (ret = device_create_file(dev, &dev_attr_stylus_lower)) ||
-           (ret = device_create_file(dev, &dev_attr_stylus_upper)) ||
-           (ret = device_create_file(dev, &dev_attr_mouse_left)) ||
-           (ret = device_create_file(dev, &dev_attr_mouse_middle)) ||
-           (ret = device_create_file(dev, &dev_attr_mouse_right)) ||
-           (ret = device_create_file(dev, &dev_attr_wheel)) ||
-           (ret = device_create_file(dev, &dev_attr_execute))) {
-               err("aiptek: killing own sysfs device files\n");
-               aiptek_delete_files(dev);
-       }
-       return ret;
-}
-
-/***********************************************************************
- * This routine is called when a tablet has been identified. It basically
- * sets up the tablet and the driver's internal structures.
- */
-static int
-aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id)
-{
-       struct usb_device *usbdev = interface_to_usbdev(intf);
-       struct usb_endpoint_descriptor *endpoint;
-       struct aiptek *aiptek;
-       struct input_dev *inputdev;
-       struct input_handle *inputhandle;
-       struct list_head *node, *next;
-       int i;
-       int speeds[] = { 0,
-               AIPTEK_PROGRAMMABLE_DELAY_50,
-               AIPTEK_PROGRAMMABLE_DELAY_400,
-               AIPTEK_PROGRAMMABLE_DELAY_25,
-               AIPTEK_PROGRAMMABLE_DELAY_100,
-               AIPTEK_PROGRAMMABLE_DELAY_200,
-               AIPTEK_PROGRAMMABLE_DELAY_300
-       };
-       int err = -ENOMEM;
-
-       /* programmableDelay is where the command-line specified
-        * delay is kept. We make it the first element of speeds[],
-        * so therefore, your override speed is tried first, then the
-        * remainder. Note that the default value of 400ms will be tried
-        * if you do not specify any command line parameter.
-        */
-       speeds[0] = programmableDelay;
-
-       aiptek = kzalloc(sizeof(struct aiptek), GFP_KERNEL);
-       inputdev = input_allocate_device();
-       if (!aiptek || !inputdev)
-               goto fail1;
-
-       aiptek->data = usb_buffer_alloc(usbdev, AIPTEK_PACKET_LENGTH,
-                                       GFP_ATOMIC, &aiptek->data_dma);
-       if (!aiptek->data)
-               goto fail1;
-
-       aiptek->urb = usb_alloc_urb(0, GFP_KERNEL);
-       if (!aiptek->urb)
-               goto fail2;
-
-       aiptek->inputdev = inputdev;
-       aiptek->usbdev = usbdev;
-       aiptek->ifnum = intf->altsetting[0].desc.bInterfaceNumber;
-       aiptek->inDelay = 0;
-       aiptek->endDelay = 0;
-       aiptek->previousJitterable = 0;
-
-       /* Set up the curSettings struct. Said struct contains the current
-        * programmable parameters. The newSetting struct contains changes
-        * the user makes to the settings via the sysfs interface. Those
-        * changes are not "committed" to curSettings until the user
-        * writes to the sysfs/.../execute file.
-        */
-       aiptek->curSetting.pointerMode = AIPTEK_POINTER_EITHER_MODE;
-       aiptek->curSetting.coordinateMode = AIPTEK_COORDINATE_ABSOLUTE_MODE;
-       aiptek->curSetting.toolMode = AIPTEK_TOOL_BUTTON_PEN_MODE;
-       aiptek->curSetting.xTilt = AIPTEK_TILT_DISABLE;
-       aiptek->curSetting.yTilt = AIPTEK_TILT_DISABLE;
-       aiptek->curSetting.mouseButtonLeft = AIPTEK_MOUSE_LEFT_BUTTON;
-       aiptek->curSetting.mouseButtonMiddle = AIPTEK_MOUSE_MIDDLE_BUTTON;
-       aiptek->curSetting.mouseButtonRight = AIPTEK_MOUSE_RIGHT_BUTTON;
-       aiptek->curSetting.stylusButtonUpper = AIPTEK_STYLUS_UPPER_BUTTON;
-       aiptek->curSetting.stylusButtonLower = AIPTEK_STYLUS_LOWER_BUTTON;
-       aiptek->curSetting.jitterDelay = jitterDelay;
-       aiptek->curSetting.programmableDelay = programmableDelay;
-
-       /* Both structs should have equivalent settings
-        */
-       aiptek->newSetting = aiptek->curSetting;
-
-       /* Determine the usb devices' physical path.
-        * Asketh not why we always pretend we're using "../input0",
-        * but I suspect this will have to be refactored one
-        * day if a single USB device can be a keyboard & a mouse
-        * & a tablet, and the inputX number actually will tell
-        * us something...
-        */
-       usb_make_path(usbdev, aiptek->features.usbPath,
-                       sizeof(aiptek->features.usbPath));
-       strlcat(aiptek->features.usbPath, "/input0",
-               sizeof(aiptek->features.usbPath));
-
-       /* Set up client data, pointers to open and close routines
-        * for the input device.
-        */
-       inputdev->name = "Aiptek";
-       inputdev->phys = aiptek->features.usbPath;
-       usb_to_input_id(usbdev, &inputdev->id);
-       inputdev->dev.parent = &intf->dev;
-
-       input_set_drvdata(inputdev, aiptek);
-
-       inputdev->open = aiptek_open;
-       inputdev->close = aiptek_close;
-
-       /* Now program the capacities of the tablet, in terms of being
-        * an input device.
-        */
-       inputdev->evbit[0] |= BIT(EV_KEY)
-           | BIT(EV_ABS)
-           | BIT(EV_REL)
-           | BIT(EV_MSC);
-
-       inputdev->absbit[0] |= BIT(ABS_MISC);
-
-       inputdev->relbit[0] |=
-           (BIT(REL_X) | BIT(REL_Y) | BIT(REL_WHEEL) | BIT(REL_MISC));
-
-       inputdev->keybit[LONG(BTN_LEFT)] |=
-           (BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE));
-
-       inputdev->keybit[LONG(BTN_DIGI)] |=
-           (BIT(BTN_TOOL_PEN) |
-            BIT(BTN_TOOL_RUBBER) |
-            BIT(BTN_TOOL_PENCIL) |
-            BIT(BTN_TOOL_AIRBRUSH) |
-            BIT(BTN_TOOL_BRUSH) |
-            BIT(BTN_TOOL_MOUSE) |
-            BIT(BTN_TOOL_LENS) |
-            BIT(BTN_TOUCH) | BIT(BTN_STYLUS) | BIT(BTN_STYLUS2));
-
-       inputdev->mscbit[0] = BIT(MSC_SERIAL);
-
-       /* Programming the tablet macro keys needs to be done with a for loop
-        * as the keycodes are discontiguous.
-        */
-       for (i = 0; i < ARRAY_SIZE(macroKeyEvents); ++i)
-               set_bit(macroKeyEvents[i], inputdev->keybit);
-
-       /*
-        * Program the input device coordinate capacities. We do not yet
-        * know what maximum X, Y, and Z values are, so we're putting fake
-        * values in. Later, we'll ask the tablet to put in the correct
-        * values.
-        */
-       input_set_abs_params(inputdev, ABS_X, 0, 2999, 0, 0);
-       input_set_abs_params(inputdev, ABS_Y, 0, 2249, 0, 0);
-       input_set_abs_params(inputdev, ABS_PRESSURE, 0, 511, 0, 0);
-       input_set_abs_params(inputdev, ABS_TILT_X, AIPTEK_TILT_MIN, AIPTEK_TILT_MAX, 0, 0);
-       input_set_abs_params(inputdev, ABS_TILT_Y, AIPTEK_TILT_MIN, AIPTEK_TILT_MAX, 0, 0);
-       input_set_abs_params(inputdev, ABS_WHEEL, AIPTEK_WHEEL_MIN, AIPTEK_WHEEL_MAX - 1, 0, 0);
-
-       endpoint = &intf->altsetting[0].endpoint[0].desc;
-
-       /* Go set up our URB, which is called when the tablet receives
-        * input.
-        */
-       usb_fill_int_urb(aiptek->urb,
-                        aiptek->usbdev,
-                        usb_rcvintpipe(aiptek->usbdev,
-                                       endpoint->bEndpointAddress),
-                        aiptek->data, 8, aiptek_irq, aiptek,
-                        endpoint->bInterval);
-
-       aiptek->urb->transfer_dma = aiptek->data_dma;
-       aiptek->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-
-       /* Program the tablet. This sets the tablet up in the mode
-        * specified in newSetting, and also queries the tablet's
-        * physical capacities.
-        *
-        * Sanity check: if a tablet doesn't like the slow programmatic
-        * delay, we often get sizes of 0x0. Let's use that as an indicator
-        * to try faster delays, up to 25 ms. If that logic fails, well, you'll
-        * have to explain to us how your tablet thinks it's 0x0, and yet that's
-        * not an error :-)
-        */
-
-       for (i = 0; i < ARRAY_SIZE(speeds); ++i) {
-               aiptek->curSetting.programmableDelay = speeds[i];
-               (void)aiptek_program_tablet(aiptek);
-               if (aiptek->inputdev->absmax[ABS_X] > 0) {
-                       info("input: Aiptek using %d ms programming speed\n",
-                            aiptek->curSetting.programmableDelay);
-                       break;
-               }
-       }
-
-       /* Register the tablet as an Input Device
-        */
-       err = input_register_device(aiptek->inputdev);
-       if (err)
-               goto fail2;
-
-       /* We now will look for the evdev device which is mapped to
-        * the tablet. The partial name is kept in the link list of
-        * input_handles associated with this input device.
-        * What identifies an evdev input_handler is that it begins
-        * with 'event', continues with a digit, and that in turn
-        * is mapped to input/eventN.
-        */
-       list_for_each_safe(node, next, &inputdev->h_list) {
-               inputhandle = to_handle(node);
-               if (strncmp(inputhandle->name, "event", 5) == 0) {
-                       strcpy(aiptek->features.inputPath, inputhandle->name);
-                       break;
-               }
-       }
-
-       /* Associate this driver's struct with the usb interface.
-        */
-       usb_set_intfdata(intf, aiptek);
-
-       /* Set up the sysfs files
-        */
-       aiptek_add_files(&intf->dev);
-
-       /* Make sure the evdev module is loaded. Assuming evdev IS a module :-)
-        */
-       if (request_module("evdev") != 0)
-               info("aiptek: error loading 'evdev' module");
-
-       return 0;
-
- fail2:        usb_buffer_free(usbdev, AIPTEK_PACKET_LENGTH, aiptek->data,
-                       aiptek->data_dma);
- fail1:        input_free_device(inputdev);
-       kfree(aiptek);
-       return err;
-}
-
-/***********************************************************************
- * Deal with tablet disconnecting from the system.
- */
-static void aiptek_disconnect(struct usb_interface *intf)
-{
-       struct aiptek *aiptek = usb_get_intfdata(intf);
-
-       /* Disassociate driver's struct with usb interface
-        */
-       usb_set_intfdata(intf, NULL);
-       if (aiptek != NULL) {
-               /* Free & unhook everything from the system.
-                */
-               usb_kill_urb(aiptek->urb);
-               input_unregister_device(aiptek->inputdev);
-               aiptek_delete_files(&intf->dev);
-               usb_free_urb(aiptek->urb);
-               usb_buffer_free(interface_to_usbdev(intf),
-                               AIPTEK_PACKET_LENGTH,
-                               aiptek->data, aiptek->data_dma);
-               kfree(aiptek);
-       }
-}
-
-static struct usb_driver aiptek_driver = {
-       .name = "aiptek",
-       .probe = aiptek_probe,
-       .disconnect = aiptek_disconnect,
-       .id_table = aiptek_ids,
-};
-
-static int __init aiptek_init(void)
-{
-       int result = usb_register(&aiptek_driver);
-       if (result == 0) {
-               info(DRIVER_VERSION ": " DRIVER_AUTHOR);
-               info(DRIVER_DESC);
-       }
-       return result;
-}
-
-static void __exit aiptek_exit(void)
-{
-       usb_deregister(&aiptek_driver);
-}
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
-
-module_param(programmableDelay, int, 0);
-MODULE_PARM_DESC(programmableDelay, "delay used during tablet programming");
-module_param(jitterDelay, int, 0);
-MODULE_PARM_DESC(jitterDelay, "stylus/mouse settlement delay");
-
-module_init(aiptek_init);
-module_exit(aiptek_exit);
diff --git a/drivers/usb/input/gtco.c b/drivers/usb/input/gtco.c
deleted file mode 100644 (file)
index b2ca10f..0000000
+++ /dev/null
@@ -1,1055 +0,0 @@
-/*    -*- linux-c -*-
-
-GTCO digitizer USB driver
-
-Use the err(), dbg() and info() macros from usb.h for system logging
-
-TO CHECK:  Is pressure done right on report 5?
-
-Copyright (C) 2006  GTCO CalComp
-
-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; version 2
-of the License.
-
-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.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-
-Permission to use, copy, modify, distribute, and sell this software and its
-documentation for any purpose is hereby granted without fee, provided that
-the above copyright notice appear in all copies and that both that
-copyright notice and this permission notice appear in supporting
-documentation, and that the name of GTCO-CalComp not be used in advertising
-or publicity pertaining to distribution of the software without specific,
-written prior permission. GTCO-CalComp makes no representations about the
-suitability of this software for any purpose.  It is provided "as is"
-without express or implied warranty.
-
-GTCO-CALCOMP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
-INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
-EVENT SHALL GTCO-CALCOMP BE LIABLE FOR ANY SPECIAL, INDIRECT OR
-CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
-DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
-TORTIOUS ACTIONS, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-PERFORMANCE OF THIS SOFTWARE.
-
-GTCO CalComp, Inc.
-7125 Riverwood Drive
-Columbia, MD 21046
-
-Jeremy Roberson jroberson@gtcocalcomp.com
-Scott Hill shill@gtcocalcomp.com
-*/
-
-
-
-/*#define DEBUG*/
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/input.h>
-#include <linux/usb.h>
-#include <asm/uaccess.h>
-#include <asm/unaligned.h>
-#include <asm/byteorder.h>
-
-
-#include <linux/version.h>
-#include <linux/usb/input.h>
-
-/* Version with a Major number of 2 is for kernel inclusion only. */
-#define  GTCO_VERSION   "2.00.0006"
-
-
-/*   MACROS  */
-
-#define VENDOR_ID_GTCO       0x078C
-#define PID_400               0x400
-#define PID_401               0x401
-#define PID_1000              0x1000
-#define PID_1001              0x1001
-#define PID_1002              0x1002
-
-/* Max size of a single report */
-#define REPORT_MAX_SIZE       10
-
-
-/* Bitmask whether pen is in range */
-#define MASK_INRANGE 0x20
-#define MASK_BUTTON  0x01F
-
-#define  PATHLENGTH     64
-
-/* DATA STRUCTURES */
-
-/* Device table */
-static struct usb_device_id gtco_usbid_table [] = {
-       { USB_DEVICE(VENDOR_ID_GTCO, PID_400) },
-       { USB_DEVICE(VENDOR_ID_GTCO, PID_401) },
-       { USB_DEVICE(VENDOR_ID_GTCO, PID_1000) },
-       { USB_DEVICE(VENDOR_ID_GTCO, PID_1001) },
-       { USB_DEVICE(VENDOR_ID_GTCO, PID_1002) },
-       { }
-};
-MODULE_DEVICE_TABLE (usb, gtco_usbid_table);
-
-
-/* Structure to hold all of our device specific stuff */
-struct gtco {
-
-       struct input_dev  *inputdevice; /* input device struct pointer  */
-       struct usb_device *usbdev; /* the usb device for this device */
-       struct urb        *urbinfo;      /* urb for incoming reports      */
-       dma_addr_t        buf_dma;  /* dma addr of the data buffer*/
-       unsigned char *   buffer;   /* databuffer for reports */
-
-       char  usbpath[PATHLENGTH];
-       int   openCount;
-
-       /* Information pulled from Report Descriptor */
-       u32  usage;
-       u32  min_X;
-       u32  max_X;
-       u32  min_Y;
-       u32  max_Y;
-       s8   mintilt_X;
-       s8   maxtilt_X;
-       s8   mintilt_Y;
-       s8   maxtilt_Y;
-       u32  maxpressure;
-       u32  minpressure;
-};
-
-
-
-/*   Code for parsing the HID REPORT DESCRIPTOR          */
-
-/* From HID1.11 spec */
-struct hid_descriptor
-{
-       struct usb_descriptor_header header;
-       __le16   bcdHID;
-       u8       bCountryCode;
-       u8       bNumDescriptors;
-       u8       bDescriptorType;
-       __le16   wDescriptorLength;
-} __attribute__ ((packed));
-
-
-#define HID_DESCRIPTOR_SIZE   9
-#define HID_DEVICE_TYPE       33
-#define REPORT_DEVICE_TYPE    34
-
-
-#define PREF_TAG(x)     ((x)>>4)
-#define PREF_TYPE(x)    ((x>>2)&0x03)
-#define PREF_SIZE(x)    ((x)&0x03)
-
-#define TYPE_MAIN       0
-#define TYPE_GLOBAL     1
-#define TYPE_LOCAL      2
-#define TYPE_RESERVED   3
-
-#define TAG_MAIN_INPUT        0x8
-#define TAG_MAIN_OUTPUT       0x9
-#define TAG_MAIN_FEATURE      0xB
-#define TAG_MAIN_COL_START    0xA
-#define TAG_MAIN_COL_END      0xC
-
-#define TAG_GLOB_USAGE        0
-#define TAG_GLOB_LOG_MIN      1
-#define TAG_GLOB_LOG_MAX      2
-#define TAG_GLOB_PHYS_MIN     3
-#define TAG_GLOB_PHYS_MAX     4
-#define TAG_GLOB_UNIT_EXP     5
-#define TAG_GLOB_UNIT         6
-#define TAG_GLOB_REPORT_SZ    7
-#define TAG_GLOB_REPORT_ID    8
-#define TAG_GLOB_REPORT_CNT   9
-#define TAG_GLOB_PUSH         10
-#define TAG_GLOB_POP          11
-
-#define TAG_GLOB_MAX          12
-
-#define DIGITIZER_USAGE_TIP_PRESSURE   0x30
-#define DIGITIZER_USAGE_TILT_X         0x3D
-#define DIGITIZER_USAGE_TILT_Y         0x3E
-
-
-/*
- *   This is an abbreviated parser for the HID Report Descriptor.  We
- *   know what devices we are talking to, so this is by no means meant
- *   to be generic.  We can make some safe assumptions:
- *
- *   - We know there are no LONG tags, all short
- *   - We know that we have no MAIN Feature and MAIN Output items
- *   - We know what the IRQ reports are supposed to look like.
- *
- *   The main purpose of this is to use the HID report desc to figure
- *   out the mins and maxs of the fields in the IRQ reports.  The IRQ
- *   reports for 400/401 change slightly if the max X is bigger than 64K.
- *
- */
-static void parse_hid_report_descriptor(struct gtco *device, char * report,
-                                       int length)
-{
-       int   x, i = 0;
-
-       /* Tag primitive vars */
-       __u8   prefix;
-       __u8   size;
-       __u8   tag;
-       __u8   type;
-       __u8   data   = 0;
-       __u16  data16 = 0;
-       __u32  data32 = 0;
-
-       /* For parsing logic */
-       int   inputnum = 0;
-       __u32 usage = 0;
-
-       /* Global Values, indexed by TAG */
-       __u32 globalval[TAG_GLOB_MAX];
-       __u32 oldval[TAG_GLOB_MAX];
-
-       /* Debug stuff */
-       char  maintype = 'x';
-       char  globtype[12];
-       int   indent = 0;
-       char  indentstr[10] = "";
-
-
-       dbg("======>>>>>>PARSE<<<<<<======");
-
-       /* Walk  this report and pull out the info we need */
-       while (i < length) {
-               prefix = report[i];
-
-               /* Skip over prefix */
-               i++;
-
-               /* Determine data size and save the data in the proper variable */
-               size = PREF_SIZE(prefix);
-               switch (size) {
-               case 1:
-                       data = report[i];
-                       break;
-               case 2:
-                       data16 = le16_to_cpu(get_unaligned((__le16 *)&report[i]));
-                       break;
-               case 3:
-                       size = 4;
-                       data32 = le32_to_cpu(get_unaligned((__le32 *)&report[i]));
-                       break;
-               }
-
-               /* Skip size of data */
-               i += size;
-
-               /* What we do depends on the tag type */
-               tag  = PREF_TAG(prefix);
-               type = PREF_TYPE(prefix);
-               switch (type) {
-               case TYPE_MAIN:
-                       strcpy(globtype, "");
-                       switch (tag) {
-
-                       case TAG_MAIN_INPUT:
-                               /*
-                                * The INPUT MAIN tag signifies this is
-                                * information from a report.  We need to
-                                * figure out what it is and store the
-                                * min/max values
-                                */
-
-                               maintype = 'I';
-                               if (data == 2)
-                                       strcpy(globtype, "Variable");
-                               else if (data == 3)
-                                       strcpy(globtype, "Var|Const");
-
-                               dbg("::::: Saving Report: %d input #%d Max: 0x%X(%d) Min:0x%X(%d) of %d bits",
-                                   globalval[TAG_GLOB_REPORT_ID], inputnum,
-                                   globalval[TAG_GLOB_LOG_MAX], globalval[TAG_GLOB_LOG_MAX],
-                                   globalval[TAG_GLOB_LOG_MIN], globalval[TAG_GLOB_LOG_MIN],
-                                   globalval[TAG_GLOB_REPORT_SZ] * globalval[TAG_GLOB_REPORT_CNT]);
-
-
-                               /*
-                                 We can assume that the first two input items
-                                 are always the X and Y coordinates.  After
-                                 that, we look for everything else by
-                                 local usage value
-                                */
-                               switch (inputnum) {
-                               case 0:  /* X coord */
-                                       dbg("GER: X Usage: 0x%x", usage);
-                                       if (device->max_X == 0) {
-                                               device->max_X = globalval[TAG_GLOB_LOG_MAX];
-                                               device->min_X = globalval[TAG_GLOB_LOG_MIN];
-                                       }
-                                       break;
-
-                               case 1:  /* Y coord */
-                                       dbg("GER: Y Usage: 0x%x", usage);
-                                       if (device->max_Y == 0) {
-                                               device->max_Y = globalval[TAG_GLOB_LOG_MAX];
-                                               device->min_Y = globalval[TAG_GLOB_LOG_MIN];
-                                       }
-                                       break;
-
-                               default:
-                                       /* Tilt X */
-                                       if (usage == DIGITIZER_USAGE_TILT_X) {
-                                               if (device->maxtilt_X == 0) {
-                                                       device->maxtilt_X = globalval[TAG_GLOB_LOG_MAX];
-                                                       device->mintilt_X = globalval[TAG_GLOB_LOG_MIN];
-                                               }
-                                       }
-
-                                       /* Tilt Y */
-                                       if (usage == DIGITIZER_USAGE_TILT_Y) {
-                                               if (device->maxtilt_Y == 0) {
-                                                       device->maxtilt_Y = globalval[TAG_GLOB_LOG_MAX];
-                                                       device->mintilt_Y = globalval[TAG_GLOB_LOG_MIN];
-                                               }
-                                       }
-
-                                       /* Pressure */
-                                       if (usage == DIGITIZER_USAGE_TIP_PRESSURE) {
-                                               if (device->maxpressure == 0) {
-                                                       device->maxpressure = globalval[TAG_GLOB_LOG_MAX];
-                                                       device->minpressure = globalval[TAG_GLOB_LOG_MIN];
-                                               }
-                                       }
-
-                                       break;
-                               }
-
-                               inputnum++;
-                               break;
-
-                       case TAG_MAIN_OUTPUT:
-                               maintype = 'O';
-                               break;
-
-                       case TAG_MAIN_FEATURE:
-                               maintype = 'F';
-                               break;
-
-                       case TAG_MAIN_COL_START:
-                               maintype = 'S';
-
-                               if (data == 0) {
-                                       dbg("======>>>>>> Physical");
-                                       strcpy(globtype, "Physical");
-                               } else
-                                       dbg("======>>>>>>");
-
-                               /* Indent the debug output */
-                               indent++;
-                               for (x = 0; x < indent; x++)
-                                       indentstr[x] = '-';
-                               indentstr[x] = 0;
-
-                               /* Save global tags */
-                               for (x = 0; x < TAG_GLOB_MAX; x++)
-                                       oldval[x] = globalval[x];
-
-                               break;
-
-                       case TAG_MAIN_COL_END:
-                               dbg("<<<<<<======");
-                               maintype = 'E';
-                               indent--;
-                               for (x = 0; x < indent; x++)
-                                       indentstr[x] = '-';
-                               indentstr[x] = 0;
-
-                               /* Copy global tags back */
-                               for (x = 0; x < TAG_GLOB_MAX; x++)
-                                       globalval[x] = oldval[x];
-
-                               break;
-                       }
-
-                       switch (size) {
-                       case 1:
-                               dbg("%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x",
-                                   indentstr, tag, maintype, size, globtype, data);
-                               break;
-
-                       case 2:
-                               dbg("%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x",
-                                   indentstr, tag, maintype, size, globtype, data16);
-                               break;
-
-                       case 4:
-                               dbg("%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x",
-                                   indentstr, tag, maintype, size, globtype, data32);
-                               break;
-                       }
-                       break;
-
-               case TYPE_GLOBAL:
-                       switch (tag) {
-                       case TAG_GLOB_USAGE:
-                               /*
-                                * First time we hit the global usage tag,
-                                * it should tell us the type of device
-                                */
-                               if (device->usage == 0)
-                                       device->usage = data;
-
-                               strcpy(globtype, "USAGE");
-                               break;
-
-                       case TAG_GLOB_LOG_MIN:
-                               strcpy(globtype, "LOG_MIN");
-                               break;
-
-                       case TAG_GLOB_LOG_MAX:
-                               strcpy(globtype, "LOG_MAX");
-                               break;
-
-                       case TAG_GLOB_PHYS_MIN:
-                               strcpy(globtype, "PHYS_MIN");
-                               break;
-
-                       case TAG_GLOB_PHYS_MAX:
-                               strcpy(globtype, "PHYS_MAX");
-                               break;
-
-                       case TAG_GLOB_UNIT_EXP:
-                               strcpy(globtype, "EXP");
-                               break;
-
-                       case TAG_GLOB_UNIT:
-                               strcpy(globtype, "UNIT");
-                               break;
-
-                       case TAG_GLOB_REPORT_SZ:
-                               strcpy(globtype, "REPORT_SZ");
-                               break;
-
-                       case TAG_GLOB_REPORT_ID:
-                               strcpy(globtype, "REPORT_ID");
-                               /* New report, restart numbering */
-                               inputnum = 0;
-                               break;
-
-                       case TAG_GLOB_REPORT_CNT:
-                               strcpy(globtype, "REPORT_CNT");
-                               break;
-
-                       case TAG_GLOB_PUSH:
-                               strcpy(globtype, "PUSH");
-                               break;
-
-                       case TAG_GLOB_POP:
-                               strcpy(globtype, "POP");
-                               break;
-                       }
-
-                       /* Check to make sure we have a good tag number
-                          so we don't overflow array */
-                       if (tag < TAG_GLOB_MAX) {
-                               switch (size) {
-                               case 1:
-                                       dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",
-                                           indentstr, globtype, tag, size, data);
-                                       globalval[tag] = data;
-                                       break;
-
-                               case 2:
-                                       dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",
-                                           indentstr, globtype, tag, size, data16);
-                                       globalval[tag] = data16;
-                                       break;
-
-                               case 4:
-                                       dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",
-                                           indentstr, globtype, tag, size, data32);
-                                       globalval[tag] = data32;
-                                       break;
-                               }
-                       } else {
-                               dbg("%sGLOBALTAG: ILLEGAL TAG:%d SIZE: %d ",
-                                   indentstr, tag, size);
-                       }
-                       break;
-
-               case TYPE_LOCAL:
-                       switch (tag) {
-                       case TAG_GLOB_USAGE:
-                               strcpy(globtype, "USAGE");
-                               /* Always 1 byte */
-                               usage = data;
-                               break;
-
-                       case TAG_GLOB_LOG_MIN:
-                               strcpy(globtype, "MIN");
-                               break;
-
-                       case TAG_GLOB_LOG_MAX:
-                               strcpy(globtype, "MAX");
-                               break;
-
-                       default:
-                               strcpy(globtype, "UNKNOWN");
-                               break;
-                       }
-
-                       switch (size) {
-                       case 1:
-                               dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x",
-                                   indentstr, tag, globtype, size, data);
-                               break;
-
-                       case 2:
-                               dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x",
-                                   indentstr, tag, globtype, size, data16);
-                               break;
-
-                       case 4:
-                               dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x",
-                                   indentstr, tag, globtype, size, data32);
-                               break;
-                       }
-
-                       break;
-               }
-       }
-}
-
-/*   INPUT DRIVER Routines                               */
-
-/*
- * Called when opening the input device.  This will submit the URB to
- * the usb system so we start getting reports
- */
-static int gtco_input_open(struct input_dev *inputdev)
-{
-       struct gtco *device = input_get_drvdata(inputdev);
-
-       device->urbinfo->dev = device->usbdev;
-       if (usb_submit_urb(device->urbinfo, GFP_KERNEL))
-               return -EIO;
-
-       return 0;
-}
-
-/*
- * Called when closing the input device.  This will unlink the URB
- */
-static void gtco_input_close(struct input_dev *inputdev)
-{
-       struct gtco *device = input_get_drvdata(inputdev);
-
-       usb_kill_urb(device->urbinfo);
-}
-
-
-/*
- *  Setup input device capabilities.  Tell the input system what this
- *  device is capable of generating.
- *
- *  This information is based on what is read from the HID report and
- *  placed in the struct gtco structure
- *
- */
-static void gtco_setup_caps(struct input_dev *inputdev)
-{
-       struct gtco *device = input_get_drvdata(inputdev);
-
-       /* Which events */
-       inputdev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_MSC);
-
-       /* Misc event menu block */
-       inputdev->mscbit[0] = BIT(MSC_SCAN)|BIT(MSC_SERIAL)|BIT(MSC_RAW) ;
-
-       /* Absolute values based on HID report info */
-       input_set_abs_params(inputdev, ABS_X, device->min_X, device->max_X,
-                            0, 0);
-       input_set_abs_params(inputdev, ABS_Y, device->min_Y, device->max_Y,
-                            0, 0);
-
-       /* Proximity */
-       input_set_abs_params(inputdev, ABS_DISTANCE, 0, 1, 0, 0);
-
-       /* Tilt & pressure */
-       input_set_abs_params(inputdev, ABS_TILT_X, device->mintilt_X,
-                            device->maxtilt_X, 0, 0);
-       input_set_abs_params(inputdev, ABS_TILT_Y, device->mintilt_Y,
-                            device->maxtilt_Y, 0, 0);
-       input_set_abs_params(inputdev, ABS_PRESSURE, device->minpressure,
-                            device->maxpressure, 0, 0);
-
-       /* Transducer */
-       input_set_abs_params(inputdev, ABS_MISC, 0, 0xFF, 0, 0);
-}
-
-/*   USB Routines  */
-
-/*
- * URB callback routine.  Called when we get IRQ reports from the
- *  digitizer.
- *
- *  This bridges the USB and input device worlds.  It generates events
- *  on the input device based on the USB reports.
- */
-static void gtco_urb_callback(struct urb *urbinfo)
-{
-       struct gtco *device = urbinfo->context;
-       struct input_dev  *inputdev;
-       int               rc;
-       u32               val = 0;
-       s8                valsigned = 0;
-       char              le_buffer[2];
-
-       inputdev = device->inputdevice;
-
-       /* Was callback OK? */
-       if (urbinfo->status == -ECONNRESET ||
-           urbinfo->status == -ENOENT ||
-           urbinfo->status == -ESHUTDOWN) {
-
-               /* Shutdown is occurring. Return and don't queue up any more */
-               return;
-       }
-
-       if (urbinfo->status != 0) {
-               /*
-                * Some unknown error.  Hopefully temporary. Just go and
-                * requeue an URB
-                */
-               goto resubmit;
-       }
-
-       /*
-        * Good URB, now process
-        */
-
-       /* PID dependent when we interpret the report */
-       if (inputdev->id.product == PID_1000 ||
-           inputdev->id.product == PID_1001 ||
-           inputdev->id.product == PID_1002) {
-
-               /*
-                * Switch on the report ID
-                * Conveniently, the reports have more information, the higher
-                * the report number.  We can just fall through the case
-                * statements if we start with the highest number report
-                */
-               switch (device->buffer[0]) {
-               case 5:
-                       /* Pressure is 9 bits */
-                       val = ((u16)(device->buffer[8]) << 1);
-                       val |= (u16)(device->buffer[7] >> 7);
-                       input_report_abs(inputdev, ABS_PRESSURE,
-                                        device->buffer[8]);
-
-                       /* Mask out the Y tilt value used for pressure */
-                       device->buffer[7] = (u8)((device->buffer[7]) & 0x7F);
-
-                       /* Fall thru */
-               case 4:
-                       /* Tilt */
-
-                       /* Sign extend these 7 bit numbers.  */
-                       if (device->buffer[6] & 0x40)
-                               device->buffer[6] |= 0x80;
-
-                       if (device->buffer[7] & 0x40)
-                               device->buffer[7] |= 0x80;
-
-
-                       valsigned = (device->buffer[6]);
-                       input_report_abs(inputdev, ABS_TILT_X, (s32)valsigned);
-
-                       valsigned = (device->buffer[7]);
-                       input_report_abs(inputdev, ABS_TILT_Y, (s32)valsigned);
-
-                       /* Fall thru */
-               case 2:
-               case 3:
-                       /* Convert buttons, only 5 bits possible */
-                       val = (device->buffer[5]) & MASK_BUTTON;
-
-                       /* We don't apply any meaning to the bitmask,
-                          just report */
-                       input_event(inputdev, EV_MSC, MSC_SERIAL, val);
-
-                       /*  Fall thru */
-               case 1:
-                       /* All reports have X and Y coords in the same place */
-                       val = le16_to_cpu(get_unaligned((__le16 *)&device->buffer[1]));
-                       input_report_abs(inputdev, ABS_X, val);
-
-                       val = le16_to_cpu(get_unaligned((__le16 *)&device->buffer[3]));
-                       input_report_abs(inputdev, ABS_Y, val);
-
-                       /* Ditto for proximity bit */
-                       val = device->buffer[5] & MASK_INRANGE ? 1 : 0;
-                       input_report_abs(inputdev, ABS_DISTANCE, val);
-
-                       /* Report 1 is an exception to how we handle buttons */
-                       /* Buttons are an index, not a bitmask */
-                       if (device->buffer[0] == 1) {
-
-                               /*
-                                * Convert buttons, 5 bit index
-                                * Report value of index set as one,
-                                * the rest as 0
-                                */
-                               val = device->buffer[5] & MASK_BUTTON;
-                               dbg("======>>>>>>REPORT 1: val 0x%X(%d)",
-                                   val, val);
-
-                               /*
-                                * We don't apply any meaning to the button
-                                * index, just report it
-                                */
-                               input_event(inputdev, EV_MSC, MSC_SERIAL, val);
-                       }
-                       break;
-
-               case 7:
-                       /* Menu blocks */
-                       input_event(inputdev, EV_MSC, MSC_SCAN,
-                                   device->buffer[1]);
-                       break;
-               }
-       }
-
-       /* Other pid class */
-       if (inputdev->id.product == PID_400 ||
-           inputdev->id.product == PID_401) {
-
-               /* Report 2 */
-               if (device->buffer[0] == 2) {
-                       /* Menu blocks */
-                       input_event(inputdev, EV_MSC, MSC_SCAN, device->buffer[1]);
-               }
-
-               /*  Report 1 */
-               if (device->buffer[0] == 1) {
-                       char buttonbyte;
-
-                       /*  IF X max > 64K, we still a bit from the y report */
-                       if (device->max_X > 0x10000) {
-
-                               val = (u16)(((u16)(device->buffer[2] << 8)) | (u8)device->buffer[1]);
-                               val |= (u32)(((u8)device->buffer[3] & 0x1) << 16);
-
-                               input_report_abs(inputdev, ABS_X, val);
-
-                               le_buffer[0]  = (u8)((u8)(device->buffer[3]) >> 1);
-                               le_buffer[0] |= (u8)((device->buffer[3] & 0x1) << 7);
-
-                               le_buffer[1]  = (u8)(device->buffer[4] >> 1);
-                               le_buffer[1] |= (u8)((device->buffer[5] & 0x1) << 7);
-
-                               val = le16_to_cpu(get_unaligned((__le16 *)le_buffer));
-                               input_report_abs(inputdev, ABS_Y, val);
-
-                               /*
-                                * Shift the button byte right by one to
-                                * make it look like the standard report
-                                */
-                               buttonbyte = device->buffer[5] >> 1;
-                       } else {
-
-                               val = le16_to_cpu(get_unaligned((__le16 *)&device->buffer[1]));
-                               input_report_abs(inputdev, ABS_X, val);
-
-                               val = le16_to_cpu(get_unaligned((__le16 *)&device->buffer[3]));
-                               input_report_abs(inputdev, ABS_Y, val);
-
-                               buttonbyte = device->buffer[5];
-                       }
-
-                       /* BUTTONS and PROXIMITY */
-                       val = buttonbyte & MASK_INRANGE ? 1 : 0;
-                       input_report_abs(inputdev, ABS_DISTANCE, val);
-
-                       /* Convert buttons, only 4 bits possible */
-                       val = buttonbyte & 0x0F;
-#ifdef USE_BUTTONS
-                       for (i = 0; i < 5; i++)
-                               input_report_key(inputdev, BTN_DIGI + i, val & (1 << i));
-#else
-                       /* We don't apply any meaning to the bitmask, just report */
-                       input_event(inputdev, EV_MSC, MSC_SERIAL, val);
-#endif
-
-                       /* TRANSDUCER */
-                       input_report_abs(inputdev, ABS_MISC, device->buffer[6]);
-               }
-       }
-
-       /* Everybody gets report ID's */
-       input_event(inputdev, EV_MSC, MSC_RAW,  device->buffer[0]);
-
-       /* Sync it up */
-       input_sync(inputdev);
-
- resubmit:
-       rc = usb_submit_urb(urbinfo, GFP_ATOMIC);
-       if (rc != 0)
-               err("usb_submit_urb failed rc=0x%x", rc);
-}
-
-/*
- *  The probe routine.  This is called when the kernel find the matching USB
- *   vendor/product.  We do the following:
- *
- *    - Allocate mem for a local structure to manage the device
- *    - Request a HID Report Descriptor from the device and parse it to
- *      find out the device parameters
- *    - Create an input device and assign it attributes
- *   - Allocate an URB so the device can talk to us when the input
- *      queue is open
- */
-static int gtco_probe(struct usb_interface *usbinterface,
-                     const struct usb_device_id *id)
-{
-
-       struct gtco             *gtco;
-       struct input_dev        *input_dev;
-       struct hid_descriptor   *hid_desc;
-       char                    *report = NULL;
-       int                     result = 0, retry;
-       int                     error;
-       struct usb_endpoint_descriptor *endpoint;
-
-       /* Allocate memory for device structure */
-       gtco = kzalloc(sizeof(struct gtco), GFP_KERNEL);
-       input_dev = input_allocate_device();
-       if (!gtco || !input_dev) {
-               err("No more memory");
-               error = -ENOMEM;
-               goto err_free_devs;
-       }
-
-       /* Set pointer to the input device */
-       gtco->inputdevice = input_dev;
-
-       /* Save interface information */
-       gtco->usbdev = usb_get_dev(interface_to_usbdev(usbinterface));
-
-       /* Allocate some data for incoming reports */
-       gtco->buffer = usb_buffer_alloc(gtco->usbdev, REPORT_MAX_SIZE,
-                                       GFP_KERNEL, &gtco->buf_dma);
-       if (!gtco->buffer) {
-               err("No more memory for us buffers");
-               error = -ENOMEM;
-               goto err_free_devs;
-       }
-
-       /* Allocate URB for reports */
-       gtco->urbinfo = usb_alloc_urb(0, GFP_KERNEL);
-       if (!gtco->urbinfo) {
-               err("Failed to allocate URB");
-               return -ENOMEM;
-               goto err_free_buf;
-       }
-
-       /*
-        * The endpoint is always altsetting 0, we know this since we know
-        * this device only has one interrupt endpoint
-        */
-       endpoint = &usbinterface->altsetting[0].endpoint[0].desc;
-
-       /* Some debug */
-       dbg("gtco # interfaces: %d", usbinterface->num_altsetting);
-       dbg("num endpoints:     %d", usbinterface->cur_altsetting->desc.bNumEndpoints);
-       dbg("interface class:   %d", usbinterface->cur_altsetting->desc.bInterfaceClass);
-       dbg("endpoint: attribute:0x%x type:0x%x", endpoint->bmAttributes, endpoint->bDescriptorType);
-       if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)
-               dbg("endpoint: we have interrupt endpoint\n");
-
-       dbg("endpoint extra len:%d ", usbinterface->altsetting[0].extralen);
-
-       /*
-        * Find the HID descriptor so we can find out the size of the
-        * HID report descriptor
-        */
-       if (usb_get_extra_descriptor(usbinterface->cur_altsetting,
-                                    HID_DEVICE_TYPE, &hid_desc) != 0){
-               err("Can't retrieve exta USB descriptor to get hid report descriptor length");
-               error = -EIO;
-               goto err_free_urb;
-       }
-
-       dbg("Extra descriptor success: type:%d  len:%d",
-           hid_desc->bDescriptorType,  hid_desc->wDescriptorLength);
-
-       report = kzalloc(hid_desc->wDescriptorLength, GFP_KERNEL);
-       if (!report) {
-               err("No more memory for report");
-               error = -ENOMEM;
-               goto err_free_urb;
-       }
-
-       /* Couple of tries to get reply */
-       for (retry = 0; retry < 3; retry++) {
-               result = usb_control_msg(gtco->usbdev,
-                                        usb_rcvctrlpipe(gtco->usbdev, 0),
-                                        USB_REQ_GET_DESCRIPTOR,
-                                        USB_RECIP_INTERFACE | USB_DIR_IN,
-                                        REPORT_DEVICE_TYPE << 8,
-                                        0, /* interface */
-                                        report,
-                                        hid_desc->wDescriptorLength,
-                                        5000); /* 5 secs */
-
-               if (result == hid_desc->wDescriptorLength)
-                       break;
-       }
-
-       /* If we didn't get the report, fail */
-       dbg("usb_control_msg result: :%d", result);
-       if (result != hid_desc->wDescriptorLength) {
-               err("Failed to get HID Report Descriptor of size: %d",
-                   hid_desc->wDescriptorLength);
-               error = -EIO;
-               goto err_free_urb;
-       }
-
-       /* Now we parse the report */
-       parse_hid_report_descriptor(gtco, report, result);
-
-       /* Now we delete it */
-       kfree(report);
-
-       /* Create a device file node */
-       usb_make_path(gtco->usbdev, gtco->usbpath, sizeof(gtco->usbpath));
-       strlcat(gtco->usbpath, "/input0", sizeof(gtco->usbpath));
-
-       /* Set Input device functions */
-       input_dev->open = gtco_input_open;
-       input_dev->close = gtco_input_close;
-
-       /* Set input device information */
-       input_dev->name = "GTCO_CalComp";
-       input_dev->phys = gtco->usbpath;
-
-       input_set_drvdata(input_dev, gtco);
-
-       /* Now set up all the input device capabilities */
-       gtco_setup_caps(input_dev);
-
-       /* Set input device required ID information */
-       usb_to_input_id(gtco->usbdev, &input_dev->id);
-       input_dev->dev.parent = &usbinterface->dev;
-
-       /* Setup the URB, it will be posted later on open of input device */
-       endpoint = &usbinterface->altsetting[0].endpoint[0].desc;
-
-       usb_fill_int_urb(gtco->urbinfo,
-                        gtco->usbdev,
-                        usb_rcvintpipe(gtco->usbdev,
-                                       endpoint->bEndpointAddress),
-                        gtco->buffer,
-                        REPORT_MAX_SIZE,
-                        gtco_urb_callback,
-                        gtco,
-                        endpoint->bInterval);
-
-       gtco->urbinfo->transfer_dma = gtco->buf_dma;
-       gtco->urbinfo->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-
-       /* Save gtco pointer in USB interface gtco */
-       usb_set_intfdata(usbinterface, gtco);
-
-       /* All done, now register the input device */
-       error = input_register_device(input_dev);
-       if (error)
-               goto err_free_urb;
-
-       return 0;
-
- err_free_urb:
-       usb_free_urb(gtco->urbinfo);
- err_free_buf:
-       usb_buffer_free(gtco->usbdev, REPORT_MAX_SIZE,
-                       gtco->buffer, gtco->buf_dma);
- err_free_devs:
-       kfree(report);
-       input_free_device(input_dev);
-       kfree(gtco);
-       return error;
-}
-
-/*
- *  This function is a standard USB function called when the USB device
- *  is disconnected.  We will get rid of the URV, de-register the input
- *  device, and free up allocated memory
- */
-static void gtco_disconnect(struct usb_interface *interface)
-{
-       /* Grab private device ptr */
-       struct gtco *gtco = usb_get_intfdata(interface);
-
-       /* Now reverse all the registration stuff */
-       if (gtco) {
-               input_unregister_device(gtco->inputdevice);
-               usb_kill_urb(gtco->urbinfo);
-               usb_free_urb(gtco->urbinfo);
-               usb_buffer_free(gtco->usbdev, REPORT_MAX_SIZE,
-                               gtco->buffer, gtco->buf_dma);
-               kfree(gtco);
-       }
-
-       info("gtco driver disconnected");
-}
-
-/*   STANDARD MODULE LOAD ROUTINES  */
-
-static struct usb_driver gtco_driverinfo_table = {
-       .name           = "gtco",
-       .id_table       = gtco_usbid_table,
-       .probe          = gtco_probe,
-       .disconnect     = gtco_disconnect,
-};
-
-/*
- *  Register this module with the USB subsystem
- */
-static int __init gtco_init(void)
-{
-       int error;
-
-       error = usb_register(&gtco_driverinfo_table);
-       if (error) {
-               err("usb_register() failed rc=0x%x", error);
-               return error;
-       }
-
-       printk("GTCO usb driver version: %s", GTCO_VERSION);
-       return 0;
-}
-
-/*
- *   Deregister this module with the USB subsystem
- */
-static void __exit gtco_exit(void)
-{
-       usb_deregister(&gtco_driverinfo_table);
-}
-
-module_init(gtco_init);
-module_exit(gtco_exit);
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/input/kbtab.c b/drivers/usb/input/kbtab.c
deleted file mode 100644 (file)
index 91e6d00..0000000
+++ /dev/null
@@ -1,226 +0,0 @@
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/usb/input.h>
-#include <asm/unaligned.h>
-
-/*
- * Version Information
- * v0.0.1 - Original, extremely basic version, 2.4.xx only
- * v0.0.2 - Updated, works with 2.5.62 and 2.4.20;
- *           - added pressure-threshold modules param code from
- *              Alex Perry <alex.perry@ieee.org>
- */
-
-#define DRIVER_VERSION "v0.0.2"
-#define DRIVER_AUTHOR "Josh Myer <josh@joshisanerd.com>"
-#define DRIVER_DESC "USB KB Gear JamStudio Tablet driver"
-#define DRIVER_LICENSE "GPL"
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE(DRIVER_LICENSE);
-
-#define USB_VENDOR_ID_KBGEAR   0x084e
-
-static int kb_pressure_click = 0x10;
-module_param(kb_pressure_click, int, 0);
-MODULE_PARM_DESC(kb_pressure_click, "pressure threshold for clicks");
-
-struct kbtab {
-       unsigned char *data;
-       dma_addr_t data_dma;
-       struct input_dev *dev;
-       struct usb_device *usbdev;
-       struct urb *irq;
-       int x, y;
-       int button;
-       int pressure;
-       __u32 serial[2];
-       char phys[32];
-};
-
-static void kbtab_irq(struct urb *urb)
-{
-       struct kbtab *kbtab = urb->context;
-       unsigned char *data = kbtab->data;
-       struct input_dev *dev = kbtab->dev;
-       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;
-       }
-
-       kbtab->x = le16_to_cpu(get_unaligned((__le16 *) &data[1]));
-       kbtab->y = le16_to_cpu(get_unaligned((__le16 *) &data[3]));
-
-       kbtab->pressure = (data[5]);
-
-       input_report_key(dev, BTN_TOOL_PEN, 1);
-
-       input_report_abs(dev, ABS_X, kbtab->x);
-       input_report_abs(dev, ABS_Y, kbtab->y);
-
-       /*input_report_key(dev, BTN_TOUCH , data[0] & 0x01);*/
-       input_report_key(dev, BTN_RIGHT, data[0] & 0x02);
-
-       if (-1 == kb_pressure_click) {
-               input_report_abs(dev, ABS_PRESSURE, kbtab->pressure);
-       } else {
-               input_report_key(dev, BTN_LEFT, (kbtab->pressure > kb_pressure_click) ? 1 : 0);
-       };
-
-       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 usb_device_id kbtab_ids[] = {
-       { USB_DEVICE(USB_VENDOR_ID_KBGEAR, 0x1001), .driver_info = 0 },
-       { }
-};
-
-MODULE_DEVICE_TABLE(usb, kbtab_ids);
-
-static int kbtab_open(struct input_dev *dev)
-{
-       struct kbtab *kbtab = input_get_drvdata(dev);
-
-       kbtab->irq->dev = kbtab->usbdev;
-       if (usb_submit_urb(kbtab->irq, GFP_KERNEL))
-               return -EIO;
-
-       return 0;
-}
-
-static void kbtab_close(struct input_dev *dev)
-{
-       struct kbtab *kbtab = input_get_drvdata(dev);
-
-       usb_kill_urb(kbtab->irq);
-}
-
-static int kbtab_probe(struct usb_interface *intf, const struct usb_device_id *id)
-{
-       struct usb_device *dev = interface_to_usbdev(intf);
-       struct usb_endpoint_descriptor *endpoint;
-       struct kbtab *kbtab;
-       struct input_dev *input_dev;
-       int error = -ENOMEM;
-
-       kbtab = kzalloc(sizeof(struct kbtab), GFP_KERNEL);
-       input_dev = input_allocate_device();
-       if (!kbtab || !input_dev)
-               goto fail1;
-
-       kbtab->data = usb_buffer_alloc(dev, 8, GFP_KERNEL, &kbtab->data_dma);
-       if (!kbtab->data)
-               goto fail1;
-
-       kbtab->irq = usb_alloc_urb(0, GFP_KERNEL);
-       if (!kbtab->irq)
-               goto fail2;
-
-       kbtab->usbdev = dev;
-       kbtab->dev = input_dev;
-
-       usb_make_path(dev, kbtab->phys, sizeof(kbtab->phys));
-       strlcat(kbtab->phys, "/input0", sizeof(kbtab->phys));
-
-       input_dev->name = "KB Gear Tablet";
-       input_dev->phys = kbtab->phys;
-       usb_to_input_id(dev, &input_dev->id);
-       input_dev->dev.parent = &intf->dev;
-
-       input_set_drvdata(input_dev, kbtab);
-
-       input_dev->open = kbtab_open;
-       input_dev->close = kbtab_close;
-
-       input_dev->evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_MSC);
-       input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
-       input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PEN) | BIT(BTN_TOUCH);
-       input_dev->mscbit[0] |= BIT(MSC_SERIAL);
-       input_set_abs_params(input_dev, ABS_X, 0, 0x2000, 4, 0);
-       input_set_abs_params(input_dev, ABS_Y, 0, 0x1750, 4, 0);
-       input_set_abs_params(input_dev, ABS_PRESSURE, 0, 0xff, 0, 0);
-
-       endpoint = &intf->cur_altsetting->endpoint[0].desc;
-
-       usb_fill_int_urb(kbtab->irq, dev,
-                        usb_rcvintpipe(dev, endpoint->bEndpointAddress),
-                        kbtab->data, 8,
-                        kbtab_irq, kbtab, endpoint->bInterval);
-       kbtab->irq->transfer_dma = kbtab->data_dma;
-       kbtab->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-
-       error = input_register_device(kbtab->dev);
-       if (error)
-               goto fail3;
-
-       usb_set_intfdata(intf, kbtab);
-
-       return 0;
-
- fail3:        usb_free_urb(kbtab->irq);
- fail2:        usb_buffer_free(dev, 10, kbtab->data, kbtab->data_dma);
- fail1:        input_free_device(input_dev);
-       kfree(kbtab);
-       return error;
-}
-
-static void kbtab_disconnect(struct usb_interface *intf)
-{
-       struct kbtab *kbtab = usb_get_intfdata(intf);
-
-       usb_set_intfdata(intf, NULL);
-       if (kbtab) {
-               usb_kill_urb(kbtab->irq);
-               input_unregister_device(kbtab->dev);
-               usb_free_urb(kbtab->irq);
-               usb_buffer_free(interface_to_usbdev(intf), 10, kbtab->data, kbtab->data_dma);
-               kfree(kbtab);
-       }
-}
-
-static struct usb_driver kbtab_driver = {
-       .name =         "kbtab",
-       .probe =        kbtab_probe,
-       .disconnect =   kbtab_disconnect,
-       .id_table =     kbtab_ids,
-};
-
-static int __init kbtab_init(void)
-{
-       int retval;
-       retval = usb_register(&kbtab_driver);
-       if (retval)
-               goto out;
-       info(DRIVER_VERSION ":" DRIVER_DESC);
-out:
-       return retval;
-}
-
-static void __exit kbtab_exit(void)
-{
-       usb_deregister(&kbtab_driver);
-}
-
-module_init(kbtab_init);
-module_exit(kbtab_exit);
diff --git a/drivers/usb/input/wacom.h b/drivers/usb/input/wacom.h
deleted file mode 100644 (file)
index d85abfc..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * drivers/usb/input/wacom.h
- *
- *  USB Wacom Graphire and Wacom Intuos tablet support
- *
- *  Copyright (c) 2000-2004 Vojtech Pavlik     <vojtech@ucw.cz>
- *  Copyright (c) 2000 Andreas Bach Aaen       <abach@stofanet.dk>
- *  Copyright (c) 2000 Clifford Wolf           <clifford@clifford.at>
- *  Copyright (c) 2000 Sam Mosel               <sam.mosel@computer.org>
- *  Copyright (c) 2000 James E. Blair          <corvus@gnu.org>
- *  Copyright (c) 2000 Daniel Egger            <egger@suse.de>
- *  Copyright (c) 2001 Frederic Lepied         <flepied@mandrakesoft.com>
- *  Copyright (c) 2004 Panagiotis Issaris      <panagiotis.issaris@mech.kuleuven.ac.be>
- *  Copyright (c) 2002-2006 Ping Cheng         <pingc@wacom.com>
- *
- *  ChangeLog:
- *      v0.1 (vp)  - Initial release
- *      v0.2 (aba) - Support for all buttons / combinations
- *      v0.3 (vp)  - Support for Intuos added
- *     v0.4 (sm)  - Support for more Intuos models, menustrip
- *                     relative mode, proximity.
- *     v0.5 (vp)  - Big cleanup, nifty features removed,
- *                     they belong in userspace
- *     v1.8 (vp)  - Submit URB only when operating, moved to CVS,
- *                     use input_report_key instead of report_btn and
- *                     other cleanups
- *     v1.11 (vp) - Add URB ->dev setting for new kernels
- *     v1.11 (jb) - Add support for the 4D Mouse & Lens
- *     v1.12 (de) - Add support for two more inking pen IDs
- *     v1.14 (vp) - Use new USB device id probing scheme.
- *                  Fix Wacom Graphire mouse wheel
- *     v1.18 (vp) - Fix mouse wheel direction
- *                  Make mouse relative
- *      v1.20 (fl) - Report tool id for Intuos devices
- *                 - Multi tools support
- *                 - Corrected Intuos protocol decoding (airbrush, 4D mouse, lens cursor...)
- *                 - Add PL models support
- *                - Fix Wacom Graphire mouse wheel again
- *     v1.21 (vp) - Removed protocol descriptions
- *                - Added MISC_SERIAL for tool serial numbers
- *           (gb) - Identify version on module load.
- *    v1.21.1 (fl) - added Graphire2 support
- *    v1.21.2 (fl) - added Intuos2 support
- *                 - added all the PL ids
- *    v1.21.3 (fl) - added another eraser id from Neil Okamoto
- *                 - added smooth filter for Graphire from Peri Hankey
- *                 - added PenPartner support from Olaf van Es
- *                 - new tool ids from Ole Martin Bjoerndalen
- *     v1.29 (pc) - Add support for more tablets
- *                - Fix pressure reporting
- *     v1.30 (vp) - Merge 2.4 and 2.5 drivers
- *                - Since 2.5 now has input_sync(), remove MSC_SERIAL abuse
- *                - Cleanups here and there
- *    v1.30.1 (pi) - Added Graphire3 support
- *     v1.40 (pc) - Add support for several new devices, fix eraser reporting, ...
- *     v1.43 (pc) - Added support for Cintiq 21UX
- *                - Fixed a Graphire bug
- *                - Merged wacom_intuos3_irq into wacom_intuos_irq
- *     v1.44 (pc) - Added support for Graphire4, Cintiq 710, Intuos3 6x11, etc.
- *                - Report Device IDs
- *      v1.45 (pc) - Added support for DTF 521, Intuos3 12x12 and 12x19
- *                 - Minor data report fix
- *      v1.46 (pc) - Split wacom.c into wacom_sys.c and wacom_wac.c,
- *                - where wacom_sys.c deals with system specific code,
- *                - and wacom_wac.c deals with Wacom specific code
- *                - Support Intuos3 4x6
- */
-
-/*
- * 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.
- */
-#ifndef WACOM_H
-#define WACOM_H
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/usb/input.h>
-#include <asm/unaligned.h>
-
-/*
- * Version Information
- */
-#define DRIVER_VERSION "v1.46"
-#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>"
-#define DRIVER_DESC "USB Wacom Graphire and Wacom Intuos tablet driver"
-#define DRIVER_LICENSE "GPL"
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE(DRIVER_LICENSE);
-
-#define USB_VENDOR_ID_WACOM    0x056a
-
-struct wacom {
-       dma_addr_t data_dma;
-       struct input_dev *dev;
-       struct usb_device *usbdev;
-       struct urb *irq;
-       struct wacom_wac * wacom_wac;
-       char phys[32];
-};
-
-struct wacom_combo {
-       struct wacom * wacom;
-       struct urb * urb;
-};
-
-extern int wacom_wac_irq(struct wacom_wac * wacom_wac, void * wcombo);
-extern void wacom_report_abs(void *wcombo, unsigned int abs_type, int abs_data);
-extern void wacom_report_rel(void *wcombo, unsigned int rel_type, int rel_data);
-extern void wacom_report_key(void *wcombo, unsigned int key_type, int key_data);
-extern void wacom_input_event(void *wcombo, unsigned int type, unsigned int code, int value);
-extern void wacom_input_sync(void *wcombo);
-extern void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
-extern void input_dev_g4(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
-extern void input_dev_g(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
-extern void input_dev_i3s(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
-extern void input_dev_i3(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
-extern void input_dev_i(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
-extern void input_dev_pl(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
-extern void input_dev_pt(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
-extern __u16 wacom_le16_to_cpu(unsigned char *data);
-extern __u16 wacom_be16_to_cpu(unsigned char *data);
-extern struct wacom_features * get_wacom_feature(const struct usb_device_id *id);
-extern const struct usb_device_id * get_device_table(void);
-
-#endif
diff --git a/drivers/usb/input/wacom_sys.c b/drivers/usb/input/wacom_sys.c
deleted file mode 100644 (file)
index 1fe4820..0000000
+++ /dev/null
@@ -1,318 +0,0 @@
-/*
- * drivers/usb/input/wacom_sys.c
- *
- *  USB Wacom Graphire and Wacom Intuos tablet support - system specific code
- */
-
-/*
- * 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 "wacom.h"
-#include "wacom_wac.h"
-
-#define USB_REQ_GET_REPORT     0x01
-#define USB_REQ_SET_REPORT     0x09
-
-static int usb_get_report(struct usb_interface *intf, unsigned char type,
-                               unsigned char id, void *buf, int size)
-{
-       return usb_control_msg(interface_to_usbdev(intf),
-               usb_rcvctrlpipe(interface_to_usbdev(intf), 0),
-               USB_REQ_GET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-               (type << 8) + id, intf->altsetting[0].desc.bInterfaceNumber,
-               buf, size, 100);
-}
-
-static int usb_set_report(struct usb_interface *intf, unsigned char type,
-                               unsigned char id, void *buf, int size)
-{
-       return usb_control_msg(interface_to_usbdev(intf),
-               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, 1000);
-}
-
-static struct input_dev * get_input_dev(struct wacom_combo *wcombo)
-{
-       return wcombo->wacom->dev;
-}
-
-static void wacom_sys_irq(struct urb *urb)
-{
-       struct wacom *wacom = urb->context;
-       struct wacom_combo wcombo;
-       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;
-       }
-
-       wcombo.wacom = wacom;
-       wcombo.urb = urb;
-
-       if (wacom_wac_irq(wacom->wacom_wac, (void *)&wcombo))
-               input_sync(get_input_dev(&wcombo));
-
- exit:
-       retval = usb_submit_urb (urb, GFP_ATOMIC);
-       if (retval)
-               err ("%s - usb_submit_urb failed with result %d",
-                    __FUNCTION__, retval);
-}
-
-void wacom_report_key(void *wcombo, unsigned int key_type, int key_data)
-{
-       input_report_key(get_input_dev((struct wacom_combo *)wcombo), key_type, key_data);
-       return;
-}
-
-void wacom_report_abs(void *wcombo, unsigned int abs_type, int abs_data)
-{
-       input_report_abs(get_input_dev((struct wacom_combo *)wcombo), abs_type, abs_data);
-       return;
-}
-
-void wacom_report_rel(void *wcombo, unsigned int rel_type, int rel_data)
-{
-       input_report_rel(get_input_dev((struct wacom_combo *)wcombo), rel_type, rel_data);
-       return;
-}
-
-void wacom_input_event(void *wcombo, unsigned int type, unsigned int code, int value)
-{
-       input_event(get_input_dev((struct wacom_combo *)wcombo), type, code, value);
-       return;
-}
-
-__u16 wacom_be16_to_cpu(unsigned char *data)
-{
-       __u16 value;
-       value = be16_to_cpu(*(__be16 *) data);
-       return value;
-}
-
-__u16 wacom_le16_to_cpu(unsigned char *data)
-{
-       __u16 value;
-       value = le16_to_cpu(*(__le16 *) data);
-       return value;
-}
-
-void wacom_input_sync(void *wcombo)
-{
-       input_sync(get_input_dev((struct wacom_combo *)wcombo));
-       return;
-}
-
-static int wacom_open(struct input_dev *dev)
-{
-       struct wacom *wacom = input_get_drvdata(dev);
-
-       wacom->irq->dev = wacom->usbdev;
-       if (usb_submit_urb(wacom->irq, GFP_KERNEL))
-               return -EIO;
-
-       return 0;
-}
-
-static void wacom_close(struct input_dev *dev)
-{
-       struct wacom *wacom = input_get_drvdata(dev);
-
-       usb_kill_urb(wacom->irq);
-}
-
-void input_dev_g4(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
-{
-       input_dev->evbit[0] |= BIT(EV_MSC);
-       input_dev->mscbit[0] |= BIT(MSC_SERIAL);
-       input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_FINGER);
-       input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_0) | BIT(BTN_4);
-}
-
-void input_dev_g(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
-{
-       input_dev->evbit[0] |= BIT(EV_REL);
-       input_dev->relbit[0] |= BIT(REL_WHEEL);
-       input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
-       input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE) | BIT(BTN_STYLUS2);
-       input_set_abs_params(input_dev, ABS_DISTANCE, 0, wacom_wac->features->distance_max, 0, 0);
-}
-
-void input_dev_i3s(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
-{
-       input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_FINGER);
-       input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_0) | BIT(BTN_1) | BIT(BTN_2) | BIT(BTN_3);
-       input_set_abs_params(input_dev, ABS_RX, 0, 4096, 0, 0);
-}
-
-void input_dev_i3(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
-{
-       input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_4) | BIT(BTN_5) | BIT(BTN_6) | BIT(BTN_7);
-       input_set_abs_params(input_dev, ABS_RY, 0, 4096, 0, 0);
-}
-
-void input_dev_i(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
-{
-       input_dev->evbit[0] |= BIT(EV_MSC) | BIT(EV_REL);
-       input_dev->mscbit[0] |= BIT(MSC_SERIAL);
-       input_dev->relbit[0] |= BIT(REL_WHEEL);
-       input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE) | BIT(BTN_SIDE) | BIT(BTN_EXTRA);
-       input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE) | BIT(BTN_TOOL_BRUSH)
-               | BIT(BTN_TOOL_PENCIL) | BIT(BTN_TOOL_AIRBRUSH) | BIT(BTN_TOOL_LENS) | BIT(BTN_STYLUS2);
-       input_set_abs_params(input_dev, ABS_DISTANCE, 0, wacom_wac->features->distance_max, 0, 0);
-       input_set_abs_params(input_dev, ABS_WHEEL, 0, 1023, 0, 0);
-       input_set_abs_params(input_dev, ABS_TILT_X, 0, 127, 0, 0);
-       input_set_abs_params(input_dev, ABS_TILT_Y, 0, 127, 0, 0);
-       input_set_abs_params(input_dev, ABS_RZ, -900, 899, 0, 0);
-       input_set_abs_params(input_dev, ABS_THROTTLE, -1023, 1023, 0, 0);
-}
-
-void input_dev_pl(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
-{
-       input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_STYLUS2) | BIT(BTN_TOOL_RUBBER);
-}
-
-void input_dev_pt(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
-{
-       input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER);
-}
-
-static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *id)
-{
-       struct usb_device *dev = interface_to_usbdev(intf);
-       struct usb_endpoint_descriptor *endpoint;
-       struct wacom *wacom;
-       struct wacom_wac *wacom_wac;
-       struct input_dev *input_dev;
-       int error = -ENOMEM;
-       char rep_data[2], limit = 0;
-
-       wacom = kzalloc(sizeof(struct wacom), GFP_KERNEL);
-       wacom_wac = kzalloc(sizeof(struct wacom_wac), GFP_KERNEL);
-       input_dev = input_allocate_device();
-       if (!wacom || !input_dev || !wacom_wac)
-               goto fail1;
-
-       wacom_wac->data = usb_buffer_alloc(dev, 10, GFP_KERNEL, &wacom->data_dma);
-       if (!wacom_wac->data)
-               goto fail1;
-
-       wacom->irq = usb_alloc_urb(0, GFP_KERNEL);
-       if (!wacom->irq)
-               goto fail2;
-
-       wacom->usbdev = dev;
-       wacom->dev = input_dev;
-       usb_make_path(dev, wacom->phys, sizeof(wacom->phys));
-       strlcat(wacom->phys, "/input0", sizeof(wacom->phys));
-
-       wacom_wac->features = get_wacom_feature(id);
-       BUG_ON(wacom_wac->features->pktlen > 10);
-
-       input_dev->name = wacom_wac->features->name;
-       wacom->wacom_wac = wacom_wac;
-       usb_to_input_id(dev, &input_dev->id);
-
-       input_dev->dev.parent = &intf->dev;
-
-       input_set_drvdata(input_dev, wacom);
-
-       input_dev->open = wacom_open;
-       input_dev->close = wacom_close;
-
-       input_dev->evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS);
-       input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PEN) | BIT(BTN_TOUCH) | BIT(BTN_STYLUS);
-       input_set_abs_params(input_dev, ABS_X, 0, wacom_wac->features->x_max, 4, 0);
-       input_set_abs_params(input_dev, ABS_Y, 0, wacom_wac->features->y_max, 4, 0);
-       input_set_abs_params(input_dev, ABS_PRESSURE, 0, wacom_wac->features->pressure_max, 0, 0);
-       input_dev->absbit[LONG(ABS_MISC)] |= BIT(ABS_MISC);
-
-       wacom_init_input_dev(input_dev, wacom_wac);
-
-       endpoint = &intf->cur_altsetting->endpoint[0].desc;
-
-       usb_fill_int_urb(wacom->irq, dev,
-                        usb_rcvintpipe(dev, endpoint->bEndpointAddress),
-                        wacom_wac->data, wacom_wac->features->pktlen,
-                        wacom_sys_irq, wacom, endpoint->bInterval);
-       wacom->irq->transfer_dma = wacom->data_dma;
-       wacom->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-
-       error = input_register_device(wacom->dev);
-       if (error)
-               goto fail3;
-
-       /* Ask the tablet to report tablet data. Repeat until it succeeds */
-       do {
-               rep_data[0] = 2;
-               rep_data[1] = 2;
-               usb_set_report(intf, 3, 2, rep_data, 2);
-               usb_get_report(intf, 3, 2, rep_data, 2);
-       } while (rep_data[1] != 2 && limit++ < 5);
-
-       usb_set_intfdata(intf, wacom);
-       return 0;
-
- fail3:        usb_free_urb(wacom->irq);
- fail2:        usb_buffer_free(dev, 10, wacom_wac->data, wacom->data_dma);
- fail1:        input_free_device(input_dev);
-       kfree(wacom);
-       kfree(wacom_wac);
-       return error;
-}
-
-static void wacom_disconnect(struct usb_interface *intf)
-{
-       struct wacom *wacom = usb_get_intfdata (intf);
-
-       usb_set_intfdata(intf, NULL);
-       if (wacom) {
-               usb_kill_urb(wacom->irq);
-               input_unregister_device(wacom->dev);
-               usb_free_urb(wacom->irq);
-               usb_buffer_free(interface_to_usbdev(intf), 10, wacom->wacom_wac->data, wacom->data_dma);
-               kfree(wacom->wacom_wac);
-               kfree(wacom);
-       }
-}
-
-static struct usb_driver wacom_driver = {
-       .name =         "wacom",
-       .probe =        wacom_probe,
-       .disconnect =   wacom_disconnect,
-};
-
-static int __init wacom_init(void)
-{
-       int result;
-       wacom_driver.id_table = get_device_table();
-       result = usb_register(&wacom_driver);
-       if (result == 0)
-               info(DRIVER_VERSION ":" DRIVER_DESC);
-       return result;
-}
-
-static void __exit wacom_exit(void)
-{
-       usb_deregister(&wacom_driver);
-}
-
-module_init(wacom_init);
-module_exit(wacom_exit);
diff --git a/drivers/usb/input/wacom_wac.c b/drivers/usb/input/wacom_wac.c
deleted file mode 100644 (file)
index 4f3e9bc..0000000
+++ /dev/null
@@ -1,675 +0,0 @@
-/*
- * drivers/usb/input/wacom_wac.c
- *
- *  USB Wacom Graphire and Wacom Intuos tablet support - Wacom specific code
- *
- */
-
-/*
- * 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 "wacom.h"
-#include "wacom_wac.h"
-
-static int wacom_penpartner_irq(struct wacom_wac *wacom, void *wcombo)
-{
-       unsigned char *data = wacom->data;
-
-       switch (data[0]) {
-               case 1:
-                       if (data[5] & 0x80) {
-                               wacom->tool[0] = (data[5] & 0x20) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
-                               wacom->id[0] = (data[5] & 0x20) ? ERASER_DEVICE_ID : STYLUS_DEVICE_ID;
-                               wacom_report_key(wcombo, wacom->tool[0], 1);
-                               wacom_report_abs(wcombo, ABS_MISC, wacom->id[0]); /* report tool id */
-                               wacom_report_abs(wcombo, ABS_X, wacom_le16_to_cpu(&data[1]));
-                               wacom_report_abs(wcombo, ABS_Y, wacom_le16_to_cpu(&data[3]));
-                               wacom_report_abs(wcombo, ABS_PRESSURE, (signed char)data[6] + 127);
-                               wacom_report_key(wcombo, BTN_TOUCH, ((signed char)data[6] > -127));
-                               wacom_report_key(wcombo, BTN_STYLUS, (data[5] & 0x40));
-                       } else {
-                               wacom_report_key(wcombo, wacom->tool[0], 0);
-                               wacom_report_abs(wcombo, ABS_MISC, 0); /* report tool id */
-                               wacom_report_abs(wcombo, ABS_PRESSURE, -1);
-                               wacom_report_key(wcombo, BTN_TOUCH, 0);
-                       }
-                       break;
-               case 2:
-                       wacom_report_key(wcombo, BTN_TOOL_PEN, 1);
-                       wacom_report_abs(wcombo, ABS_MISC, STYLUS_DEVICE_ID); /* report tool id */
-                       wacom_report_abs(wcombo, ABS_X, wacom_le16_to_cpu(&data[1]));
-                       wacom_report_abs(wcombo, ABS_Y, wacom_le16_to_cpu(&data[3]));
-                       wacom_report_abs(wcombo, ABS_PRESSURE, (signed char)data[6] + 127);
-                       wacom_report_key(wcombo, BTN_TOUCH, ((signed char)data[6] > -80) && !(data[5] & 0x20));
-                       wacom_report_key(wcombo, BTN_STYLUS, (data[5] & 0x40));
-                       break;
-               default:
-                       printk(KERN_INFO "wacom_penpartner_irq: received unknown report #%d\n", data[0]);
-                       return 0;
-        }
-       return 1;
-}
-
-static int wacom_pl_irq(struct wacom_wac *wacom, void *wcombo)
-{
-       unsigned char *data = wacom->data;
-       int prox, id, pressure;
-
-       if (data[0] != 2) {
-               dbg("wacom_pl_irq: received unknown report #%d", data[0]);
-               return 0;
-       }
-
-       prox = data[1] & 0x40;
-
-       id = ERASER_DEVICE_ID;
-       if (prox) {
-
-               pressure = (signed char)((data[7] << 1) | ((data[4] >> 2) & 1));
-               if (wacom->features->pressure_max > 255)
-                       pressure = (pressure << 1) | ((data[4] >> 6) & 1);
-               pressure += (wacom->features->pressure_max + 1) / 2;
-
-               /*
-                * if going from out of proximity into proximity select between the eraser
-                * and the pen based on the state of the stylus2 button, choose eraser if
-                * pressed else choose pen. if not a proximity change from out to in, send
-                * an out of proximity for previous tool then a in for new tool.
-                */
-               if (!wacom->tool[0]) {
-                       /* Eraser bit set for DTF */
-                       if (data[1] & 0x10)
-                               wacom->tool[1] = BTN_TOOL_RUBBER;
-                       else
-                               /* Going into proximity select tool */
-                               wacom->tool[1] = (data[4] & 0x20) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
-               } else {
-                       /* was entered with stylus2 pressed */
-                       if (wacom->tool[1] == BTN_TOOL_RUBBER && !(data[4] & 0x20)) {
-                               /* report out proximity for previous tool */
-                               wacom_report_key(wcombo, wacom->tool[1], 0);
-                               wacom_input_sync(wcombo);
-                               wacom->tool[1] = BTN_TOOL_PEN;
-                               return 0;
-                       }
-               }
-               if (wacom->tool[1] != BTN_TOOL_RUBBER) {
-                       /* Unknown tool selected default to pen tool */
-                       wacom->tool[1] = BTN_TOOL_PEN;
-                       id = STYLUS_DEVICE_ID;
-               }
-               wacom_report_key(wcombo, wacom->tool[1], prox); /* report in proximity for tool */
-               wacom_report_abs(wcombo, ABS_MISC, id); /* report tool id */
-               wacom_report_abs(wcombo, ABS_X, data[3] | (data[2] << 7) | ((data[1] & 0x03) << 14));
-               wacom_report_abs(wcombo, ABS_Y, data[6] | (data[5] << 7) | ((data[4] & 0x03) << 14));
-               wacom_report_abs(wcombo, ABS_PRESSURE, pressure);
-
-               wacom_report_key(wcombo, BTN_TOUCH, data[4] & 0x08);
-               wacom_report_key(wcombo, BTN_STYLUS, data[4] & 0x10);
-               /* Only allow the stylus2 button to be reported for the pen tool. */
-               wacom_report_key(wcombo, BTN_STYLUS2, (wacom->tool[1] == BTN_TOOL_PEN) && (data[4] & 0x20));
-       } else {
-               /* report proximity-out of a (valid) tool */
-               if (wacom->tool[1] != BTN_TOOL_RUBBER) {
-                       /* Unknown tool selected default to pen tool */
-                       wacom->tool[1] = BTN_TOOL_PEN;
-               }
-               wacom_report_key(wcombo, wacom->tool[1], prox);
-       }
-
-       wacom->tool[0] = prox; /* Save proximity state */
-       return 1;
-}
-
-static int wacom_ptu_irq(struct wacom_wac *wacom, void *wcombo)
-{
-       unsigned char *data = wacom->data;
-       int id;
-
-       if (data[0] != 2) {
-               printk(KERN_INFO "wacom_ptu_irq: received unknown report #%d\n", data[0]);
-               return 0;
-       }
-
-       if (data[1] & 0x04) {
-               wacom_report_key(wcombo, BTN_TOOL_RUBBER, data[1] & 0x20);
-               wacom_report_key(wcombo, BTN_TOUCH, data[1] & 0x08);
-               id = ERASER_DEVICE_ID;
-       } else {
-               wacom_report_key(wcombo, BTN_TOOL_PEN, data[1] & 0x20);
-               wacom_report_key(wcombo, BTN_TOUCH, data[1] & 0x01);
-               id = STYLUS_DEVICE_ID;
-       }
-       wacom_report_abs(wcombo, ABS_MISC, id); /* report tool id */
-       wacom_report_abs(wcombo, ABS_X, wacom_le16_to_cpu(&data[2]));
-       wacom_report_abs(wcombo, ABS_Y, wacom_le16_to_cpu(&data[4]));
-       wacom_report_abs(wcombo, ABS_PRESSURE, wacom_le16_to_cpu(&data[6]));
-       wacom_report_key(wcombo, BTN_STYLUS, data[1] & 0x02);
-       wacom_report_key(wcombo, BTN_STYLUS2, data[1] & 0x10);
-       return 1;
-}
-
-static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo)
-{
-       unsigned char *data = wacom->data;
-       int x, y, id, rw;
-
-       if (data[0] != 2) {
-               dbg("wacom_graphire_irq: received unknown report #%d", data[0]);
-               return 0;
-       }
-
-       id = STYLUS_DEVICE_ID;
-       if (data[1] & 0x80) { /* in prox */
-
-               switch ((data[1] >> 5) & 3) {
-
-                       case 0: /* Pen */
-                               wacom->tool[0] = BTN_TOOL_PEN;
-                               break;
-
-                       case 1: /* Rubber */
-                               wacom->tool[0] = BTN_TOOL_RUBBER;
-                               id = ERASER_DEVICE_ID;
-                               break;
-
-                       case 2: /* Mouse with wheel */
-                               wacom_report_key(wcombo, BTN_MIDDLE, data[1] & 0x04);
-                               if (wacom->features->type == WACOM_G4) {
-                                       rw = data[7] & 0x04 ? (data[7] & 0x03)-4 : (data[7] & 0x03);
-                                       wacom_report_rel(wcombo, REL_WHEEL, -rw);
-                               } else
-                                       wacom_report_rel(wcombo, REL_WHEEL, -(signed char) data[6]);
-                               /* fall through */
-
-                       case 3: /* Mouse without wheel */
-                               wacom->tool[0] = BTN_TOOL_MOUSE;
-                               id = CURSOR_DEVICE_ID;
-                               wacom_report_key(wcombo, BTN_LEFT, data[1] & 0x01);
-                               wacom_report_key(wcombo, BTN_RIGHT, data[1] & 0x02);
-                               if (wacom->features->type == WACOM_G4)
-                                       wacom_report_abs(wcombo, ABS_DISTANCE, data[6] & 0x3f);
-                               else
-                                       wacom_report_abs(wcombo, ABS_DISTANCE, data[7] & 0x3f);
-                               break;
-               }
-               x = wacom_le16_to_cpu(&data[2]);
-               y = wacom_le16_to_cpu(&data[4]);
-               wacom_report_abs(wcombo, ABS_X, x);
-               wacom_report_abs(wcombo, ABS_Y, y);
-               if (wacom->tool[0] != BTN_TOOL_MOUSE) {
-                       wacom_report_abs(wcombo, ABS_PRESSURE, data[6] | ((data[7] & 0x01) << 8));
-                       wacom_report_key(wcombo, BTN_TOUCH, data[1] & 0x01);
-                       wacom_report_key(wcombo, BTN_STYLUS, data[1] & 0x02);
-                       wacom_report_key(wcombo, BTN_STYLUS2, data[1] & 0x04);
-               }
-               wacom_report_abs(wcombo, ABS_MISC, id); /* report tool id */
-               wacom_report_key(wcombo, wacom->tool[0], 1);
-       } else if (!(data[1] & 0x90)) {
-               wacom_report_abs(wcombo, ABS_X, 0);
-               wacom_report_abs(wcombo, ABS_Y, 0);
-               if (wacom->tool[0] == BTN_TOOL_MOUSE) {
-                       wacom_report_key(wcombo, BTN_LEFT, 0);
-                       wacom_report_key(wcombo, BTN_RIGHT, 0);
-                       wacom_report_abs(wcombo, ABS_DISTANCE, 0);
-               } else {
-                       wacom_report_abs(wcombo, ABS_PRESSURE, 0);
-                       wacom_report_key(wcombo, BTN_TOUCH, 0);
-                       wacom_report_key(wcombo, BTN_STYLUS, 0);
-                       wacom_report_key(wcombo, BTN_STYLUS2, 0);
-               }
-               wacom_report_abs(wcombo, ABS_MISC, 0); /* reset tool id */
-               wacom_report_key(wcombo, wacom->tool[0], 0);
-       }
-
-       /* send pad data */
-       if (wacom->features->type == WACOM_G4) {
-               if (data[7] & 0xf8) {
-                       wacom_input_sync(wcombo); /* sync last event */
-                       wacom->id[1] = 1;
-                       wacom->serial[1] = (data[7] & 0xf8);
-                       wacom_report_key(wcombo, BTN_0, (data[7] & 0x40));
-                       wacom_report_key(wcombo, BTN_4, (data[7] & 0x80));
-                       rw = ((data[7] & 0x18) >> 3) - ((data[7] & 0x20) >> 3);
-                       wacom_report_rel(wcombo, REL_WHEEL, rw);
-                       wacom_report_key(wcombo, BTN_TOOL_FINGER, 0xf0);
-                       wacom_report_abs(wcombo, ABS_MISC, PAD_DEVICE_ID);
-                       wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xf0);
-               } else if (wacom->id[1]) {
-                       wacom_input_sync(wcombo); /* sync last event */
-                       wacom->id[1] = 0;
-                       wacom_report_key(wcombo, BTN_0, (data[7] & 0x40));
-                       wacom_report_key(wcombo, BTN_4, (data[7] & 0x80));
-                       wacom_report_key(wcombo, BTN_TOOL_FINGER, 0);
-                       wacom_report_abs(wcombo, ABS_MISC, 0);
-                       wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xf0);
-               }
-       }
-       return 1;
-}
-
-static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo)
-{
-       unsigned char *data = wacom->data;
-       int idx;
-
-       /* tool number */
-       idx = data[1] & 0x01;
-
-       /* Enter report */
-       if ((data[1] & 0xfc) == 0xc0) {
-               /* serial number of the tool */
-               wacom->serial[idx] = ((data[3] & 0x0f) << 28) +
-                       (data[4] << 20) + (data[5] << 12) +
-                       (data[6] << 4) + (data[7] >> 4);
-
-               wacom->id[idx] = (data[2] << 4) | (data[3] >> 4);
-               switch (wacom->id[idx]) {
-                       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 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:
-                       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:
-                       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:
-                       case 0x913: /* Intuos3 Airbrush */
-                               wacom->tool[idx] = BTN_TOOL_AIRBRUSH;
-                               break;
-                       default: /* Unknown tool */
-                               wacom->tool[idx] = BTN_TOOL_PEN;
-               }
-               return 1;
-       }
-
-       /* Exit report */
-       if ((data[1] & 0xfe) == 0x80) {
-               wacom_report_abs(wcombo, ABS_X, 0);
-               wacom_report_abs(wcombo, ABS_Y, 0);
-               wacom_report_abs(wcombo, ABS_DISTANCE, 0);
-               if (wacom->tool[idx] >= BTN_TOOL_MOUSE) {
-                       wacom_report_key(wcombo, BTN_LEFT, 0);
-                       wacom_report_key(wcombo, BTN_MIDDLE, 0);
-                       wacom_report_key(wcombo, BTN_RIGHT, 0);
-                       wacom_report_key(wcombo, BTN_SIDE, 0);
-                       wacom_report_key(wcombo, BTN_EXTRA, 0);
-                       wacom_report_abs(wcombo, ABS_THROTTLE, 0);
-                       wacom_report_abs(wcombo, ABS_RZ, 0);
-               } else {
-                       wacom_report_abs(wcombo, ABS_PRESSURE, 0);
-                       wacom_report_abs(wcombo, ABS_TILT_X, 0);
-                       wacom_report_abs(wcombo, ABS_TILT_Y, 0);
-                       wacom_report_key(wcombo, BTN_STYLUS, 0);
-                       wacom_report_key(wcombo, BTN_STYLUS2, 0);
-                       wacom_report_key(wcombo, BTN_TOUCH, 0);
-                       wacom_report_abs(wcombo, ABS_WHEEL, 0);
-               }
-               wacom_report_key(wcombo, wacom->tool[idx], 0);
-               wacom_report_abs(wcombo, ABS_MISC, 0); /* reset tool id */
-               wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
-               return 2;
-       }
-       return 0;
-}
-
-static void wacom_intuos_general(struct wacom_wac *wacom, void *wcombo)
-{
-       unsigned char *data = wacom->data;
-       unsigned int t;
-
-       /* general pen packet */
-       if ((data[1] & 0xb8) == 0xa0) {
-               t = (data[6] << 2) | ((data[7] >> 6) & 3);
-               wacom_report_abs(wcombo, ABS_PRESSURE, t);
-               wacom_report_abs(wcombo, ABS_TILT_X,
-                               ((data[7] << 1) & 0x7e) | (data[8] >> 7));
-               wacom_report_abs(wcombo, ABS_TILT_Y, data[8] & 0x7f);
-               wacom_report_key(wcombo, BTN_STYLUS, data[1] & 2);
-               wacom_report_key(wcombo, BTN_STYLUS2, data[1] & 4);
-               wacom_report_key(wcombo, BTN_TOUCH, t > 10);
-       }
-
-       /* airbrush second packet */
-       if ((data[1] & 0xbc) == 0xb4) {
-               wacom_report_abs(wcombo, ABS_WHEEL,
-                               (data[6] << 2) | ((data[7] >> 6) & 3));
-               wacom_report_abs(wcombo, ABS_TILT_X,
-                               ((data[7] << 1) & 0x7e) | (data[8] >> 7));
-               wacom_report_abs(wcombo, ABS_TILT_Y, data[8] & 0x7f);
-       }
-       return;
-}
-
-static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
-{
-       unsigned char *data = wacom->data;
-       unsigned int t;
-       int idx, result;
-
-       if (data[0] != 2 && data[0] != 5 && data[0] != 6 && data[0] != 12) {
-               dbg("wacom_intuos_irq: received unknown report #%d", data[0]);
-                return 0;
-       }
-
-       /* tool number */
-       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;
-
-               wacom_report_key(wcombo, BTN_0, (data[5] & 0x01));
-               wacom_report_key(wcombo, BTN_1, (data[5] & 0x02));
-               wacom_report_key(wcombo, BTN_2, (data[5] & 0x04));
-               wacom_report_key(wcombo, BTN_3, (data[5] & 0x08));
-               wacom_report_key(wcombo, BTN_4, (data[6] & 0x01));
-               wacom_report_key(wcombo, BTN_5, (data[6] & 0x02));
-               wacom_report_key(wcombo, BTN_6, (data[6] & 0x04));
-               wacom_report_key(wcombo, BTN_7, (data[6] & 0x08));
-               wacom_report_abs(wcombo, ABS_RX, ((data[1] & 0x1f) << 8) | data[2]);
-               wacom_report_abs(wcombo, ABS_RY, ((data[3] & 0x1f) << 8) | data[4]);
-
-               if((data[5] & 0x0f) | (data[6] & 0x0f) | (data[1] & 0x1f) |
-                       data[2] | (data[3] & 0x1f) | data[4])
-                       wacom_report_key(wcombo, wacom->tool[1], 1);
-               else
-                       wacom_report_key(wcombo, wacom->tool[1], 0);
-               wacom_report_abs(wcombo, ABS_MISC, PAD_DEVICE_ID);
-               wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xffffffff);
-                return 1;
-       }
-
-       /* process in/out prox events */
-       result = wacom_intuos_inout(wacom, wcombo);
-       if (result)
-                return result-1;
-
-       /* Only large I3 and I1 & I2 support Lense Cursor */
-       if((wacom->tool[idx] == BTN_TOOL_LENS)
-                       && ((wacom->features->type == INTUOS3)
-                       || (wacom->features->type == INTUOS3S)))
-               return 0;
-
-       /* Cintiq doesn't send data when RDY bit isn't set */
-       if ((wacom->features->type == CINTIQ) && !(data[1] & 0x40))
-                 return 0;
-
-       if (wacom->features->type >= INTUOS3S) {
-               wacom_report_abs(wcombo, ABS_X, (data[2] << 9) | (data[3] << 1) | ((data[9] >> 1) & 1));
-               wacom_report_abs(wcombo, ABS_Y, (data[4] << 9) | (data[5] << 1) | (data[9] & 1));
-               wacom_report_abs(wcombo, ABS_DISTANCE, ((data[9] >> 2) & 0x3f));
-       } else {
-               wacom_report_abs(wcombo, ABS_X, wacom_be16_to_cpu(&data[2]));
-               wacom_report_abs(wcombo, ABS_Y, wacom_be16_to_cpu(&data[4]));
-               wacom_report_abs(wcombo, ABS_DISTANCE, ((data[9] >> 3) & 0x1f));
-       }
-
-       /* process general packets */
-       wacom_intuos_general(wacom, wcombo);
-
-       /* 4D mouse, 2D mouse, marker pen rotation, or Lens cursor packets */
-       if ((data[1] & 0xbc) == 0xa8 || (data[1] & 0xbe) == 0xb0) {
-
-               if (data[1] & 0x02) {
-                       /* Rotation packet */
-                       if (wacom->features->type >= INTUOS3S) {
-                               /* I3 marker pen rotation reported as wheel
-                                * due to valuator limitation
-                                */
-                               t = (data[6] << 3) | ((data[7] >> 5) & 7);
-                               t = (data[7] & 0x20) ? ((t > 900) ? ((t-1) / 2 - 1350) :
-                                       ((t-1) / 2 + 450)) : (450 - t / 2) ;
-                               wacom_report_abs(wcombo, ABS_WHEEL, t);
-                       } else {
-                               /* 4D mouse rotation packet */
-                               t = (data[6] << 3) | ((data[7] >> 5) & 7);
-                               wacom_report_abs(wcombo, ABS_RZ, (data[7] & 0x20) ?
-                                       ((t - 1) / 2) : -t / 2);
-                       }
-
-               } else if (!(data[1] & 0x10) && wacom->features->type < INTUOS3S) {
-                       /* 4D mouse packet */
-                       wacom_report_key(wcombo, BTN_LEFT,   data[8] & 0x01);
-                       wacom_report_key(wcombo, BTN_MIDDLE, data[8] & 0x02);
-                       wacom_report_key(wcombo, BTN_RIGHT,  data[8] & 0x04);
-
-                       wacom_report_key(wcombo, BTN_SIDE,   data[8] & 0x20);
-                       wacom_report_key(wcombo, BTN_EXTRA,  data[8] & 0x10);
-                       t = (data[6] << 2) | ((data[7] >> 6) & 3);
-                       wacom_report_abs(wcombo, ABS_THROTTLE, (data[8] & 0x08) ? -t : t);
-
-               } else if (wacom->tool[idx] == BTN_TOOL_MOUSE) {
-                       /* 2D mouse packet */
-                       wacom_report_key(wcombo, BTN_LEFT,   data[8] & 0x04);
-                       wacom_report_key(wcombo, BTN_MIDDLE, data[8] & 0x08);
-                       wacom_report_key(wcombo, BTN_RIGHT,  data[8] & 0x10);
-                       wacom_report_rel(wcombo, REL_WHEEL, (data[8] & 0x01)
-                                                - ((data[8] & 0x02) >> 1));
-
-                       /* I3 2D mouse side buttons */
-                       if (wacom->features->type >= INTUOS3S && wacom->features->type <= INTUOS3L) {
-                               wacom_report_key(wcombo, BTN_SIDE,   data[8] & 0x40);
-                               wacom_report_key(wcombo, BTN_EXTRA,  data[8] & 0x20);
-                       }
-
-               } else if (wacom->features->type < INTUOS3S || wacom->features->type == INTUOS3L) {
-                       /* Lens cursor packets */
-                       wacom_report_key(wcombo, BTN_LEFT,   data[8] & 0x01);
-                       wacom_report_key(wcombo, BTN_MIDDLE, data[8] & 0x02);
-                       wacom_report_key(wcombo, BTN_RIGHT,  data[8] & 0x04);
-                       wacom_report_key(wcombo, BTN_SIDE,   data[8] & 0x10);
-                       wacom_report_key(wcombo, BTN_EXTRA,  data[8] & 0x08);
-               }
-       }
-
-       wacom_report_abs(wcombo, ABS_MISC, wacom->id[idx]); /* report tool id */
-       wacom_report_key(wcombo, wacom->tool[idx], 1);
-       wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
-       return 1;
-}
-
-int wacom_wac_irq(struct wacom_wac *wacom_wac, void *wcombo)
-{
-       switch (wacom_wac->features->type) {
-               case PENPARTNER:
-                       return (wacom_penpartner_irq(wacom_wac, wcombo));
-                       break;
-               case PL:
-                       return (wacom_pl_irq(wacom_wac, wcombo));
-                       break;
-               case WACOM_G4:
-               case GRAPHIRE:
-                       return (wacom_graphire_irq(wacom_wac, wcombo));
-                       break;
-               case PTU:
-                       return (wacom_ptu_irq(wacom_wac, wcombo));
-                       break;
-               case INTUOS:
-               case INTUOS3S:
-               case INTUOS3:
-               case INTUOS3L:
-               case CINTIQ:
-                       return (wacom_intuos_irq(wacom_wac, wcombo));
-                       break;
-               default:
-                       return 0;
-       }
-       return 0;
-}
-
-void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
-{
-       switch (wacom_wac->features->type) {
-               case WACOM_G4:
-                       input_dev_g4(input_dev, wacom_wac);
-                       /* fall through */
-               case GRAPHIRE:
-                       input_dev_g(input_dev, wacom_wac);
-                       break;
-               case INTUOS3:
-               case INTUOS3L:
-               case CINTIQ:
-                       input_dev_i3(input_dev, wacom_wac);
-                       /* fall through */
-               case INTUOS3S:
-                       input_dev_i3s(input_dev, wacom_wac);
-               case INTUOS:
-                       input_dev_i(input_dev, wacom_wac);
-                       break;
-               case PL:
-               case PTU:
-                       input_dev_pl(input_dev, wacom_wac);
-                       break;
-               case PENPARTNER:
-                       input_dev_pt(input_dev, wacom_wac);
-                       break;
-       }
-       return;
-}
-
-static struct wacom_features wacom_features[] = {
-       { "Wacom Penpartner",    7,   5040,  3780,  255,  0, PENPARTNER },
-        { "Wacom Graphire",      8,  10206,  7422,  511, 63, GRAPHIRE },
-       { "Wacom Graphire2 4x5", 8,  10206,  7422,  511, 63, GRAPHIRE },
-       { "Wacom Graphire2 5x7", 8,  13918, 10206,  511, 63, GRAPHIRE },
-       { "Wacom Graphire3",     8,  10208,  7424,  511, 63, GRAPHIRE },
-       { "Wacom Graphire3 6x8", 8,  16704, 12064,  511, 63, GRAPHIRE },
-       { "Wacom Graphire4 4x5", 8,  10208,  7424,  511, 63, WACOM_G4 },
-       { "Wacom Graphire4 6x8", 8,  16704, 12064,  511, 63, WACOM_G4 },
-       { "Wacom Volito",        8,   5104,  3712,  511, 63, GRAPHIRE },
-       { "Wacom PenStation2",   8,   3250,  2320,  255, 63, GRAPHIRE },
-       { "Wacom Volito2 4x5",   8,   5104,  3712,  511, 63, GRAPHIRE },
-       { "Wacom Volito2 2x3",   8,   3248,  2320,  511, 63, GRAPHIRE },
-       { "Wacom PenPartner2",   8,   3250,  2320,  255, 63, GRAPHIRE },
-       { "Wacom Intuos 4x5",   10,  12700, 10600, 1023, 31, INTUOS },
-       { "Wacom Intuos 6x8",   10,  20320, 16240, 1023, 31, INTUOS },
-       { "Wacom Intuos 9x12",  10,  30480, 24060, 1023, 31, INTUOS },
-       { "Wacom Intuos 12x12", 10,  30480, 31680, 1023, 31, INTUOS },
-       { "Wacom Intuos 12x18", 10,  45720, 31680, 1023, 31, INTUOS },
-       { "Wacom PL400",         8,   5408,  4056,  255,  0, PL },
-       { "Wacom PL500",         8,   6144,  4608,  255,  0, PL },
-       { "Wacom PL600",         8,   6126,  4604,  255,  0, PL },
-       { "Wacom PL600SX",       8,   6260,  5016,  255,  0, PL },
-       { "Wacom PL550",         8,   6144,  4608,  511,  0, PL },
-       { "Wacom PL800",         8,   7220,  5780,  511,  0, PL },
-       { "Wacom PL700",         8,   6758,  5406,  511,  0, PL },
-       { "Wacom PL510",         8,   6282,  4762,  511,  0, PL },
-       { "Wacom DTU710",        8,  34080, 27660,  511,  0, PL },
-       { "Wacom DTF521",        8,   6282,  4762,  511,  0, PL },
-       { "Wacom DTF720",        8,   6858,  5506,  511,  0, PL },
-       { "Wacom Cintiq Partner",8,  20480, 15360,  511,  0, PTU },
-       { "Wacom Intuos2 4x5",   10, 12700, 10600, 1023, 31, INTUOS },
-       { "Wacom Intuos2 6x8",   10, 20320, 16240, 1023, 31, INTUOS },
-       { "Wacom Intuos2 9x12",  10, 30480, 24060, 1023, 31, INTUOS },
-       { "Wacom Intuos2 12x12", 10, 30480, 31680, 1023, 31, INTUOS },
-       { "Wacom Intuos2 12x18", 10, 45720, 31680, 1023, 31, INTUOS },
-       { "Wacom Intuos3 4x5",   10, 25400, 20320, 1023, 63, INTUOS3S },
-       { "Wacom Intuos3 6x8",   10, 40640, 30480, 1023, 63, INTUOS3 },
-       { "Wacom Intuos3 9x12",  10, 60960, 45720, 1023, 63, INTUOS3 },
-       { "Wacom Intuos3 12x12", 10, 60960, 60960, 1023, 63, INTUOS3L },
-       { "Wacom Intuos3 12x19", 10, 97536, 60960, 1023, 63, INTUOS3L },
-       { "Wacom Intuos3 6x11",  10, 54204, 31750, 1023, 63, INTUOS3 },
-       { "Wacom Intuos3 4x6",   10, 31496, 19685, 1023, 63, INTUOS3S },
-       { "Wacom Cintiq 21UX",   10, 87200, 65600, 1023, 63, CINTIQ },
-       { "Wacom Intuos2 6x8",   10, 20320, 16240, 1023, 31, INTUOS },
-       { }
-};
-
-static struct usb_device_id wacom_ids[] = {
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x00) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x10) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x11) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x12) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x13) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x14) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x15) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x16) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x60) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x61) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x62) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x63) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x64) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x20) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x21) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x22) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x23) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x24) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x30) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x31) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x32) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x33) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x34) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x35) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x37) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x38) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x39) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC0) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC4) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x03) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x41) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x42) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x43) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x44) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x45) },
-       { 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, 0xB3) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB4) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB5) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB7) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x3F) },
-       { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x47) },
-       { }
-};
-
-const struct usb_device_id * get_device_table(void) {
-        const struct usb_device_id * id_table = wacom_ids;
-        return id_table;
-}
-
-struct wacom_features * get_wacom_feature(const struct usb_device_id * id) {
-        int index = id - wacom_ids;
-        struct wacom_features *wf = &wacom_features[index];
-        return wf;
-}
-
-MODULE_DEVICE_TABLE(usb, wacom_ids);
diff --git a/drivers/usb/input/wacom_wac.h b/drivers/usb/input/wacom_wac.h
deleted file mode 100644 (file)
index 8979366..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * drivers/usb/input/wacom_wac.h
- *
- * 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.
- */
-#ifndef WACOM_WAC_H
-#define WACOM_WAC_H
-
-#define STYLUS_DEVICE_ID       0x02
-#define CURSOR_DEVICE_ID       0x06
-#define ERASER_DEVICE_ID       0x0A
-#define PAD_DEVICE_ID          0x0F
-
-enum {
-       PENPARTNER = 0,
-       GRAPHIRE,
-       WACOM_G4,
-       PTU,
-       PL,
-       INTUOS,
-       INTUOS3S,
-       INTUOS3,
-       INTUOS3L,
-       CINTIQ,
-       MAX_TYPE
-};
-
-struct wacom_features {
-       char *name;
-       int pktlen;
-       int x_max;
-       int y_max;
-       int pressure_max;
-       int distance_max;
-       int type;
-};
-
-struct wacom_wac {
-       unsigned char *data;
-        int tool[2];
-        int id[2];
-        __u32 serial[2];
-       struct wacom_features *features;
-};
-
-#endif