aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/misc/idmouse.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/misc/idmouse.c')
-rw-r--r--drivers/usb/misc/idmouse.c149
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 */
46static struct usb_device_id idmouse_table[] = { 52static 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
51MODULE_DEVICE_TABLE(usb, idmouse_table); 69MODULE_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() */
107static DECLARE_MUTEX(disconnect_sem); 126static DECLARE_MUTEX(disconnect_sem);
108 127
109static int idmouse_create_image(struct usb_idmouse *dev) 128static 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), 186reset:
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
176static inline void idmouse_delete(struct usb_idmouse *dev) 205static 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.");