diff options
author | Ondrej Zary <linux@rainbow-software.org> | 2010-02-04 03:17:18 -0500 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2010-02-04 03:21:56 -0500 |
commit | 5197424cdcccd2b0b1922babb93969b2515c43ce (patch) | |
tree | 0dc1d6adda483519c20b3af650c2dcb6683d7e25 /drivers | |
parent | f4a5e359c4bafc2269766ccd74256024160ed7ac (diff) |
Input: usbtouchscreen - add NEXIO (or iNexio) support
Add support for NEXIO (or iNexio) USB touchscreens to usbtouchscreen
driver. Tested with NEX170MRT 17" LCD monitor with integrated touchscreen
(with xserver-xorg-input-evtouch 0.8.8-1):
T: Bus=02 Lev=01 Prnt=01 Port=01 Cnt=01 Dev#= 54 Spd=12 MxCh= 0
D: Ver= 1.10 Cls=02(comm.) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1
P: Vendor=1870 ProdID=0001 Rev= 1.00
S: Manufacturer=iNexio
S: Product=iNexio USB
C:* #Ifs= 2 Cfg#= 1 Atr=c0 MxPwr=500mA
I:* If#= 0 Alt= 0 #EPs= 1 Cls=02(comm.) Sub=02 Prot=00 Driver=(none)
E: Ad=83(I) Atr=03(Int.) MxPS= 8 Ivl=255ms
I:* If#= 1 Alt= 0 #EPs= 2 Cls=0a(data ) Sub=00 Prot=00 Driver=(none)
E: Ad=01(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms
E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms
No datasheet is available, this was written by capturing some data with
SniffUSB in Windows: http://www.rainbow-software.org/linux_files/nexio/
Signed-off-by: Ondrej Zary <linux@rainbow-software.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/input/touchscreen/Kconfig | 5 | ||||
-rw-r--r-- | drivers/input/touchscreen/usbtouchscreen.c | 261 |
2 files changed, 264 insertions, 2 deletions
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index dfafc76da4fb..a1e2d845f680 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig | |||
@@ -537,6 +537,11 @@ config TOUCHSCREEN_USB_ETT_TC5UH | |||
537 | bool "ET&T TC5UH touchscreen controler support" if EMBEDDED | 537 | bool "ET&T TC5UH touchscreen controler support" if EMBEDDED |
538 | depends on TOUCHSCREEN_USB_COMPOSITE | 538 | depends on TOUCHSCREEN_USB_COMPOSITE |
539 | 539 | ||
540 | config TOUCHSCREEN_USB_NEXIO | ||
541 | default y | ||
542 | bool "NEXIO/iNexio device support" if EMBEDDED | ||
543 | depends on TOUCHSCREEN_USB_COMPOSITE | ||
544 | |||
540 | config TOUCHSCREEN_TOUCHIT213 | 545 | config TOUCHSCREEN_TOUCHIT213 |
541 | tristate "Sahara TouchIT-213 touchscreen" | 546 | tristate "Sahara TouchIT-213 touchscreen" |
542 | select SERIO | 547 | select SERIO |
diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c index a2a82351a42f..07656efee654 100644 --- a/drivers/input/touchscreen/usbtouchscreen.c +++ b/drivers/input/touchscreen/usbtouchscreen.c | |||
@@ -15,6 +15,7 @@ | |||
15 | * - GoTop Super_Q2/GogoPen/PenPower tablets | 15 | * - GoTop Super_Q2/GogoPen/PenPower tablets |
16 | * - JASTEC USB touch controller/DigiTech DTR-02U | 16 | * - JASTEC USB touch controller/DigiTech DTR-02U |
17 | * - Zytronic capacitive touchscreen | 17 | * - Zytronic capacitive touchscreen |
18 | * - NEXIO/iNexio | ||
18 | * | 19 | * |
19 | * Copyright (C) 2004-2007 by Daniel Ritz <daniel.ritz@gmx.ch> | 20 | * Copyright (C) 2004-2007 by Daniel Ritz <daniel.ritz@gmx.ch> |
20 | * Copyright (C) by Todd E. Johnson (mtouchusb.c) | 21 | * Copyright (C) by Todd E. Johnson (mtouchusb.c) |
@@ -95,6 +96,7 @@ struct usbtouch_device_info { | |||
95 | 96 | ||
96 | int (*read_data) (struct usbtouch_usb *usbtouch, unsigned char *pkt); | 97 | int (*read_data) (struct usbtouch_usb *usbtouch, unsigned char *pkt); |
97 | int (*init) (struct usbtouch_usb *usbtouch); | 98 | int (*init) (struct usbtouch_usb *usbtouch); |
99 | void (*exit) (struct usbtouch_usb *usbtouch); | ||
98 | }; | 100 | }; |
99 | 101 | ||
100 | /* a usbtouch device */ | 102 | /* a usbtouch device */ |
@@ -109,6 +111,7 @@ struct usbtouch_usb { | |||
109 | struct usbtouch_device_info *type; | 111 | struct usbtouch_device_info *type; |
110 | char name[128]; | 112 | char name[128]; |
111 | char phys[64]; | 113 | char phys[64]; |
114 | void *priv; | ||
112 | 115 | ||
113 | int x, y; | 116 | int x, y; |
114 | int touch, press; | 117 | int touch, press; |
@@ -133,6 +136,7 @@ enum { | |||
133 | DEVTYPE_E2I, | 136 | DEVTYPE_E2I, |
134 | DEVTYPE_ZYTRONIC, | 137 | DEVTYPE_ZYTRONIC, |
135 | DEVTYPE_TC5UH, | 138 | DEVTYPE_TC5UH, |
139 | DEVTYPE_NEXIO, | ||
136 | }; | 140 | }; |
137 | 141 | ||
138 | #define USB_DEVICE_HID_CLASS(vend, prod) \ | 142 | #define USB_DEVICE_HID_CLASS(vend, prod) \ |
@@ -222,6 +226,14 @@ static const struct usb_device_id usbtouch_devices[] = { | |||
222 | {USB_DEVICE(0x0664, 0x0309), .driver_info = DEVTYPE_TC5UH}, | 226 | {USB_DEVICE(0x0664, 0x0309), .driver_info = DEVTYPE_TC5UH}, |
223 | #endif | 227 | #endif |
224 | 228 | ||
229 | #ifdef CONFIG_TOUCHSCREEN_USB_NEXIO | ||
230 | /* data interface only */ | ||
231 | {USB_DEVICE_AND_INTERFACE_INFO(0x10f0, 0x2002, 0x0a, 0x00, 0x00), | ||
232 | .driver_info = DEVTYPE_NEXIO}, | ||
233 | {USB_DEVICE_AND_INTERFACE_INFO(0x1870, 0x0001, 0x0a, 0x00, 0x00), | ||
234 | .driver_info = DEVTYPE_NEXIO}, | ||
235 | #endif | ||
236 | |||
225 | {} | 237 | {} |
226 | }; | 238 | }; |
227 | 239 | ||
@@ -692,6 +704,229 @@ static int zytronic_read_data(struct usbtouch_usb *dev, unsigned char *pkt) | |||
692 | #endif | 704 | #endif |
693 | 705 | ||
694 | /***************************************************************************** | 706 | /***************************************************************************** |
707 | * NEXIO Part | ||
708 | */ | ||
709 | #ifdef CONFIG_TOUCHSCREEN_USB_NEXIO | ||
710 | |||
711 | #define NEXIO_TIMEOUT 5000 | ||
712 | #define NEXIO_BUFSIZE 1024 | ||
713 | #define NEXIO_THRESHOLD 50 | ||
714 | |||
715 | struct nexio_priv { | ||
716 | struct urb *ack; | ||
717 | unsigned char *ack_buf; | ||
718 | }; | ||
719 | |||
720 | struct nexio_touch_packet { | ||
721 | u8 flags; /* 0xe1 = touch, 0xe1 = release */ | ||
722 | __be16 data_len; /* total bytes of touch data */ | ||
723 | __be16 x_len; /* bytes for X axis */ | ||
724 | __be16 y_len; /* bytes for Y axis */ | ||
725 | u8 data[]; | ||
726 | } __attribute__ ((packed)); | ||
727 | |||
728 | static unsigned char nexio_ack_pkt[2] = { 0xaa, 0x02 }; | ||
729 | static unsigned char nexio_init_pkt[4] = { 0x82, 0x04, 0x0a, 0x0f }; | ||
730 | |||
731 | static void nexio_ack_complete(struct urb *urb) | ||
732 | { | ||
733 | } | ||
734 | |||
735 | static int nexio_init(struct usbtouch_usb *usbtouch) | ||
736 | { | ||
737 | struct usb_device *dev = interface_to_usbdev(usbtouch->interface); | ||
738 | struct usb_host_interface *interface = usbtouch->interface->cur_altsetting; | ||
739 | struct nexio_priv *priv; | ||
740 | int ret = -ENOMEM; | ||
741 | int actual_len, i; | ||
742 | unsigned char *buf; | ||
743 | char *firmware_ver = NULL, *device_name = NULL; | ||
744 | int input_ep = 0, output_ep = 0; | ||
745 | |||
746 | /* find first input and output endpoint */ | ||
747 | for (i = 0; i < interface->desc.bNumEndpoints; i++) { | ||
748 | if (!input_ep && | ||
749 | usb_endpoint_dir_in(&interface->endpoint[i].desc)) | ||
750 | input_ep = interface->endpoint[i].desc.bEndpointAddress; | ||
751 | if (!output_ep && | ||
752 | usb_endpoint_dir_out(&interface->endpoint[i].desc)) | ||
753 | output_ep = interface->endpoint[i].desc.bEndpointAddress; | ||
754 | } | ||
755 | if (!input_ep || !output_ep) | ||
756 | return -ENXIO; | ||
757 | |||
758 | buf = kmalloc(NEXIO_BUFSIZE, GFP_KERNEL); | ||
759 | if (!buf) | ||
760 | goto out_buf; | ||
761 | |||
762 | /* two empty reads */ | ||
763 | for (i = 0; i < 2; i++) { | ||
764 | ret = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, input_ep), | ||
765 | buf, NEXIO_BUFSIZE, &actual_len, | ||
766 | NEXIO_TIMEOUT); | ||
767 | if (ret < 0) | ||
768 | goto out_buf; | ||
769 | } | ||
770 | |||
771 | /* send init command */ | ||
772 | memcpy(buf, nexio_init_pkt, sizeof(nexio_init_pkt)); | ||
773 | ret = usb_bulk_msg(dev, usb_sndbulkpipe(dev, output_ep), | ||
774 | buf, sizeof(nexio_init_pkt), &actual_len, | ||
775 | NEXIO_TIMEOUT); | ||
776 | if (ret < 0) | ||
777 | goto out_buf; | ||
778 | |||
779 | /* read replies */ | ||
780 | for (i = 0; i < 3; i++) { | ||
781 | memset(buf, 0, NEXIO_BUFSIZE); | ||
782 | ret = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, input_ep), | ||
783 | buf, NEXIO_BUFSIZE, &actual_len, | ||
784 | NEXIO_TIMEOUT); | ||
785 | if (ret < 0 || actual_len < 1 || buf[1] != actual_len) | ||
786 | continue; | ||
787 | switch (buf[0]) { | ||
788 | case 0x83: /* firmware version */ | ||
789 | if (!firmware_ver) | ||
790 | firmware_ver = kstrdup(&buf[2], GFP_KERNEL); | ||
791 | break; | ||
792 | case 0x84: /* device name */ | ||
793 | if (!device_name) | ||
794 | device_name = kstrdup(&buf[2], GFP_KERNEL); | ||
795 | break; | ||
796 | } | ||
797 | } | ||
798 | |||
799 | printk(KERN_INFO "Nexio device: %s, firmware version: %s\n", | ||
800 | device_name, firmware_ver); | ||
801 | |||
802 | kfree(firmware_ver); | ||
803 | kfree(device_name); | ||
804 | |||
805 | /* prepare ACK URB */ | ||
806 | ret = -ENOMEM; | ||
807 | |||
808 | usbtouch->priv = kmalloc(sizeof(struct nexio_priv), GFP_KERNEL); | ||
809 | if (!usbtouch->priv) | ||
810 | goto out_buf; | ||
811 | |||
812 | priv = usbtouch->priv; | ||
813 | |||
814 | priv->ack_buf = kmalloc(sizeof(nexio_ack_pkt), GFP_KERNEL); | ||
815 | if (!priv->ack_buf) | ||
816 | goto err_priv; | ||
817 | |||
818 | memcpy(priv->ack_buf, nexio_ack_pkt, sizeof(nexio_ack_pkt)); | ||
819 | |||
820 | priv->ack = usb_alloc_urb(0, GFP_KERNEL); | ||
821 | if (!priv->ack) { | ||
822 | dbg("%s - usb_alloc_urb failed: usbtouch->ack", __func__); | ||
823 | goto err_ack_buf; | ||
824 | } | ||
825 | |||
826 | usb_fill_bulk_urb(priv->ack, dev, usb_sndbulkpipe(dev, output_ep), | ||
827 | priv->ack_buf, sizeof(nexio_ack_pkt), | ||
828 | nexio_ack_complete, usbtouch); | ||
829 | ret = 0; | ||
830 | goto out_buf; | ||
831 | |||
832 | err_ack_buf: | ||
833 | kfree(priv->ack_buf); | ||
834 | err_priv: | ||
835 | kfree(priv); | ||
836 | out_buf: | ||
837 | kfree(buf); | ||
838 | return ret; | ||
839 | } | ||
840 | |||
841 | static void nexio_exit(struct usbtouch_usb *usbtouch) | ||
842 | { | ||
843 | struct nexio_priv *priv = usbtouch->priv; | ||
844 | |||
845 | usb_kill_urb(priv->ack); | ||
846 | usb_free_urb(priv->ack); | ||
847 | kfree(priv->ack_buf); | ||
848 | kfree(priv); | ||
849 | } | ||
850 | |||
851 | static int nexio_read_data(struct usbtouch_usb *usbtouch, unsigned char *pkt) | ||
852 | { | ||
853 | int x, y, begin_x, begin_y, end_x, end_y, w, h, ret; | ||
854 | struct nexio_touch_packet *packet = (void *) pkt; | ||
855 | struct nexio_priv *priv = usbtouch->priv; | ||
856 | |||
857 | /* got touch data? */ | ||
858 | if ((pkt[0] & 0xe0) != 0xe0) | ||
859 | return 0; | ||
860 | |||
861 | /* send ACK */ | ||
862 | ret = usb_submit_urb(priv->ack, GFP_ATOMIC); | ||
863 | |||
864 | if (!usbtouch->type->max_xc) { | ||
865 | usbtouch->type->max_xc = 2 * be16_to_cpu(packet->x_len); | ||
866 | input_set_abs_params(usbtouch->input, ABS_X, 0, | ||
867 | 2 * be16_to_cpu(packet->x_len), 0, 0); | ||
868 | usbtouch->type->max_yc = 2 * be16_to_cpu(packet->y_len); | ||
869 | input_set_abs_params(usbtouch->input, ABS_Y, 0, | ||
870 | 2 * be16_to_cpu(packet->y_len), 0, 0); | ||
871 | } | ||
872 | /* | ||
873 | * The device reports state of IR sensors on X and Y axes. | ||
874 | * Each byte represents "darkness" percentage (0-100) of one element. | ||
875 | * 17" touchscreen reports only 64 x 52 bytes so the resolution is low. | ||
876 | * This also means that there's a limited multi-touch capability but | ||
877 | * it's disabled (and untested) here as there's no X driver for that. | ||
878 | */ | ||
879 | begin_x = end_x = begin_y = end_y = -1; | ||
880 | for (x = 0; x < be16_to_cpu(packet->x_len); x++) { | ||
881 | if (begin_x == -1 && packet->data[x] > NEXIO_THRESHOLD) { | ||
882 | begin_x = x; | ||
883 | continue; | ||
884 | } | ||
885 | if (end_x == -1 && begin_x != -1 && packet->data[x] < NEXIO_THRESHOLD) { | ||
886 | end_x = x - 1; | ||
887 | for (y = be16_to_cpu(packet->x_len); | ||
888 | y < be16_to_cpu(packet->data_len); y++) { | ||
889 | if (begin_y == -1 && packet->data[y] > NEXIO_THRESHOLD) { | ||
890 | begin_y = y - be16_to_cpu(packet->x_len); | ||
891 | continue; | ||
892 | } | ||
893 | if (end_y == -1 && | ||
894 | begin_y != -1 && packet->data[y] < NEXIO_THRESHOLD) { | ||
895 | end_y = y - 1 - be16_to_cpu(packet->x_len); | ||
896 | w = end_x - begin_x; | ||
897 | h = end_y - begin_y; | ||
898 | #if 0 | ||
899 | /* multi-touch */ | ||
900 | input_report_abs(usbtouch->input, | ||
901 | ABS_MT_TOUCH_MAJOR, max(w,h)); | ||
902 | input_report_abs(usbtouch->input, | ||
903 | ABS_MT_TOUCH_MINOR, min(x,h)); | ||
904 | input_report_abs(usbtouch->input, | ||
905 | ABS_MT_POSITION_X, 2*begin_x+w); | ||
906 | input_report_abs(usbtouch->input, | ||
907 | ABS_MT_POSITION_Y, 2*begin_y+h); | ||
908 | input_report_abs(usbtouch->input, | ||
909 | ABS_MT_ORIENTATION, w > h); | ||
910 | input_mt_sync(usbtouch->input); | ||
911 | #endif | ||
912 | /* single touch */ | ||
913 | usbtouch->x = 2 * begin_x + w; | ||
914 | usbtouch->y = 2 * begin_y + h; | ||
915 | usbtouch->touch = packet->flags & 0x01; | ||
916 | begin_y = end_y = -1; | ||
917 | return 1; | ||
918 | } | ||
919 | } | ||
920 | begin_x = end_x = -1; | ||
921 | } | ||
922 | |||
923 | } | ||
924 | return 0; | ||
925 | } | ||
926 | #endif | ||
927 | |||
928 | |||
929 | /***************************************************************************** | ||
695 | * the different device descriptors | 930 | * the different device descriptors |
696 | */ | 931 | */ |
697 | #ifdef MULTI_PACKET | 932 | #ifdef MULTI_PACKET |
@@ -875,6 +1110,16 @@ static struct usbtouch_device_info usbtouch_dev_info[] = { | |||
875 | .read_data = tc5uh_read_data, | 1110 | .read_data = tc5uh_read_data, |
876 | }, | 1111 | }, |
877 | #endif | 1112 | #endif |
1113 | |||
1114 | #ifdef CONFIG_TOUCHSCREEN_USB_NEXIO | ||
1115 | [DEVTYPE_NEXIO] = { | ||
1116 | .rept_size = 128, | ||
1117 | .irq_always = true, | ||
1118 | .read_data = nexio_read_data, | ||
1119 | .init = nexio_init, | ||
1120 | .exit = nexio_exit, | ||
1121 | }, | ||
1122 | #endif | ||
878 | }; | 1123 | }; |
879 | 1124 | ||
880 | 1125 | ||
@@ -1000,6 +1245,7 @@ static void usbtouch_irq(struct urb *urb) | |||
1000 | case -ECONNRESET: | 1245 | case -ECONNRESET: |
1001 | case -ENOENT: | 1246 | case -ENOENT: |
1002 | case -ESHUTDOWN: | 1247 | case -ESHUTDOWN: |
1248 | case -EPIPE: | ||
1003 | /* this urb is terminated, clean up */ | 1249 | /* this urb is terminated, clean up */ |
1004 | dbg("%s - urb shutting down with status: %d", | 1250 | dbg("%s - urb shutting down with status: %d", |
1005 | __func__, urb->status); | 1251 | __func__, urb->status); |
@@ -1146,10 +1392,16 @@ static int usbtouch_probe(struct usb_interface *intf, | |||
1146 | input_set_abs_params(input_dev, ABS_PRESSURE, type->min_press, | 1392 | input_set_abs_params(input_dev, ABS_PRESSURE, type->min_press, |
1147 | type->max_press, 0, 0); | 1393 | type->max_press, 0, 0); |
1148 | 1394 | ||
1149 | usb_fill_int_urb(usbtouch->irq, udev, | 1395 | if (usb_endpoint_type(endpoint) == USB_ENDPOINT_XFER_INT) |
1396 | usb_fill_int_urb(usbtouch->irq, udev, | ||
1150 | usb_rcvintpipe(udev, endpoint->bEndpointAddress), | 1397 | usb_rcvintpipe(udev, endpoint->bEndpointAddress), |
1151 | usbtouch->data, type->rept_size, | 1398 | usbtouch->data, type->rept_size, |
1152 | usbtouch_irq, usbtouch, endpoint->bInterval); | 1399 | usbtouch_irq, usbtouch, endpoint->bInterval); |
1400 | else | ||
1401 | usb_fill_bulk_urb(usbtouch->irq, udev, | ||
1402 | usb_rcvbulkpipe(udev, endpoint->bEndpointAddress), | ||
1403 | usbtouch->data, type->rept_size, | ||
1404 | usbtouch_irq, usbtouch); | ||
1153 | 1405 | ||
1154 | usbtouch->irq->dev = udev; | 1406 | usbtouch->irq->dev = udev; |
1155 | usbtouch->irq->transfer_dma = usbtouch->data_dma; | 1407 | usbtouch->irq->transfer_dma = usbtouch->data_dma; |
@@ -1167,7 +1419,7 @@ static int usbtouch_probe(struct usb_interface *intf, | |||
1167 | err = input_register_device(usbtouch->input); | 1419 | err = input_register_device(usbtouch->input); |
1168 | if (err) { | 1420 | if (err) { |
1169 | dbg("%s - input_register_device failed, err: %d", __func__, err); | 1421 | dbg("%s - input_register_device failed, err: %d", __func__, err); |
1170 | goto out_free_buffers; | 1422 | goto out_do_exit; |
1171 | } | 1423 | } |
1172 | 1424 | ||
1173 | usb_set_intfdata(intf, usbtouch); | 1425 | usb_set_intfdata(intf, usbtouch); |
@@ -1177,6 +1429,9 @@ static int usbtouch_probe(struct usb_interface *intf, | |||
1177 | 1429 | ||
1178 | return 0; | 1430 | return 0; |
1179 | 1431 | ||
1432 | out_do_exit: | ||
1433 | if (type->exit) | ||
1434 | type->exit(usbtouch); | ||
1180 | out_free_buffers: | 1435 | out_free_buffers: |
1181 | usbtouch_free_buffers(udev, usbtouch); | 1436 | usbtouch_free_buffers(udev, usbtouch); |
1182 | out_free: | 1437 | out_free: |
@@ -1199,6 +1454,8 @@ static void usbtouch_disconnect(struct usb_interface *intf) | |||
1199 | /* this will stop IO via close */ | 1454 | /* this will stop IO via close */ |
1200 | input_unregister_device(usbtouch->input); | 1455 | input_unregister_device(usbtouch->input); |
1201 | usb_free_urb(usbtouch->irq); | 1456 | usb_free_urb(usbtouch->irq); |
1457 | if (usbtouch->type->exit) | ||
1458 | usbtouch->type->exit(usbtouch); | ||
1202 | usbtouch_free_buffers(interface_to_usbdev(intf), usbtouch); | 1459 | usbtouch_free_buffers(interface_to_usbdev(intf), usbtouch); |
1203 | kfree(usbtouch); | 1460 | kfree(usbtouch); |
1204 | } | 1461 | } |