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