diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/usb/input/mtouchusb.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/usb/input/mtouchusb.c')
-rw-r--r-- | drivers/usb/input/mtouchusb.c | 367 |
1 files changed, 367 insertions, 0 deletions
diff --git a/drivers/usb/input/mtouchusb.c b/drivers/usb/input/mtouchusb.c new file mode 100644 index 000000000000..6b45a66d58c1 --- /dev/null +++ b/drivers/usb/input/mtouchusb.c | |||
@@ -0,0 +1,367 @@ | |||
1 | /****************************************************************************** | ||
2 | * mtouchusb.c -- Driver for Microtouch (Now 3M) USB Touchscreens | ||
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 Radoslaw Garbacz (usb-support@ite.pl) | ||
19 | * (http://freshmeat.net/projects/3mtouchscreendriver) | ||
20 | * | ||
21 | * History | ||
22 | * | ||
23 | * 0.3 & 0.4 2002 (TEJ) tejohnson@yahoo.com | ||
24 | * Updated to 2.4.18, then 2.4.19 | ||
25 | * Old version still relied on stealing a minor | ||
26 | * | ||
27 | * 0.5 02/26/2004 (TEJ) tejohnson@yahoo.com | ||
28 | * Complete rewrite using Linux Input in 2.6.3 | ||
29 | * Unfortunately no calibration support at this time | ||
30 | * | ||
31 | * 1.4 04/25/2004 (TEJ) tejohnson@yahoo.com | ||
32 | * Changed reset from standard USB dev reset to vendor reset | ||
33 | * Changed data sent to host from compensated to raw coordinates | ||
34 | * Eliminated vendor/product module params | ||
35 | * Performed multiple successfull tests with an EXII-5010UC | ||
36 | * | ||
37 | * 1.5 02/27/2005 ddstreet@ieee.org | ||
38 | * Added module parameter to select raw or hw-calibrated coordinate reporting | ||
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 | |||
57 | #define MTOUCHUSB_MIN_XC 0x0 | ||
58 | #define MTOUCHUSB_MAX_RAW_XC 0x4000 | ||
59 | #define MTOUCHUSB_MAX_CALIB_XC 0xffff | ||
60 | #define MTOUCHUSB_XC_FUZZ 0x0 | ||
61 | #define MTOUCHUSB_XC_FLAT 0x0 | ||
62 | #define MTOUCHUSB_MIN_YC 0x0 | ||
63 | #define MTOUCHUSB_MAX_RAW_YC 0x4000 | ||
64 | #define MTOUCHUSB_MAX_CALIB_YC 0xffff | ||
65 | #define MTOUCHUSB_YC_FUZZ 0x0 | ||
66 | #define MTOUCHUSB_YC_FLAT 0x0 | ||
67 | |||
68 | #define MTOUCHUSB_ASYNC_REPORT 1 | ||
69 | #define MTOUCHUSB_RESET 7 | ||
70 | #define MTOUCHUSB_REPORT_DATA_SIZE 11 | ||
71 | #define MTOUCHUSB_REQ_CTRLLR_ID 10 | ||
72 | |||
73 | #define MTOUCHUSB_GET_RAW_XC(data) (data[8]<<8 | data[7]) | ||
74 | #define MTOUCHUSB_GET_CALIB_XC(data) (data[4]<<8 | data[3]) | ||
75 | #define MTOUCHUSB_GET_RAW_YC(data) (data[10]<<8 | data[9]) | ||
76 | #define MTOUCHUSB_GET_CALIB_YC(data) (data[6]<<8 | data[5]) | ||
77 | #define MTOUCHUSB_GET_XC(data) (raw_coordinates ? \ | ||
78 | MTOUCHUSB_GET_RAW_XC(data) : \ | ||
79 | MTOUCHUSB_GET_CALIB_XC(data)) | ||
80 | #define MTOUCHUSB_GET_YC(data) (raw_coordinates ? \ | ||
81 | MTOUCHUSB_GET_RAW_YC(data) : \ | ||
82 | MTOUCHUSB_GET_CALIB_YC(data)) | ||
83 | #define MTOUCHUSB_GET_TOUCHED(data) ((data[2] & 0x40) ? 1:0) | ||
84 | |||
85 | #define DRIVER_VERSION "v1.5" | ||
86 | #define DRIVER_AUTHOR "Todd E. Johnson, tejohnson@yahoo.com" | ||
87 | #define DRIVER_DESC "3M USB Touchscreen Driver" | ||
88 | #define DRIVER_LICENSE "GPL" | ||
89 | |||
90 | static int raw_coordinates = 1; | ||
91 | |||
92 | module_param(raw_coordinates, bool, S_IRUGO | S_IWUSR); | ||
93 | MODULE_PARM_DESC(raw_coordinates, "report raw coordinate values (y, default) or hardware-calibrated coordinate values (n)"); | ||
94 | |||
95 | struct mtouch_usb { | ||
96 | unsigned char *data; | ||
97 | dma_addr_t data_dma; | ||
98 | struct urb *irq; | ||
99 | struct usb_device *udev; | ||
100 | struct input_dev input; | ||
101 | int open; | ||
102 | char name[128]; | ||
103 | char phys[64]; | ||
104 | }; | ||
105 | |||
106 | static struct usb_device_id mtouchusb_devices [] = { | ||
107 | { USB_DEVICE(0x0596, 0x0001) }, | ||
108 | { } | ||
109 | }; | ||
110 | |||
111 | static void mtouchusb_irq(struct urb *urb, struct pt_regs *regs) | ||
112 | { | ||
113 | struct mtouch_usb *mtouch = urb->context; | ||
114 | int retval; | ||
115 | |||
116 | switch (urb->status) { | ||
117 | case 0: | ||
118 | /* success */ | ||
119 | break; | ||
120 | case -ETIMEDOUT: | ||
121 | /* this urb is timing out */ | ||
122 | dbg("%s - urb timed out - was the device unplugged?", | ||
123 | __FUNCTION__); | ||
124 | return; | ||
125 | case -ECONNRESET: | ||
126 | case -ENOENT: | ||
127 | case -ESHUTDOWN: | ||
128 | /* this urb is terminated, clean up */ | ||
129 | dbg("%s - urb shutting down with status: %d", | ||
130 | __FUNCTION__, urb->status); | ||
131 | return; | ||
132 | default: | ||
133 | dbg("%s - nonzero urb status received: %d", | ||
134 | __FUNCTION__, urb->status); | ||
135 | goto exit; | ||
136 | } | ||
137 | |||
138 | input_regs(&mtouch->input, regs); | ||
139 | input_report_key(&mtouch->input, BTN_TOUCH, | ||
140 | MTOUCHUSB_GET_TOUCHED(mtouch->data)); | ||
141 | input_report_abs(&mtouch->input, ABS_X, | ||
142 | MTOUCHUSB_GET_XC(mtouch->data)); | ||
143 | input_report_abs(&mtouch->input, ABS_Y, | ||
144 | (raw_coordinates ? MTOUCHUSB_MAX_RAW_YC : MTOUCHUSB_MAX_CALIB_YC) | ||
145 | - MTOUCHUSB_GET_YC(mtouch->data)); | ||
146 | input_sync(&mtouch->input); | ||
147 | |||
148 | exit: | ||
149 | retval = usb_submit_urb (urb, GFP_ATOMIC); | ||
150 | if (retval) | ||
151 | err ("%s - usb_submit_urb failed with result: %d", | ||
152 | __FUNCTION__, retval); | ||
153 | } | ||
154 | |||
155 | static int mtouchusb_open (struct input_dev *input) | ||
156 | { | ||
157 | struct mtouch_usb *mtouch = input->private; | ||
158 | |||
159 | if (mtouch->open++) | ||
160 | return 0; | ||
161 | |||
162 | mtouch->irq->dev = mtouch->udev; | ||
163 | |||
164 | if (usb_submit_urb (mtouch->irq, GFP_ATOMIC)) { | ||
165 | mtouch->open--; | ||
166 | return -EIO; | ||
167 | } | ||
168 | |||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | static void mtouchusb_close (struct input_dev *input) | ||
173 | { | ||
174 | struct mtouch_usb *mtouch = input->private; | ||
175 | |||
176 | if (!--mtouch->open) | ||
177 | usb_kill_urb (mtouch->irq); | ||
178 | } | ||
179 | |||
180 | static int mtouchusb_alloc_buffers(struct usb_device *udev, struct mtouch_usb *mtouch) | ||
181 | { | ||
182 | dbg("%s - called", __FUNCTION__); | ||
183 | |||
184 | mtouch->data = usb_buffer_alloc(udev, MTOUCHUSB_REPORT_DATA_SIZE, | ||
185 | SLAB_ATOMIC, &mtouch->data_dma); | ||
186 | |||
187 | if (!mtouch->data) | ||
188 | return -1; | ||
189 | |||
190 | return 0; | ||
191 | } | ||
192 | |||
193 | static void mtouchusb_free_buffers(struct usb_device *udev, struct mtouch_usb *mtouch) | ||
194 | { | ||
195 | dbg("%s - called", __FUNCTION__); | ||
196 | |||
197 | if (mtouch->data) | ||
198 | usb_buffer_free(udev, MTOUCHUSB_REPORT_DATA_SIZE, | ||
199 | mtouch->data, mtouch->data_dma); | ||
200 | } | ||
201 | |||
202 | static int mtouchusb_probe(struct usb_interface *intf, const struct usb_device_id *id) | ||
203 | { | ||
204 | struct mtouch_usb *mtouch; | ||
205 | struct usb_host_interface *interface; | ||
206 | struct usb_endpoint_descriptor *endpoint; | ||
207 | struct usb_device *udev = interface_to_usbdev (intf); | ||
208 | char path[64]; | ||
209 | int nRet; | ||
210 | |||
211 | dbg("%s - called", __FUNCTION__); | ||
212 | |||
213 | dbg("%s - setting interface", __FUNCTION__); | ||
214 | interface = intf->cur_altsetting; | ||
215 | |||
216 | dbg("%s - setting endpoint", __FUNCTION__); | ||
217 | endpoint = &interface->endpoint[0].desc; | ||
218 | |||
219 | if (!(mtouch = kmalloc (sizeof (struct mtouch_usb), GFP_KERNEL))) { | ||
220 | err("%s - Out of memory.", __FUNCTION__); | ||
221 | return -ENOMEM; | ||
222 | } | ||
223 | |||
224 | memset(mtouch, 0, sizeof(struct mtouch_usb)); | ||
225 | mtouch->udev = udev; | ||
226 | |||
227 | dbg("%s - allocating buffers", __FUNCTION__); | ||
228 | if (mtouchusb_alloc_buffers(udev, mtouch)) { | ||
229 | mtouchusb_free_buffers(udev, mtouch); | ||
230 | kfree(mtouch); | ||
231 | return -ENOMEM; | ||
232 | } | ||
233 | |||
234 | mtouch->input.private = mtouch; | ||
235 | mtouch->input.open = mtouchusb_open; | ||
236 | mtouch->input.close = mtouchusb_close; | ||
237 | |||
238 | usb_make_path(udev, path, 64); | ||
239 | sprintf(mtouch->phys, "%s/input0", path); | ||
240 | |||
241 | mtouch->input.name = mtouch->name; | ||
242 | mtouch->input.phys = mtouch->phys; | ||
243 | mtouch->input.id.bustype = BUS_USB; | ||
244 | mtouch->input.id.vendor = le16_to_cpu(udev->descriptor.idVendor); | ||
245 | mtouch->input.id.product = le16_to_cpu(udev->descriptor.idProduct); | ||
246 | mtouch->input.id.version = le16_to_cpu(udev->descriptor.bcdDevice); | ||
247 | mtouch->input.dev = &intf->dev; | ||
248 | |||
249 | mtouch->input.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); | ||
250 | mtouch->input.absbit[0] = BIT(ABS_X) | BIT(ABS_Y); | ||
251 | mtouch->input.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); | ||
252 | |||
253 | /* Used to Scale Compensated Data and Flip Y */ | ||
254 | mtouch->input.absmin[ABS_X] = MTOUCHUSB_MIN_XC; | ||
255 | mtouch->input.absmax[ABS_X] = raw_coordinates ? \ | ||
256 | MTOUCHUSB_MAX_RAW_XC : MTOUCHUSB_MAX_CALIB_XC; | ||
257 | mtouch->input.absfuzz[ABS_X] = MTOUCHUSB_XC_FUZZ; | ||
258 | mtouch->input.absflat[ABS_X] = MTOUCHUSB_XC_FLAT; | ||
259 | mtouch->input.absmin[ABS_Y] = MTOUCHUSB_MIN_YC; | ||
260 | mtouch->input.absmax[ABS_Y] = raw_coordinates ? \ | ||
261 | MTOUCHUSB_MAX_RAW_YC : MTOUCHUSB_MAX_CALIB_YC; | ||
262 | mtouch->input.absfuzz[ABS_Y] = MTOUCHUSB_YC_FUZZ; | ||
263 | mtouch->input.absflat[ABS_Y] = MTOUCHUSB_YC_FLAT; | ||
264 | |||
265 | if (udev->manufacturer) | ||
266 | strcat(mtouch->name, udev->manufacturer); | ||
267 | if (udev->product) | ||
268 | sprintf(mtouch->name, "%s %s", mtouch->name, udev->product); | ||
269 | |||
270 | if (!strlen(mtouch->name)) | ||
271 | sprintf(mtouch->name, "USB Touchscreen %04x:%04x", | ||
272 | mtouch->input.id.vendor, mtouch->input.id.product); | ||
273 | |||
274 | nRet = usb_control_msg(mtouch->udev, | ||
275 | usb_rcvctrlpipe(udev, 0), | ||
276 | MTOUCHUSB_RESET, | ||
277 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
278 | 1, | ||
279 | 0, | ||
280 | NULL, | ||
281 | 0, | ||
282 | USB_CTRL_SET_TIMEOUT); | ||
283 | dbg("%s - usb_control_msg - MTOUCHUSB_RESET - bytes|err: %d", | ||
284 | __FUNCTION__, nRet); | ||
285 | |||
286 | dbg("%s - usb_alloc_urb: mtouch->irq", __FUNCTION__); | ||
287 | mtouch->irq = usb_alloc_urb(0, GFP_KERNEL); | ||
288 | if (!mtouch->irq) { | ||
289 | dbg("%s - usb_alloc_urb failed: mtouch->irq", __FUNCTION__); | ||
290 | mtouchusb_free_buffers(udev, mtouch); | ||
291 | kfree(mtouch); | ||
292 | return -ENOMEM; | ||
293 | } | ||
294 | |||
295 | dbg("%s - usb_fill_int_urb", __FUNCTION__); | ||
296 | usb_fill_int_urb(mtouch->irq, | ||
297 | mtouch->udev, | ||
298 | usb_rcvintpipe(mtouch->udev, 0x81), | ||
299 | mtouch->data, | ||
300 | MTOUCHUSB_REPORT_DATA_SIZE, | ||
301 | mtouchusb_irq, | ||
302 | mtouch, | ||
303 | endpoint->bInterval); | ||
304 | |||
305 | dbg("%s - input_register_device", __FUNCTION__); | ||
306 | input_register_device(&mtouch->input); | ||
307 | |||
308 | nRet = usb_control_msg(mtouch->udev, | ||
309 | usb_rcvctrlpipe(udev, 0), | ||
310 | MTOUCHUSB_ASYNC_REPORT, | ||
311 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
312 | 1, | ||
313 | 1, | ||
314 | NULL, | ||
315 | 0, | ||
316 | USB_CTRL_SET_TIMEOUT); | ||
317 | dbg("%s - usb_control_msg - MTOUCHUSB_ASYNC_REPORT - bytes|err: %d", | ||
318 | __FUNCTION__, nRet); | ||
319 | |||
320 | printk(KERN_INFO "input: %s on %s\n", mtouch->name, path); | ||
321 | usb_set_intfdata(intf, mtouch); | ||
322 | |||
323 | return 0; | ||
324 | } | ||
325 | |||
326 | static void mtouchusb_disconnect(struct usb_interface *intf) | ||
327 | { | ||
328 | struct mtouch_usb *mtouch = usb_get_intfdata (intf); | ||
329 | |||
330 | dbg("%s - called", __FUNCTION__); | ||
331 | usb_set_intfdata(intf, NULL); | ||
332 | if (mtouch) { | ||
333 | dbg("%s - mtouch is initialized, cleaning up", __FUNCTION__); | ||
334 | usb_kill_urb(mtouch->irq); | ||
335 | input_unregister_device(&mtouch->input); | ||
336 | usb_free_urb(mtouch->irq); | ||
337 | mtouchusb_free_buffers(interface_to_usbdev(intf), mtouch); | ||
338 | kfree(mtouch); | ||
339 | } | ||
340 | } | ||
341 | |||
342 | MODULE_DEVICE_TABLE (usb, mtouchusb_devices); | ||
343 | |||
344 | static struct usb_driver mtouchusb_driver = { | ||
345 | .owner = THIS_MODULE, | ||
346 | .name = "mtouchusb", | ||
347 | .probe = mtouchusb_probe, | ||
348 | .disconnect = mtouchusb_disconnect, | ||
349 | .id_table = mtouchusb_devices, | ||
350 | }; | ||
351 | |||
352 | static int __init mtouchusb_init(void) { | ||
353 | dbg("%s - called", __FUNCTION__); | ||
354 | return usb_register(&mtouchusb_driver); | ||
355 | } | ||
356 | |||
357 | static void __exit mtouchusb_cleanup(void) { | ||
358 | dbg("%s - called", __FUNCTION__); | ||
359 | usb_deregister(&mtouchusb_driver); | ||
360 | } | ||
361 | |||
362 | module_init(mtouchusb_init); | ||
363 | module_exit(mtouchusb_cleanup); | ||
364 | |||
365 | MODULE_AUTHOR( DRIVER_AUTHOR ); | ||
366 | MODULE_DESCRIPTION( DRIVER_DESC ); | ||
367 | MODULE_LICENSE("GPL"); | ||