1 /* Hey EMACS -*- linux-c -*-
3 * tiglusb -- Texas Instruments' USB GraphLink (aka SilverLink) driver.
4 * Target: Texas Instruments graphing calculators (http://lpg.ticalc.org).
6 * Copyright (C) 2001-2004:
7 * Romain Lievin <roms@tilp.info>
8 * Julien BLACHE <jb@technologeek.org>
9 * under the terms of the GNU General Public License.
11 * Based on dabusb.c, printer.c & scanner.c
13 * Please see the file: Documentation/usb/silverlink.txt
14 * and the website at: http://lpg.ticalc.org/prj_usb/
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 * 1.08, Romain: added support of USB port embedded on some TI's handhelds.
28 #include <linux/module.h>
29 #include <linux/socket.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 #include <linux/device.h>
39 #include <linux/ticable.h>
45 #define DRIVER_VERSION "1.08"
46 #define DRIVER_AUTHOR "Romain Lievin <roms@tilp.info> & Julien Blache <jb@jblache.org>"
47 #define DRIVER_DESC "TI-GRAPH LINK USB (aka SilverLink) driver"
48 #define DRIVER_LICENSE "GPL"
50 /* ----- global variables --------------------------------------------- */
52 static tiglusb_t tiglusb[MAXTIGL];
53 static int timeout = TIMAXTIME; /* timeout in tenth of seconds */
54 static struct class_simple *tiglusb_class;
56 /*---------- misc functions ------------------------------------------- */
59 * Re-initialize device
62 clear_device (struct usb_device *dev)
64 if (usb_reset_configuration (dev) < 0) {
65 err ("clear_device failed");
73 * Clear input & output pipes (endpoints)
76 clear_pipes (struct usb_device *dev)
80 pipe = usb_sndbulkpipe (dev, 2);
81 if (usb_clear_halt (dev, pipe)) {
82 err ("clear_pipe (w), request failed");
86 pipe = usb_rcvbulkpipe (dev, 1);
87 if (usb_clear_halt (dev, pipe)) {
88 err ("clear_pipe (r), request failed");
95 /* ----- file operations functions--------------------------------------- */
98 tiglusb_open (struct inode *inode, struct file *filp)
100 int devnum = iminor(inode);
103 if (devnum < TIUSB_MINOR || devnum >= (TIUSB_MINOR + MAXTIGL))
106 s = &tiglusb[devnum - TIUSB_MINOR];
108 if (down_interruptible (&s->mutex)) {
112 while (!s->dev || s->opened) {
115 if (filp->f_flags & O_NONBLOCK) {
119 msleep_interruptible(500);
121 if (signal_pending (current)) {
125 if (down_interruptible (&s->mutex)) {
134 filp->private_data = s;
136 return nonseekable_open(inode, filp);
140 tiglusb_release (struct inode *inode, struct file *filp)
142 ptiglusb_t s = (ptiglusb_t) filp->private_data;
144 if (down_interruptible (&s->mutex)) {
151 if (!s->remove_pending)
152 clear_device (s->dev);
154 wake_up (&s->remove_ok);
162 tiglusb_read (struct file *filp, char __user *buf, size_t count, loff_t * f_pos)
164 ptiglusb_t s = (ptiglusb_t) filp->private_data;
166 int bytes_to_read = 0;
175 if (s->remove_pending)
181 buffer = kmalloc (s->max_ps, GFP_KERNEL);
185 bytes_to_read = (count >= s->max_ps) ? s->max_ps : count;
187 pipe = usb_rcvbulkpipe (s->dev, 1);
188 result = usb_bulk_msg (s->dev, pipe, buffer, bytes_to_read,
189 &bytes_read, (HZ * timeout) / 10);
190 if (result == -ETIMEDOUT) { /* NAK */
193 warn ("tiglusb_read, NAK received.");
196 } else if (result == -EPIPE) { /* STALL -- shouldn't happen */
197 warn ("clear_halt request to remove STALL condition.");
198 if (usb_clear_halt (s->dev, pipe))
199 err ("clear_halt, request failed");
200 clear_device (s->dev);
203 } else if (result < 0) { /* We should not get any I/O errors */
204 err ("funky result: %d. Please notify maintainer.", result);
209 if (copy_to_user (buf, buffer, bytes_read)) {
215 return ret ? ret : bytes_read;
219 tiglusb_write (struct file *filp, const char __user *buf, size_t count, loff_t * f_pos)
221 ptiglusb_t s = (ptiglusb_t) filp->private_data;
223 int bytes_to_write = 0;
224 int bytes_written = 0;
232 if (s->remove_pending)
238 buffer = kmalloc (s->max_ps, GFP_KERNEL);
242 bytes_to_write = (count >= s->max_ps) ? s->max_ps : count;
243 if (copy_from_user (buffer, buf, bytes_to_write)) {
248 pipe = usb_sndbulkpipe (s->dev, 2);
249 result = usb_bulk_msg (s->dev, pipe, buffer, bytes_to_write,
250 &bytes_written, (HZ * timeout) / 10);
252 if (result == -ETIMEDOUT) { /* NAK */
253 warn ("tiglusb_write, NAK received.");
256 } else if (result == -EPIPE) { /* STALL -- shouldn't happen */
257 warn ("clear_halt request to remove STALL condition.");
258 if (usb_clear_halt (s->dev, pipe))
259 err ("clear_halt, request failed");
260 clear_device (s->dev);
263 } else if (result < 0) { /* We should not get any I/O errors */
264 warn ("funky result: %d. Please notify maintainer.", result);
269 if (bytes_written != bytes_to_write) {
275 return ret ? ret : bytes_written;
279 tiglusb_ioctl (struct inode *inode, struct file *filp,
280 unsigned int cmd, unsigned long arg)
282 ptiglusb_t s = (ptiglusb_t) filp->private_data;
285 if (s->remove_pending)
288 if (down_interruptible (&s->mutex)) {
298 case IOCTL_TIUSB_TIMEOUT:
304 case IOCTL_TIUSB_RESET_DEVICE:
305 if (clear_device (s->dev))
308 case IOCTL_TIUSB_RESET_PIPES:
309 if (clear_pipes (s->dev))
312 case IOCTL_TIUSB_GET_MAXPS:
313 if (copy_to_user((int __user *) arg, &s->max_ps, sizeof(int)))
316 case IOCTL_TIUSB_GET_DEVID:
317 if (copy_to_user((int __user *) arg, &s->dev->descriptor.idProduct,
331 /* ----- kernel module registering ------------------------------------ */
333 static struct file_operations tiglusb_fops = {
334 .owner = THIS_MODULE,
336 .read = tiglusb_read,
337 .write = tiglusb_write,
338 .ioctl = tiglusb_ioctl,
339 .open = tiglusb_open,
340 .release = tiglusb_release,
343 /* --- initialisation code ------------------------------------- */
346 tiglusb_probe (struct usb_interface *intf,
347 const struct usb_device_id *id)
349 struct usb_device *dev = interface_to_usbdev(intf);
353 struct usb_host_config *conf;
354 struct usb_host_interface *ifdata = NULL;
357 dbg ("probing vendor id 0x%x, device id 0x%x",
358 dev->descriptor.idVendor, dev->descriptor.idProduct);
361 * We don't handle multiple configurations. As of version 0x0103 of
362 * the TIGL hardware, there's only 1 configuration.
365 if (dev->descriptor.bNumConfigurations != 1) {
370 if (dev->descriptor.idVendor != 0x451) {
375 if ((dev->descriptor.idProduct != 0xe001) &&
376 (dev->descriptor.idProduct != 0xe004) &&
377 (dev->descriptor.idProduct != 0xe008)) {
383 * TI introduced some new handhelds with embedded USB port.
384 * Port advertises same config as SilverLink cable but with a
385 * different maximum packet size (64 rather than 32).
388 conf = dev->actconfig;
389 ifdata = conf->interface[0]->cur_altsetting;
390 max_ps = ifdata->endpoint[0].desc.wMaxPacketSize;
392 info("max packet size of %d/%d bytes\n",
393 ifdata->endpoint[0].desc.wMaxPacketSize,
394 ifdata->endpoint[1].desc.wMaxPacketSize);
397 * Find a tiglusb struct
399 for (i = 0; i < MAXTIGL; i++) {
400 ptiglusb_t s = &tiglusb[i];
415 s->remove_pending = 0;
419 dbg ("bound to interface");
421 class_simple_device_add(tiglusb_class, MKDEV(TIUSB_MAJOR, TIUSB_MINOR + s->minor),
422 NULL, "usb%d", s->minor);
423 err = devfs_mk_cdev(MKDEV(TIUSB_MAJOR, TIUSB_MINOR) + s->minor,
424 S_IFCHR | S_IRUGO | S_IWUGO,
425 "ticables/usb/%d", s->minor);
430 /* Display firmware version */
431 info ("firmware revision %i.%02x",
432 dev->descriptor.bcdDevice >> 8,
433 dev->descriptor.bcdDevice & 0xff);
435 usb_set_intfdata (intf, s);
440 class_simple_device_remove(MKDEV(TIUSB_MAJOR, TIUSB_MINOR + s->minor));
446 tiglusb_disconnect (struct usb_interface *intf)
449 ptiglusb_t s = usb_get_intfdata (intf);
451 init_waitqueue_entry(&__wait, current);
454 usb_set_intfdata (intf, NULL);
456 info ("bogus disconnect");
460 s->remove_pending = 1;
462 add_wait_queue(&s->wait, &__wait);
463 set_current_state(TASK_UNINTERRUPTIBLE);
464 if (s->state == _started)
466 current->state = TASK_RUNNING;
467 remove_wait_queue(&s->wait, &__wait);
472 class_simple_device_remove(MKDEV(TIUSB_MAJOR, TIUSB_MINOR + s->minor));
473 devfs_remove("ticables/usb/%d", s->minor);
475 info ("device %d removed", s->minor);
480 static struct usb_device_id tiglusb_ids[] = {
481 {USB_DEVICE (0x0451, 0xe001)},
485 MODULE_DEVICE_TABLE (usb, tiglusb_ids);
487 static struct usb_driver tiglusb_driver = {
488 .owner = THIS_MODULE,
490 .probe = tiglusb_probe,
491 .disconnect = tiglusb_disconnect,
492 .id_table = tiglusb_ids,
495 /* --- initialisation code ------------------------------------- */
499 * You can use 'tiusb=timeout' to set timeout.
502 tiglusb_setup (char *str)
506 str = get_options (str, ARRAY_SIZE (ints), ints);
512 info ("tiglusb: wrong timeout value (0), using default value.");
525 /* initialize struct */
526 for (u = 0; u < MAXTIGL; u++) {
527 ptiglusb_t s = &tiglusb[u];
528 memset (s, 0, sizeof (tiglusb_t));
529 init_MUTEX (&s->mutex);
533 init_waitqueue_head (&s->wait);
534 init_waitqueue_head (&s->remove_ok);
537 /* register device */
538 if (register_chrdev (TIUSB_MAJOR, "tiglusb", &tiglusb_fops)) {
539 err ("unable to get major %d", TIUSB_MAJOR);
544 /* Use devfs, tree: /dev/ticables/usb/[0..3] */
545 devfs_mk_dir ("ticables/usb");
547 tiglusb_class = class_simple_create(THIS_MODULE, "tiglusb");
548 if (IS_ERR(tiglusb_class)) {
549 err = PTR_ERR(tiglusb_class);
552 /* register USB module */
553 result = usb_register (&tiglusb_driver);
559 info (DRIVER_DESC ", version " DRIVER_VERSION);
565 unregister_chrdev (TIUSB_MAJOR, "tiglusb");
571 tiglusb_cleanup (void)
573 usb_deregister (&tiglusb_driver);
574 class_simple_destroy(tiglusb_class);
575 devfs_remove("ticables/usb");
576 unregister_chrdev (TIUSB_MAJOR, "tiglusb");
579 /* --------------------------------------------------------------------- */
581 __setup ("tiusb=", tiglusb_setup);
582 module_init (tiglusb_init);
583 module_exit (tiglusb_cleanup);
585 MODULE_AUTHOR (DRIVER_AUTHOR);
586 MODULE_DESCRIPTION (DRIVER_DESC);
587 MODULE_LICENSE (DRIVER_LICENSE);
589 module_param(timeout, int, 0);
590 MODULE_PARM_DESC (timeout, "Timeout in tenths of seconds (default=1.5 seconds)");
592 /* --------------------------------------------------------------------- */