Input: usbtouchscreen - add support for Zytronic capacitive touchscreen
[safe/jmp/linux-2.6] / drivers / input / touchscreen / usbtouchscreen.c
index 792b270..4474e23 100644 (file)
@@ -13,6 +13,8 @@
  *  - IdealTEK URTC1000
  *  - General Touch
  *  - GoTop Super_Q2/GogoPen/PenPower tablets
+ *  - JASTEC USB touch controller/DigiTech DTR-02U
+ *  - Zytronic capacitive touchscreen
  *
  * Copyright (C) 2004-2007 by Daniel Ritz <daniel.ritz@gmx.ch>
  * Copyright (C) by Todd E. Johnson (mtouchusb.c)
@@ -49,6 +51,7 @@
 #include <linux/init.h>
 #include <linux/usb.h>
 #include <linux/usb/input.h>
+#include <linux/hid.h>
 
 
 #define DRIVER_VERSION         "v0.6"
@@ -59,6 +62,10 @@ static int swap_xy;
 module_param(swap_xy, bool, 0644);
 MODULE_PARM_DESC(swap_xy, "If set X and Y axes are swapped.");
 
+static int hwcalib_xy;
+module_param(hwcalib_xy, bool, 0644);
+MODULE_PARM_DESC(hwcalib_xy, "If set hw-calibrated X/Y are used if available");
+
 /* device specifc data/functions */
 struct usbtouch_usb;
 struct usbtouch_device_info {
@@ -67,6 +74,15 @@ struct usbtouch_device_info {
        int min_press, max_press;
        int rept_size;
 
+       /*
+        * Always service the USB devices irq not just when the input device is
+        * open. This is useful when devices have a watchdog which prevents us
+        * from periodically polling the device. Leave this unset unless your
+        * touchscreen device requires it, as it does consume more of the USB
+        * bandwidth.
+        */
+       bool irq_always;
+
        void (*process_pkt) (struct usbtouch_usb *usbtouch, unsigned char *pkt, int len);
 
        /*
@@ -101,7 +117,7 @@ struct usbtouch_usb {
 
 /* device types */
 enum {
-       DEVTPYE_DUMMY = -1,
+       DEVTYPE_IGNORE = -1,
        DEVTYPE_EGALAX,
        DEVTYPE_PANJIT,
        DEVTYPE_3M,
@@ -113,10 +129,27 @@ enum {
        DEVTYPE_IDEALTEK,
        DEVTYPE_GENERAL_TOUCH,
        DEVTYPE_GOTOP,
+       DEVTYPE_JASTEC,
+       DEVTYPE_E2I,
+       DEVTYPE_ZYTRONIC,
 };
 
+#define USB_DEVICE_HID_CLASS(vend, prod) \
+       .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS \
+               | USB_DEVICE_ID_MATCH_INT_PROTOCOL \
+               | USB_DEVICE_ID_MATCH_DEVICE, \
+       .idVendor = (vend), \
+       .idProduct = (prod), \
+       .bInterfaceClass = USB_INTERFACE_CLASS_HID, \
+       .bInterfaceProtocol = USB_INTERFACE_PROTOCOL_MOUSE
+
 static struct usb_device_id usbtouch_devices[] = {
 #ifdef CONFIG_TOUCHSCREEN_USB_EGALAX
+       /* ignore the HID capable devices, handled by usbhid */
+       {USB_DEVICE_HID_CLASS(0x0eef, 0x0001), .driver_info = DEVTYPE_IGNORE},
+       {USB_DEVICE_HID_CLASS(0x0eef, 0x0002), .driver_info = DEVTYPE_IGNORE},
+
+       /* normal device IDs */
        {USB_DEVICE(0x3823, 0x0001), .driver_info = DEVTYPE_EGALAX},
        {USB_DEVICE(0x3823, 0x0002), .driver_info = DEVTYPE_EGALAX},
        {USB_DEVICE(0x0123, 0x0001), .driver_info = DEVTYPE_EGALAX},
@@ -172,11 +205,56 @@ static struct usb_device_id usbtouch_devices[] = {
        {USB_DEVICE(0x08f2, 0x00f4), .driver_info = DEVTYPE_GOTOP},
 #endif
 
+#ifdef CONFIG_TOUCHSCREEN_USB_JASTEC
+       {USB_DEVICE(0x0f92, 0x0001), .driver_info = DEVTYPE_JASTEC},
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_E2I
+       {USB_DEVICE(0x1ac7, 0x0001), .driver_info = DEVTYPE_E2I},
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_ZYTRONIC
+       {USB_DEVICE(0x14c8, 0x0003), .driver_info = DEVTYPE_ZYTRONIC},
+#endif
+
        {}
 };
 
 
 /*****************************************************************************
+ * e2i Part
+ */
+
+#ifdef CONFIG_TOUCHSCREEN_USB_E2I
+static int e2i_init(struct usbtouch_usb *usbtouch)
+{
+       int ret;
+
+       ret = usb_control_msg(usbtouch->udev, usb_rcvctrlpipe(usbtouch->udev, 0),
+                             0x01, 0x02, 0x0000, 0x0081,
+                             NULL, 0, USB_CTRL_SET_TIMEOUT);
+
+       dbg("%s - usb_control_msg - E2I_RESET - bytes|err: %d",
+           __func__, ret);
+       return ret;
+}
+
+static int e2i_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
+{
+       int tmp = (pkt[0] << 8) | pkt[1];
+       dev->x  = (pkt[2] << 8) | pkt[3];
+       dev->y  = (pkt[4] << 8) | pkt[5];
+
+       tmp = tmp - 0xA000;
+       dev->touch = (tmp > 0);
+       dev->press = (tmp > 0 ? tmp : 0);
+
+       return 1;
+}
+#endif
+
+
+/*****************************************************************************
  * eGalax part
  */
 
@@ -246,8 +324,13 @@ static int panjit_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
 
 static int mtouch_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
 {
-       dev->x = (pkt[8] << 8) | pkt[7];
-       dev->y = (pkt[10] << 8) | pkt[9];
+       if (hwcalib_xy) {
+               dev->x = (pkt[4] << 8) | pkt[3];
+               dev->y = 0xffff - ((pkt[6] << 8) | pkt[5]);
+       } else {
+               dev->x = (pkt[8] << 8) | pkt[7];
+               dev->y = (pkt[10] << 8) | pkt[9];
+       }
        dev->touch = (pkt[2] & 0x40) ? 1 : 0;
 
        return 1;
@@ -280,6 +363,12 @@ static int mtouch_init(struct usbtouch_usb *usbtouch)
                        return ret;
        }
 
+       /* Default min/max xy are the raw values, override if using hw-calib */
+       if (hwcalib_xy) {
+               input_set_abs_params(usbtouch->input, ABS_X, 0, 0xffff, 0, 0);
+               input_set_abs_params(usbtouch->input, ABS_Y, 0, 0xffff, 0, 0);
+       }
+
        return 0;
 }
 #endif
@@ -410,7 +499,7 @@ static int dmc_tsc10_init(struct usbtouch_usb *usbtouch)
                              0, 0, buf, 2, USB_CTRL_SET_TIMEOUT);
        if (ret < 0)
                goto err_out;
-       if (buf[0] != 0x06 || buf[1] != 0x00) {
+       if (buf[0] != 0x06) {
                ret = -ENODEV;
                goto err_out;
        }
@@ -423,8 +512,7 @@ static int dmc_tsc10_init(struct usbtouch_usb *usbtouch)
                              TSC10_RATE_150, 0, buf, 2, USB_CTRL_SET_TIMEOUT);
        if (ret < 0)
                goto err_out;
-       if ((buf[0] != 0x06 || buf[1] != 0x00) &&
-           (buf[0] != 0x15 || buf[1] != 0x01)) {
+       if ((buf[0] != 0x06) && (buf[0] != 0x15 || buf[1] != 0x01)) {
                ret = -ENODEV;
                goto err_out;
        }
@@ -530,10 +618,58 @@ static int gotop_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
        dev->x = ((pkt[1] & 0x38) << 4) | pkt[2];
        dev->y = ((pkt[1] & 0x07) << 7) | pkt[3];
        dev->touch = pkt[0] & 0x01;
+
+       return 1;
+}
+#endif
+
+/*****************************************************************************
+ * JASTEC Part
+ */
+#ifdef CONFIG_TOUCHSCREEN_USB_JASTEC
+static int jastec_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
+{
+       dev->x = ((pkt[0] & 0x3f) << 6) | (pkt[2] & 0x3f);
+       dev->y = ((pkt[1] & 0x3f) << 6) | (pkt[3] & 0x3f);
+       dev->touch = (pkt[0] & 0x40) >> 6;
+
        return 1;
 }
 #endif
 
+/*****************************************************************************
+ * Zytronic Part
+ */
+#ifdef CONFIG_TOUCHSCREEN_USB_ZYTRONIC
+static int zytronic_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
+{
+       switch (pkt[0]) {
+       case 0x3A: /* command response */
+               dbg("%s: Command response %d", __func__, pkt[1]);
+               break;
+
+       case 0xC0: /* down */
+               dev->x = (pkt[1] & 0x7f) | ((pkt[2] & 0x07) << 7);
+               dev->y = (pkt[3] & 0x7f) | ((pkt[4] & 0x07) << 7);
+               dev->touch = 1;
+               dbg("%s: down %d,%d", __func__, dev->x, dev->y);
+               return 1;
+
+       case 0x80: /* up */
+               dev->x = (pkt[1] & 0x7f) | ((pkt[2] & 0x07) << 7);
+               dev->y = (pkt[3] & 0x7f) | ((pkt[4] & 0x07) << 7);
+               dev->touch = 0;
+               dbg("%s: up %d,%d", __func__, dev->x, dev->y);
+               return 1;
+
+       default:
+               dbg("%s: Unknown return %d", __func__, pkt[0]);
+               break;
+       }
+
+       return 0;
+}
+#endif
 
 /*****************************************************************************
  * the different device descriptors
@@ -673,6 +809,41 @@ static struct usbtouch_device_info usbtouch_dev_info[] = {
                .read_data      = gotop_read_data,
        },
 #endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_JASTEC
+       [DEVTYPE_JASTEC] = {
+               .min_xc         = 0x0,
+               .max_xc         = 0x0fff,
+               .min_yc         = 0x0,
+               .max_yc         = 0x0fff,
+               .rept_size      = 4,
+               .read_data      = jastec_read_data,
+       },
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_E2I
+       [DEVTYPE_E2I] = {
+               .min_xc         = 0x0,
+               .max_xc         = 0x7fff,
+               .min_yc         = 0x0,
+               .max_yc         = 0x7fff,
+               .rept_size      = 6,
+               .init           = e2i_init,
+               .read_data      = e2i_read_data,
+       },
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_ZYTRONIC
+       [DEVTYPE_ZYTRONIC] = {
+               .min_xc         = 0x0,
+               .max_xc         = 0x03ff,
+               .min_yc         = 0x0,
+               .max_yc         = 0x03ff,
+               .rept_size      = 5,
+               .read_data      = zytronic_read_data,
+               .irq_always     = true,
+       },
+#endif
 };
 
 
@@ -823,8 +994,10 @@ static int usbtouch_open(struct input_dev *input)
 
        usbtouch->irq->dev = usbtouch->udev;
 
-       if (usb_submit_urb(usbtouch->irq, GFP_KERNEL))
-               return -EIO;
+       if (!usbtouch->type->irq_always) {
+               if (usb_submit_urb(usbtouch->irq, GFP_KERNEL))
+                 return -EIO;
+       }
 
        return 0;
 }
@@ -833,7 +1006,8 @@ static void usbtouch_close(struct input_dev *input)
 {
        struct usbtouch_usb *usbtouch = input_get_drvdata(input);
 
-       usb_kill_urb(usbtouch->irq);
+       if (!usbtouch->type->irq_always)
+               usb_kill_urb(usbtouch->irq);
 }
 
 
@@ -857,6 +1031,10 @@ static int usbtouch_probe(struct usb_interface *intf,
        struct usbtouch_device_info *type;
        int err = -ENOMEM;
 
+       /* some devices are ignored */
+       if (id->driver_info == DEVTYPE_IGNORE)
+               return -ENODEV;
+
        interface = intf->cur_altsetting;
        endpoint = &interface->endpoint[0].desc;
 
@@ -952,6 +1130,9 @@ static int usbtouch_probe(struct usb_interface *intf,
 
        usb_set_intfdata(intf, usbtouch);
 
+       if (usbtouch->type->irq_always)
+               usb_submit_urb(usbtouch->irq, GFP_KERNEL);
+
        return 0;
 
 out_free_buffers:
@@ -973,7 +1154,7 @@ static void usbtouch_disconnect(struct usb_interface *intf)
 
        dbg("%s - usbtouch is initialized, cleaning up", __func__);
        usb_set_intfdata(intf, NULL);
-       usb_kill_urb(usbtouch->irq);
+       /* this will stop IO via close */
        input_unregister_device(usbtouch->input);
        usb_free_urb(usbtouch->irq);
        usbtouch_free_buffers(interface_to_usbdev(intf), usbtouch);