Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v2.6.14 266 lines 7.5 kB view raw
1/****************************************************************************** 2 * itmtouch.c -- Driver for ITM touchscreen panel 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License as 6 * published by the Free Software Foundation; either version 2 of the 7 * License, or (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, but 10 * WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 17 * 18 * Based upon original work by Chris Collins <xfire-itmtouch@xware.cx>. 19 * 20 * Kudos to ITM for providing me with the datasheet for the panel, 21 * even though it was a day later than I had finished writing this 22 * driver. 23 * 24 * It has meant that I've been able to correct my interpretation of the 25 * protocol packets however. 26 * 27 * CC -- 2003/9/29 28 * 29 * History 30 * 1.0 & 1.1 2003 (CC) vojtech@suse.cz 31 * Original version for 2.4.x kernels 32 * 33 * 1.2 02/03/2005 (HCE) hc@mivu.no 34 * Complete rewrite to support Linux 2.6.10, thanks to mtouchusb.c for hints. 35 * Unfortunately no calibration support at this time. 36 * 37 * 1.2.1 09/03/2005 (HCE) hc@mivu.no 38 * Code cleanup and adjusting syntax to start matching kernel standards 39 * 40 *****************************************************************************/ 41 42#include <linux/config.h> 43 44#ifdef CONFIG_USB_DEBUG 45 #define DEBUG 46#else 47 #undef DEBUG 48#endif 49 50#include <linux/kernel.h> 51#include <linux/slab.h> 52#include <linux/input.h> 53#include <linux/module.h> 54#include <linux/init.h> 55#include <linux/usb.h> 56#include <linux/usb_input.h> 57 58/* only an 8 byte buffer necessary for a single packet */ 59#define ITM_BUFSIZE 8 60#define PATH_SIZE 64 61 62#define USB_VENDOR_ID_ITMINC 0x0403 63#define USB_PRODUCT_ID_TOUCHPANEL 0xf9e9 64 65#define DRIVER_AUTHOR "Hans-Christian Egtvedt <hc@mivu.no>" 66#define DRIVER_VERSION "v1.2.1" 67#define DRIVER_DESC "USB ITM Inc Touch Panel Driver" 68#define DRIVER_LICENSE "GPL" 69 70MODULE_AUTHOR( DRIVER_AUTHOR ); 71MODULE_DESCRIPTION( DRIVER_DESC ); 72MODULE_LICENSE( DRIVER_LICENSE ); 73 74struct itmtouch_dev { 75 struct usb_device *usbdev; /* usb device */ 76 struct input_dev inputdev; /* input device */ 77 struct urb *readurb; /* urb */ 78 char rbuf[ITM_BUFSIZE]; /* data */ 79 int users; 80 char name[128]; 81 char phys[64]; 82}; 83 84static struct usb_device_id itmtouch_ids [] = { 85 { USB_DEVICE(USB_VENDOR_ID_ITMINC, USB_PRODUCT_ID_TOUCHPANEL) }, 86 { } 87}; 88 89static void itmtouch_irq(struct urb *urb, struct pt_regs *regs) 90{ 91 struct itmtouch_dev * itmtouch = urb->context; 92 unsigned char *data = urb->transfer_buffer; 93 struct input_dev *dev = &itmtouch->inputdev; 94 int retval; 95 96 switch (urb->status) { 97 case 0: 98 /* success */ 99 break; 100 case -ETIMEDOUT: 101 /* this urb is timing out */ 102 dbg("%s - urb timed out - was the device unplugged?", 103 __FUNCTION__); 104 return; 105 case -ECONNRESET: 106 case -ENOENT: 107 case -ESHUTDOWN: 108 /* this urb is terminated, clean up */ 109 dbg("%s - urb shutting down with status: %d", 110 __FUNCTION__, urb->status); 111 return; 112 default: 113 dbg("%s - nonzero urb status received: %d", 114 __FUNCTION__, urb->status); 115 goto exit; 116 } 117 118 input_regs(dev, regs); 119 120 /* if pressure has been released, then don't report X/Y */ 121 if (data[7] & 0x20) { 122 input_report_abs(dev, ABS_X, (data[0] & 0x1F) << 7 | (data[3] & 0x7F)); 123 input_report_abs(dev, ABS_Y, (data[1] & 0x1F) << 7 | (data[4] & 0x7F)); 124 } 125 126 input_report_abs(dev, ABS_PRESSURE, (data[2] & 1) << 7 | (data[5] & 0x7F)); 127 input_report_key(dev, BTN_TOUCH, ~data[7] & 0x20); 128 input_sync(dev); 129 130exit: 131 retval = usb_submit_urb (urb, GFP_ATOMIC); 132 if (retval) 133 printk(KERN_ERR "%s - usb_submit_urb failed with result: %d", 134 __FUNCTION__, retval); 135} 136 137static int itmtouch_open(struct input_dev *input) 138{ 139 struct itmtouch_dev *itmtouch = input->private; 140 141 itmtouch->readurb->dev = itmtouch->usbdev; 142 143 if (usb_submit_urb(itmtouch->readurb, GFP_KERNEL)) 144 return -EIO; 145 146 return 0; 147} 148 149static void itmtouch_close(struct input_dev *input) 150{ 151 struct itmtouch_dev *itmtouch = input->private; 152 153 usb_kill_urb(itmtouch->readurb); 154} 155 156static int itmtouch_probe(struct usb_interface *intf, const struct usb_device_id *id) 157{ 158 struct itmtouch_dev *itmtouch; 159 struct usb_host_interface *interface; 160 struct usb_endpoint_descriptor *endpoint; 161 struct usb_device *udev = interface_to_usbdev(intf); 162 unsigned int pipe; 163 unsigned int maxp; 164 char path[PATH_SIZE]; 165 166 interface = intf->cur_altsetting; 167 endpoint = &interface->endpoint[0].desc; 168 169 if (!(itmtouch = kzalloc(sizeof(struct itmtouch_dev), GFP_KERNEL))) { 170 err("%s - Out of memory.", __FUNCTION__); 171 return -ENOMEM; 172 } 173 174 itmtouch->usbdev = udev; 175 176 itmtouch->inputdev.private = itmtouch; 177 itmtouch->inputdev.open = itmtouch_open; 178 itmtouch->inputdev.close = itmtouch_close; 179 180 usb_make_path(udev, path, PATH_SIZE); 181 182 itmtouch->inputdev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); 183 itmtouch->inputdev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE); 184 itmtouch->inputdev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); 185 186 itmtouch->inputdev.name = itmtouch->name; 187 itmtouch->inputdev.phys = itmtouch->phys; 188 usb_to_input_id(udev, &itmtouch->inputdev.id); 189 itmtouch->inputdev.dev = &intf->dev; 190 191 if (!strlen(itmtouch->name)) 192 sprintf(itmtouch->name, "USB ITM touchscreen"); 193 194 /* device limits */ 195 /* as specified by the ITM datasheet, X and Y are 12bit, 196 * Z (pressure) is 8 bit. However, the fields are defined up 197 * to 14 bits for future possible expansion. 198 */ 199 input_set_abs_params(&itmtouch->inputdev, ABS_X, 0, 0x0FFF, 2, 0); 200 input_set_abs_params(&itmtouch->inputdev, ABS_Y, 0, 0x0FFF, 2, 0); 201 input_set_abs_params(&itmtouch->inputdev, ABS_PRESSURE, 0, 0xFF, 2, 0); 202 203 /* initialise the URB so we can read from the transport stream */ 204 pipe = usb_rcvintpipe(itmtouch->usbdev, endpoint->bEndpointAddress); 205 maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); 206 207 if (maxp > ITM_BUFSIZE) 208 maxp = ITM_BUFSIZE; 209 210 itmtouch->readurb = usb_alloc_urb(0, GFP_KERNEL); 211 212 if (!itmtouch->readurb) { 213 dbg("%s - usb_alloc_urb failed: itmtouch->readurb", __FUNCTION__); 214 kfree(itmtouch); 215 return -ENOMEM; 216 } 217 218 usb_fill_int_urb(itmtouch->readurb, itmtouch->usbdev, pipe, itmtouch->rbuf, 219 maxp, itmtouch_irq, itmtouch, endpoint->bInterval); 220 221 input_register_device(&itmtouch->inputdev); 222 223 printk(KERN_INFO "itmtouch: %s registered on %s\n", itmtouch->name, path); 224 usb_set_intfdata(intf, itmtouch); 225 226 return 0; 227} 228 229static void itmtouch_disconnect(struct usb_interface *intf) 230{ 231 struct itmtouch_dev *itmtouch = usb_get_intfdata(intf); 232 233 usb_set_intfdata(intf, NULL); 234 235 if (itmtouch) { 236 input_unregister_device(&itmtouch->inputdev); 237 usb_kill_urb(itmtouch->readurb); 238 usb_free_urb(itmtouch->readurb); 239 kfree(itmtouch); 240 } 241} 242 243MODULE_DEVICE_TABLE(usb, itmtouch_ids); 244 245static struct usb_driver itmtouch_driver = { 246 .owner = THIS_MODULE, 247 .name = "itmtouch", 248 .probe = itmtouch_probe, 249 .disconnect = itmtouch_disconnect, 250 .id_table = itmtouch_ids, 251}; 252 253static int __init itmtouch_init(void) 254{ 255 info(DRIVER_DESC " " DRIVER_VERSION); 256 info(DRIVER_AUTHOR); 257 return usb_register(&itmtouch_driver); 258} 259 260static void __exit itmtouch_exit(void) 261{ 262 usb_deregister(&itmtouch_driver); 263} 264 265module_init(itmtouch_init); 266module_exit(itmtouch_exit);