diff options
Diffstat (limited to 'drivers/usb/misc/idmouse.c')
-rw-r--r-- | drivers/usb/misc/idmouse.c | 149 |
1 files changed, 88 insertions, 61 deletions
diff --git a/drivers/usb/misc/idmouse.c b/drivers/usb/misc/idmouse.c index ce030d1f1c1f..733acc213726 100644 --- a/drivers/usb/misc/idmouse.c +++ b/drivers/usb/misc/idmouse.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* Siemens ID Mouse driver v0.5 | 1 | /* Siemens ID Mouse driver v0.6 |
2 | 2 | ||
3 | This program is free software; you can redistribute it and/or | 3 | This program is free software; you can redistribute it and/or |
4 | modify it under the terms of the GNU General Public License as | 4 | modify it under the terms of the GNU General Public License as |
@@ -11,6 +11,9 @@ | |||
11 | Derived from the USB Skeleton driver 1.1, | 11 | Derived from the USB Skeleton driver 1.1, |
12 | Copyright (C) 2003 Greg Kroah-Hartman (greg@kroah.com) | 12 | Copyright (C) 2003 Greg Kroah-Hartman (greg@kroah.com) |
13 | 13 | ||
14 | Additional information provided by Martin Reising | ||
15 | <Martin.Reising@natural-computing.de> | ||
16 | |||
14 | */ | 17 | */ |
15 | 18 | ||
16 | #include <linux/config.h> | 19 | #include <linux/config.h> |
@@ -25,29 +28,44 @@ | |||
25 | #include <asm/uaccess.h> | 28 | #include <asm/uaccess.h> |
26 | #include <linux/usb.h> | 29 | #include <linux/usb.h> |
27 | 30 | ||
31 | /* image constants */ | ||
28 | #define WIDTH 225 | 32 | #define WIDTH 225 |
29 | #define HEIGHT 288 | 33 | #define HEIGHT 289 |
30 | #define HEADER "P5 225 288 255 " | 34 | #define HEADER "P5 225 289 255 " |
31 | #define IMGSIZE ((WIDTH * HEIGHT) + sizeof(HEADER)-1) | 35 | #define IMGSIZE ((WIDTH * HEIGHT) + sizeof(HEADER)-1) |
32 | 36 | ||
33 | /* Version Information */ | 37 | /* version information */ |
34 | #define DRIVER_VERSION "0.5" | 38 | #define DRIVER_VERSION "0.6" |
35 | #define DRIVER_SHORT "idmouse" | 39 | #define DRIVER_SHORT "idmouse" |
36 | #define DRIVER_AUTHOR "Florian 'Floe' Echtler <echtler@fs.tum.de>" | 40 | #define DRIVER_AUTHOR "Florian 'Floe' Echtler <echtler@fs.tum.de>" |
37 | #define DRIVER_DESC "Siemens ID Mouse FingerTIP Sensor Driver" | 41 | #define DRIVER_DESC "Siemens ID Mouse FingerTIP Sensor Driver" |
38 | 42 | ||
39 | /* Siemens ID Mouse */ | 43 | /* minor number for misc USB devices */ |
40 | #define USB_IDMOUSE_VENDOR_ID 0x0681 | ||
41 | #define USB_IDMOUSE_PRODUCT_ID 0x0005 | ||
42 | |||
43 | /* we still need a minor number */ | ||
44 | #define USB_IDMOUSE_MINOR_BASE 132 | 44 | #define USB_IDMOUSE_MINOR_BASE 132 |
45 | 45 | ||
46 | /* vendor and device IDs */ | ||
47 | #define ID_SIEMENS 0x0681 | ||
48 | #define ID_IDMOUSE 0x0005 | ||
49 | #define ID_CHERRY 0x0010 | ||
50 | |||
51 | /* device ID table */ | ||
46 | static struct usb_device_id idmouse_table[] = { | 52 | static struct usb_device_id idmouse_table[] = { |
47 | {USB_DEVICE(USB_IDMOUSE_VENDOR_ID, USB_IDMOUSE_PRODUCT_ID)}, | 53 | {USB_DEVICE(ID_SIEMENS, ID_IDMOUSE)}, /* Siemens ID Mouse (Professional) */ |
48 | {} /* null entry at the end */ | 54 | {USB_DEVICE(ID_SIEMENS, ID_CHERRY )}, /* Cherry FingerTIP ID Board */ |
55 | {} /* terminating null entry */ | ||
49 | }; | 56 | }; |
50 | 57 | ||
58 | /* sensor commands */ | ||
59 | #define FTIP_RESET 0x20 | ||
60 | #define FTIP_ACQUIRE 0x21 | ||
61 | #define FTIP_RELEASE 0x22 | ||
62 | #define FTIP_BLINK 0x23 /* LSB of value = blink pulse width */ | ||
63 | #define FTIP_SCROLL 0x24 | ||
64 | |||
65 | #define ftip_command(dev, command, value, index) \ | ||
66 | usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0), command, \ | ||
67 | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT, value, index, NULL, 0, 1000) | ||
68 | |||
51 | MODULE_DEVICE_TABLE(usb, idmouse_table); | 69 | MODULE_DEVICE_TABLE(usb, idmouse_table); |
52 | 70 | ||
53 | /* structure to hold all of our device specific stuff */ | 71 | /* structure to hold all of our device specific stuff */ |
@@ -57,7 +75,8 @@ struct usb_idmouse { | |||
57 | struct usb_interface *interface; /* the interface for this device */ | 75 | struct usb_interface *interface; /* the interface for this device */ |
58 | 76 | ||
59 | unsigned char *bulk_in_buffer; /* the buffer to receive data */ | 77 | unsigned char *bulk_in_buffer; /* the buffer to receive data */ |
60 | size_t bulk_in_size; /* the size of the receive buffer */ | 78 | size_t bulk_in_size; /* the maximum bulk packet size */ |
79 | size_t orig_bi_size; /* same as above, but reported by the device */ | ||
61 | __u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */ | 80 | __u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */ |
62 | 81 | ||
63 | int open; /* if the port is open or not */ | 82 | int open; /* if the port is open or not */ |
@@ -103,7 +122,7 @@ static struct usb_driver idmouse_driver = { | |||
103 | .id_table = idmouse_table, | 122 | .id_table = idmouse_table, |
104 | }; | 123 | }; |
105 | 124 | ||
106 | // prevent races between open() and disconnect() | 125 | /* prevent races between open() and disconnect() */ |
107 | static DECLARE_MUTEX(disconnect_sem); | 126 | static DECLARE_MUTEX(disconnect_sem); |
108 | 127 | ||
109 | static int idmouse_create_image(struct usb_idmouse *dev) | 128 | static int idmouse_create_image(struct usb_idmouse *dev) |
@@ -112,42 +131,34 @@ static int idmouse_create_image(struct usb_idmouse *dev) | |||
112 | int bulk_read = 0; | 131 | int bulk_read = 0; |
113 | int result = 0; | 132 | int result = 0; |
114 | 133 | ||
115 | if (dev->bulk_in_size < sizeof(HEADER)) | 134 | memcpy(dev->bulk_in_buffer, HEADER, sizeof(HEADER)-1); |
116 | return -ENOMEM; | ||
117 | |||
118 | memcpy(dev->bulk_in_buffer,HEADER,sizeof(HEADER)-1); | ||
119 | bytes_read += sizeof(HEADER)-1; | 135 | bytes_read += sizeof(HEADER)-1; |
120 | 136 | ||
121 | /* Dump the setup packets. Yes, they are uncommented, simply | 137 | /* reset the device and set a fast blink rate */ |
122 | because they were sniffed under Windows using SnoopyPro. | 138 | result = ftip_command(dev, FTIP_RELEASE, 0, 0); |
123 | I _guess_ that 0x22 is a kind of reset command and 0x21 | ||
124 | means init.. | ||
125 | */ | ||
126 | result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0), | ||
127 | 0x21, 0x42, 0x0001, 0x0002, NULL, 0, 1000); | ||
128 | if (result < 0) | ||
129 | return result; | ||
130 | result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0), | ||
131 | 0x20, 0x42, 0x0001, 0x0002, NULL, 0, 1000); | ||
132 | if (result < 0) | 139 | if (result < 0) |
133 | return result; | 140 | goto reset; |
134 | result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0), | 141 | result = ftip_command(dev, FTIP_BLINK, 1, 0); |
135 | 0x22, 0x42, 0x0000, 0x0002, NULL, 0, 1000); | ||
136 | if (result < 0) | 142 | if (result < 0) |
137 | return result; | 143 | goto reset; |
138 | 144 | ||
139 | result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0), | 145 | /* initialize the sensor - sending this command twice */ |
140 | 0x21, 0x42, 0x0001, 0x0002, NULL, 0, 1000); | 146 | /* significantly reduces the rate of failed reads */ |
147 | result = ftip_command(dev, FTIP_ACQUIRE, 0, 0); | ||
141 | if (result < 0) | 148 | if (result < 0) |
142 | return result; | 149 | goto reset; |
143 | result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0), | 150 | result = ftip_command(dev, FTIP_ACQUIRE, 0, 0); |
144 | 0x20, 0x42, 0x0001, 0x0002, NULL, 0, 1000); | ||
145 | if (result < 0) | 151 | if (result < 0) |
146 | return result; | 152 | goto reset; |
147 | result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0), | 153 | |
148 | 0x20, 0x42, 0x0000, 0x0002, NULL, 0, 1000); | 154 | /* start the readout - sending this command twice */ |
155 | /* presumably enables the high dynamic range mode */ | ||
156 | result = ftip_command(dev, FTIP_RESET, 0, 0); | ||
149 | if (result < 0) | 157 | if (result < 0) |
150 | return result; | 158 | goto reset; |
159 | result = ftip_command(dev, FTIP_RESET, 0, 0); | ||
160 | if (result < 0) | ||
161 | goto reset; | ||
151 | 162 | ||
152 | /* loop over a blocking bulk read to get data from the device */ | 163 | /* loop over a blocking bulk read to get data from the device */ |
153 | while (bytes_read < IMGSIZE) { | 164 | while (bytes_read < IMGSIZE) { |
@@ -155,22 +166,40 @@ static int idmouse_create_image(struct usb_idmouse *dev) | |||
155 | usb_rcvbulkpipe (dev->udev, dev->bulk_in_endpointAddr), | 166 | usb_rcvbulkpipe (dev->udev, dev->bulk_in_endpointAddr), |
156 | dev->bulk_in_buffer + bytes_read, | 167 | dev->bulk_in_buffer + bytes_read, |
157 | dev->bulk_in_size, &bulk_read, 5000); | 168 | dev->bulk_in_size, &bulk_read, 5000); |
158 | if (result < 0) | 169 | if (result < 0) { |
159 | return result; | 170 | /* Maybe this error was caused by the increased packet size? */ |
160 | if (signal_pending(current)) | 171 | /* Reset to the original value and tell userspace to retry. */ |
161 | return -EINTR; | 172 | if (dev->bulk_in_size != dev->orig_bi_size) { |
173 | dev->bulk_in_size = dev->orig_bi_size; | ||
174 | result = -EAGAIN; | ||
175 | } | ||
176 | break; | ||
177 | } | ||
178 | if (signal_pending(current)) { | ||
179 | result = -EINTR; | ||
180 | break; | ||
181 | } | ||
162 | bytes_read += bulk_read; | 182 | bytes_read += bulk_read; |
163 | } | 183 | } |
164 | 184 | ||
165 | /* reset the device */ | 185 | /* reset the device */ |
166 | result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0), | 186 | reset: |
167 | 0x22, 0x42, 0x0000, 0x0002, NULL, 0, 1000); | 187 | ftip_command(dev, FTIP_RELEASE, 0, 0); |
168 | if (result < 0) | 188 | |
169 | return result; | 189 | /* check for valid image */ |
190 | /* right border should be black (0x00) */ | ||
191 | for (bytes_read = sizeof(HEADER)-1 + WIDTH-1; bytes_read < IMGSIZE; bytes_read += WIDTH) | ||
192 | if (dev->bulk_in_buffer[bytes_read] != 0x00) | ||
193 | return -EAGAIN; | ||
170 | 194 | ||
171 | /* should be IMGSIZE == 64815 */ | 195 | /* lower border should be white (0xFF) */ |
196 | for (bytes_read = IMGSIZE-WIDTH; bytes_read < IMGSIZE-1; bytes_read++) | ||
197 | if (dev->bulk_in_buffer[bytes_read] != 0xFF) | ||
198 | return -EAGAIN; | ||
199 | |||
200 | /* should be IMGSIZE == 65040 */ | ||
172 | dbg("read %d bytes fingerprint data", bytes_read); | 201 | dbg("read %d bytes fingerprint data", bytes_read); |
173 | return 0; | 202 | return result; |
174 | } | 203 | } |
175 | 204 | ||
176 | static inline void idmouse_delete(struct usb_idmouse *dev) | 205 | static inline void idmouse_delete(struct usb_idmouse *dev) |
@@ -282,10 +311,10 @@ static ssize_t idmouse_read(struct file *file, char __user *buffer, size_t count | |||
282 | 311 | ||
283 | dev = (struct usb_idmouse *) file->private_data; | 312 | dev = (struct usb_idmouse *) file->private_data; |
284 | 313 | ||
285 | // lock this object | 314 | /* lock this object */ |
286 | down (&dev->sem); | 315 | down (&dev->sem); |
287 | 316 | ||
288 | // verify that the device wasn't unplugged | 317 | /* verify that the device wasn't unplugged */ |
289 | if (!dev->present) { | 318 | if (!dev->present) { |
290 | up (&dev->sem); | 319 | up (&dev->sem); |
291 | return -ENODEV; | 320 | return -ENODEV; |
@@ -296,8 +325,7 @@ static ssize_t idmouse_read(struct file *file, char __user *buffer, size_t count | |||
296 | return 0; | 325 | return 0; |
297 | } | 326 | } |
298 | 327 | ||
299 | if (count > IMGSIZE - *ppos) | 328 | count = min ((loff_t)count, IMGSIZE - (*ppos)); |
300 | count = IMGSIZE - *ppos; | ||
301 | 329 | ||
302 | if (copy_to_user (buffer, dev->bulk_in_buffer + *ppos, count)) { | 330 | if (copy_to_user (buffer, dev->bulk_in_buffer + *ppos, count)) { |
303 | result = -EFAULT; | 331 | result = -EFAULT; |
@@ -306,7 +334,7 @@ static ssize_t idmouse_read(struct file *file, char __user *buffer, size_t count | |||
306 | *ppos += count; | 334 | *ppos += count; |
307 | } | 335 | } |
308 | 336 | ||
309 | // unlock the device | 337 | /* unlock the device */ |
310 | up(&dev->sem); | 338 | up(&dev->sem); |
311 | return result; | 339 | return result; |
312 | } | 340 | } |
@@ -318,7 +346,6 @@ static int idmouse_probe(struct usb_interface *interface, | |||
318 | struct usb_idmouse *dev = NULL; | 346 | struct usb_idmouse *dev = NULL; |
319 | struct usb_host_interface *iface_desc; | 347 | struct usb_host_interface *iface_desc; |
320 | struct usb_endpoint_descriptor *endpoint; | 348 | struct usb_endpoint_descriptor *endpoint; |
321 | size_t buffer_size; | ||
322 | int result; | 349 | int result; |
323 | 350 | ||
324 | /* check if we have gotten the data or the hid interface */ | 351 | /* check if we have gotten the data or the hid interface */ |
@@ -344,11 +371,11 @@ static int idmouse_probe(struct usb_interface *interface, | |||
344 | USB_ENDPOINT_XFER_BULK)) { | 371 | USB_ENDPOINT_XFER_BULK)) { |
345 | 372 | ||
346 | /* we found a bulk in endpoint */ | 373 | /* we found a bulk in endpoint */ |
347 | buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); | 374 | dev->orig_bi_size = le16_to_cpu(endpoint->wMaxPacketSize); |
348 | dev->bulk_in_size = buffer_size; | 375 | dev->bulk_in_size = 0x200; /* works _much_ faster */ |
349 | dev->bulk_in_endpointAddr = endpoint->bEndpointAddress; | 376 | dev->bulk_in_endpointAddr = endpoint->bEndpointAddress; |
350 | dev->bulk_in_buffer = | 377 | dev->bulk_in_buffer = |
351 | kmalloc(IMGSIZE + buffer_size, GFP_KERNEL); | 378 | kmalloc(IMGSIZE + dev->bulk_in_size, GFP_KERNEL); |
352 | 379 | ||
353 | if (!dev->bulk_in_buffer) { | 380 | if (!dev->bulk_in_buffer) { |
354 | err("Unable to allocate input buffer."); | 381 | err("Unable to allocate input buffer."); |