ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / drivers / usb / misc / tiglusb.c
1 /* Hey EMACS -*- linux-c -*-
2  *
3  * tiglusb -- Texas Instruments' USB GraphLink (aka SilverLink) driver.
4  * Target: Texas Instruments graphing calculators (http://lpg.ticalc.org).
5  *
6  * Copyright (C) 2001-2004:
7  *   Romain Lievin <roms@lpg.ticalc.org>
8  *   Julien BLACHE <jb@technologeek.org>
9  * under the terms of the GNU General Public License.
10  *
11  * Based on dabusb.c, printer.c & scanner.c
12  *
13  * Please see the file: linux/Documentation/usb/SilverLink.txt
14  * and the website at:  http://lpg.ticalc.org/prj_usb/
15  * for more info.
16  *
17  * History :
18  *   1.0x, Romain & Julien: initial submit.
19  *   1.03, Greg Kroah: modifications.
20  *   1.04, Julien: clean-up & fixes; Romain: 2.4 backport.
21  *   1.05, Randy Dunlap: bug fix with the timeout parameter (divide-by-zero).
22  *   1.06, Romain: synched with 2.5, version/firmware changed (confusing).
23  *   1.07, Romain: fixed bad use of usb_clear_halt (invalid argument);
24  *          timeout argument checked in ioctl + clean-up.
25  */
26
27 #include <linux/module.h>
28 #include <linux/socket.h>
29 #include <linux/slab.h>
30 #include <linux/init.h>
31 #include <asm/uaccess.h>
32 #include <linux/delay.h>
33 #include <linux/usb.h>
34 #include <linux/smp_lock.h>
35 #include <linux/devfs_fs_kernel.h>
36
37 #include <linux/ticable.h>
38 #include "tiglusb.h"
39
40 /*
41  * Version Information
42  */
43 #define DRIVER_VERSION "1.07"
44 #define DRIVER_AUTHOR  "Romain Lievin <roms@tilp.info> & Julien Blache <jb@jblache.org>"
45 #define DRIVER_DESC    "TI-GRAPH LINK USB (aka SilverLink) driver"
46 #define DRIVER_LICENSE "GPL"
47
48 /* ----- global variables --------------------------------------------- */
49
50 static tiglusb_t tiglusb[MAXTIGL];
51 static int timeout = TIMAXTIME; /* timeout in tenth of seconds     */
52
53 /*---------- misc functions ------------------------------------------- */
54
55 /*
56  * Re-initialize device
57  */
58 static inline int
59 clear_device (struct usb_device *dev)
60 {
61         if (usb_reset_configuration (dev) < 0) {
62                 err ("clear_device failed");
63                 return -1;
64         }
65
66         return 0;
67 }
68
69 /* 
70  * Clear input & output pipes (endpoints)
71  */
72 static inline int
73 clear_pipes (struct usb_device *dev)
74 {
75         unsigned int pipe;
76
77         pipe = usb_sndbulkpipe (dev, 2);
78         if (usb_clear_halt (dev, pipe)) {
79                 err ("clear_pipe (w), request failed");
80                 return -1;
81         }
82
83         pipe = usb_rcvbulkpipe (dev, 1);
84         if (usb_clear_halt (dev, pipe)) {
85                 err ("clear_pipe (r), request failed");
86                 return -1;
87         }
88
89         return 0;
90 }
91
92 /* ----- file operations functions--------------------------------------- */
93
94 static int
95 tiglusb_open (struct inode *inode, struct file *filp)
96 {
97         int devnum = iminor(inode);
98         ptiglusb_t s;
99
100         if (devnum < TIUSB_MINOR || devnum >= (TIUSB_MINOR + MAXTIGL))
101                 return -EIO;
102
103         s = &tiglusb[devnum - TIUSB_MINOR];
104
105         if (down_interruptible (&s->mutex)) {
106                 return -ERESTARTSYS;
107         }
108
109         while (!s->dev || s->opened) {
110                 up (&s->mutex);
111
112                 if (filp->f_flags & O_NONBLOCK) {
113                         return -EBUSY;
114                 }
115
116                 schedule_timeout (HZ / 2);
117
118                 if (signal_pending (current)) {
119                         return -EAGAIN;
120                 }
121
122                 if (down_interruptible (&s->mutex)) {
123                         return -ERESTARTSYS;
124                 }
125         }
126
127         s->opened = 1;
128         up (&s->mutex);
129
130         filp->f_pos = 0;
131         filp->private_data = s;
132
133         return 0;
134 }
135
136 static int
137 tiglusb_release (struct inode *inode, struct file *filp)
138 {
139         ptiglusb_t s = (ptiglusb_t) filp->private_data;
140
141         if (down_interruptible (&s->mutex)) {
142                 return -ERESTARTSYS;
143         }
144
145         s->state = _stopped;
146         up (&s->mutex);
147
148         if (!s->remove_pending)
149                 clear_device (s->dev);
150         else
151                 wake_up (&s->remove_ok);
152
153         s->opened = 0;
154
155         return 0;
156 }
157
158 static ssize_t
159 tiglusb_read (struct file *filp, char __user *buf, size_t count, loff_t * f_pos)
160 {
161         ptiglusb_t s = (ptiglusb_t) filp->private_data;
162         ssize_t ret = 0;
163         int bytes_to_read = 0;
164         int bytes_read = 0;
165         int result = 0;
166         char *buffer;
167         unsigned int pipe;
168
169         if (*f_pos)
170                 return -ESPIPE;
171
172         if (s->remove_pending)
173                 return -EIO;
174
175         if (!s->dev)
176                 return -EIO;
177
178         buffer = kmalloc(BULK_RCV_MAX, GFP_KERNEL);
179         if (!buffer)
180                 return -ENOMEM;
181
182         bytes_to_read = (count >= BULK_RCV_MAX) ? BULK_RCV_MAX : count;
183
184         pipe = usb_rcvbulkpipe (s->dev, 1);
185         result = usb_bulk_msg (s->dev, pipe, buffer, bytes_to_read,
186                                &bytes_read, (HZ * timeout) / 10);
187         if (result == -ETIMEDOUT) {     /* NAK */
188                 if (!bytes_read)
189                         dbg ("quirk !");
190                 warn ("tiglusb_read, NAK received.");
191                 ret = result;
192                 goto out;
193         } else if (result == -EPIPE) {  /* STALL -- shouldn't happen */
194                 warn ("clear_halt request to remove STALL condition.");
195                 if (usb_clear_halt (s->dev, pipe))
196                         err ("clear_halt, request failed");
197                 clear_device (s->dev);
198                 ret = result;
199                 goto out;
200         } else if (result < 0) {        /* We should not get any I/O errors */
201                 err ("funky result: %d. Please notify maintainer.", result);
202                 ret = -EIO;
203                 goto out;
204         }
205
206         if (copy_to_user (buf, buffer, bytes_read)) {
207                 ret = -EFAULT;
208         }
209
210       out:
211         kfree(buffer);
212         return ret ? ret : bytes_read;
213 }
214
215 static ssize_t
216 tiglusb_write (struct file *filp, const char __user *buf, size_t count, loff_t * f_pos)
217 {
218         ptiglusb_t s = (ptiglusb_t) filp->private_data;
219         ssize_t ret = 0;
220         int bytes_to_write = 0;
221         int bytes_written = 0;
222         int result = 0;
223         char *buffer;
224         unsigned int pipe;
225
226         if (*f_pos)
227                 return -ESPIPE;
228
229         if (s->remove_pending)
230                 return -EIO;
231
232         if (!s->dev)
233                 return -EIO;
234
235         buffer = kmalloc(BULK_SND_MAX, GFP_KERNEL);
236         if (!buffer)
237                 return -ENOMEM;
238
239         bytes_to_write = (count >= BULK_SND_MAX) ? BULK_SND_MAX : count;
240         if (copy_from_user (buffer, buf, bytes_to_write)) {
241                 ret = -EFAULT;
242                 goto out;
243         }
244
245         pipe = usb_sndbulkpipe (s->dev, 2);
246         result = usb_bulk_msg (s->dev, pipe, buffer, bytes_to_write,
247                                &bytes_written, (HZ * timeout) / 10);
248
249         if (result == -ETIMEDOUT) {     /* NAK */
250                 warn ("tiglusb_write, NAK received.");
251                 ret = result;
252                 goto out;
253         } else if (result == -EPIPE) {  /* STALL -- shouldn't happen */
254                 warn ("clear_halt request to remove STALL condition.");
255                 if (usb_clear_halt (s->dev, pipe))
256                         err ("clear_halt, request failed");
257                 clear_device (s->dev);
258                 ret = result;
259                 goto out;
260         } else if (result < 0) {        /* We should not get any I/O errors */
261                 warn ("funky result: %d. Please notify maintainer.", result);
262                 ret = -EIO;
263                 goto out;
264         }
265
266         if (bytes_written != bytes_to_write) {
267                 ret = -EIO;
268         }
269
270       out:
271         kfree(buffer);
272         return ret ? ret : bytes_written;
273 }
274
275 static int
276 tiglusb_ioctl (struct inode *inode, struct file *filp,
277                unsigned int cmd, unsigned long arg)
278 {
279         ptiglusb_t s = (ptiglusb_t) filp->private_data;
280         int ret = 0;
281
282         if (s->remove_pending)
283                 return -EIO;
284
285         if (down_interruptible (&s->mutex)) {
286                 return -ERESTARTSYS;
287         }
288
289         if (!s->dev) {
290                 up (&s->mutex);
291                 return -EIO;
292         }
293
294         switch (cmd) {
295         case IOCTL_TIUSB_TIMEOUT:
296                 if (arg > 0)
297                         timeout = arg;
298                 else
299                         ret = -EINVAL;
300                 break;
301         case IOCTL_TIUSB_RESET_DEVICE:
302                 if (clear_device (s->dev))
303                         ret = -EIO;
304                 break;
305         case IOCTL_TIUSB_RESET_PIPES:
306                 if (clear_pipes (s->dev))
307                         ret = -EIO;
308                 break;
309         default:
310                 ret = -ENOTTY;
311                 break;
312         }
313
314         up (&s->mutex);
315
316         return ret;
317 }
318
319 /* ----- kernel module registering ------------------------------------ */
320
321 static struct file_operations tiglusb_fops = {
322         .owner =        THIS_MODULE,
323         .llseek =       no_llseek,
324         .read =         tiglusb_read,
325         .write =        tiglusb_write,
326         .ioctl =        tiglusb_ioctl,
327         .open =         tiglusb_open,
328         .release =      tiglusb_release,
329 };
330
331 /* --- initialisation code ------------------------------------- */
332
333 static int
334 tiglusb_probe (struct usb_interface *intf,
335                const struct usb_device_id *id)
336 {
337         struct usb_device *dev = interface_to_usbdev(intf);
338         int minor = -1;
339         int i;
340         ptiglusb_t s;
341
342         dbg ("probing vendor id 0x%x, device id 0x%x",
343              dev->descriptor.idVendor, dev->descriptor.idProduct);
344
345         /*
346          * We don't handle multiple configurations. As of version 0x0103 of
347          * the TIGL hardware, there's only 1 configuration.
348          */
349
350         if (dev->descriptor.bNumConfigurations != 1)
351                 return -ENODEV;
352
353         if ((dev->descriptor.idProduct != 0xe001)
354             && (dev->descriptor.idVendor != 0x451))
355                 return -ENODEV;
356
357         // NOTE:  it's already in this config, this shouldn't be needed.
358         // is this working around some hardware bug?
359         if (usb_reset_configuration (dev) < 0) {
360                 err ("tiglusb_probe: reset_configuration failed");
361                 return -ENODEV;
362         }
363
364         /*
365          * Find a tiglusb struct
366          */
367         for (i = 0; i < MAXTIGL; i++) {
368                 ptiglusb_t s = &tiglusb[i];
369                 if (!s->dev) {
370                         minor = i;
371                         break;
372                 }
373         }
374
375         if (minor == -1)
376                 return -ENODEV;
377
378         s = &tiglusb[minor];
379
380         down (&s->mutex);
381         s->remove_pending = 0;
382         s->dev = dev;
383         up (&s->mutex);
384         dbg ("bound to interface");
385
386         devfs_mk_cdev(MKDEV(TIUSB_MAJOR, TIUSB_MINOR) + s->minor,
387                         S_IFCHR | S_IRUGO | S_IWUGO,
388                         "ticables/usb/%d", s->minor);
389
390         /* Display firmware version */
391         info ("firmware revision %i.%02x",
392                 dev->descriptor.bcdDevice >> 8,
393                 dev->descriptor.bcdDevice & 0xff);
394
395         usb_set_intfdata (intf, s);
396         return 0;
397 }
398
399 static void
400 tiglusb_disconnect (struct usb_interface *intf)
401 {
402         wait_queue_t __wait;
403         ptiglusb_t s = usb_get_intfdata (intf);
404         
405         init_waitqueue_entry(&__wait, current);
406         
407
408         usb_set_intfdata (intf, NULL);
409         if (!s || !s->dev) {
410                 info ("bogus disconnect");
411                 return;
412         }
413
414         s->remove_pending = 1;
415         wake_up (&s->wait);
416         add_wait_queue(&s->wait, &__wait);
417         set_current_state(TASK_UNINTERRUPTIBLE);
418         if (s->state == _started)
419                 schedule();
420         current->state = TASK_RUNNING;
421         remove_wait_queue(&s->wait, &__wait);
422         down (&s->mutex);
423         s->dev = NULL;
424         s->opened = 0;
425
426         devfs_remove("ticables/usb/%d", s->minor);
427
428         info ("device %d removed", s->minor);
429
430         up (&s->mutex);
431 }
432
433 static struct usb_device_id tiglusb_ids[] = {
434         {USB_DEVICE (0x0451, 0xe001)},
435         {}
436 };
437
438 MODULE_DEVICE_TABLE (usb, tiglusb_ids);
439
440 static struct usb_driver tiglusb_driver = {
441         .owner =        THIS_MODULE,
442         .name =         "tiglusb",
443         .probe =        tiglusb_probe,
444         .disconnect =   tiglusb_disconnect,
445         .id_table =     tiglusb_ids,
446 };
447
448 /* --- initialisation code ------------------------------------- */
449
450 #ifndef MODULE
451 /*
452  * You can use 'tiusb=timeout' to set timeout.
453  */
454 static int __init
455 tiglusb_setup (char *str)
456 {
457         int ints[2];
458
459         str = get_options (str, ARRAY_SIZE (ints), ints);
460
461         if (ints[0] > 0) {
462                 if (ints[1] > 0)
463                         timeout = ints[1];
464                 else
465                         info ("tiglusb: wrong timeout value (0), using default value.");
466         }
467
468         return 1;
469 }
470 #endif
471
472 static int __init
473 tiglusb_init (void)
474 {
475         unsigned u;
476         int result;
477
478         /* initialize struct */
479         for (u = 0; u < MAXTIGL; u++) {
480                 ptiglusb_t s = &tiglusb[u];
481                 memset (s, 0, sizeof (tiglusb_t));
482                 init_MUTEX (&s->mutex);
483                 s->dev = NULL;
484                 s->minor = u;
485                 s->opened = 0;
486                 init_waitqueue_head (&s->wait);
487                 init_waitqueue_head (&s->remove_ok);
488         }
489
490         /* register device */
491         if (register_chrdev (TIUSB_MAJOR, "tiglusb", &tiglusb_fops)) {
492                 err ("unable to get major %d", TIUSB_MAJOR);
493                 return -EIO;
494         }
495
496         /* Use devfs, tree: /dev/ticables/usb/[0..3] */
497         devfs_mk_dir ("ticables/usb");
498
499         /* register USB module */
500         result = usb_register (&tiglusb_driver);
501         if (result < 0) {
502                 unregister_chrdev (TIUSB_MAJOR, "tiglusb");
503                 return -1;
504         }
505
506         info (DRIVER_DESC ", version " DRIVER_VERSION);
507
508         return 0;
509 }
510
511 static void __exit
512 tiglusb_cleanup (void)
513 {
514         usb_deregister (&tiglusb_driver);
515         devfs_remove("ticables/usb");
516         unregister_chrdev (TIUSB_MAJOR, "tiglusb");
517 }
518
519 /* --------------------------------------------------------------------- */
520
521 __setup ("tiusb=", tiglusb_setup);
522 module_init (tiglusb_init);
523 module_exit (tiglusb_cleanup);
524
525 MODULE_AUTHOR (DRIVER_AUTHOR);
526 MODULE_DESCRIPTION (DRIVER_DESC);
527 MODULE_LICENSE (DRIVER_LICENSE);
528
529 MODULE_PARM (timeout, "i");
530 MODULE_PARM_DESC (timeout, "Timeout in tenths of seconds (default=1.5 seconds)");
531
532 /* --------------------------------------------------------------------- */