diff options
Diffstat (limited to 'drivers/usb/usb-serial.c')
-rw-r--r-- | drivers/usb/usb-serial.c | 854 |
1 files changed, 523 insertions, 331 deletions
diff --git a/drivers/usb/usb-serial.c b/drivers/usb/usb-serial.c index 0cb3bdcba..8826bc522 100644 --- a/drivers/usb/usb-serial.c +++ b/drivers/usb/usb-serial.c @@ -1,7 +1,7 @@ /* * USB Serial Converter driver * - * (C) Copyright (C) 1999 + * (C) Copyright (C) 1999, 2000 * Greg Kroah-Hartman (greg@kroah.com) * * This program is free software; you can redistribute it and/or modify @@ -12,8 +12,42 @@ * This driver was originally based on the ACM driver by Armin Fuerst (which was * based on a driver by Brad Keryan) * - * See README.serial for more information on using this driver. + * See Documentation/usb/usb-serial.txt for more information on using this driver * + * (01/19/2000) gkh + * Removed lots of cruft that was around from the old (pre urb) driver + * interface. + * Made the serial_table dynamic. This should save lots of memory when + * the number of minor nodes goes up to 256. + * Added initial support for devices that have more than one port. + * Added more debugging comments for the Visor, and added a needed + * set_configuration call. + * + * (01/17/2000) gkh + * Fixed the WhiteHEAT firmware (my processing tool had a bug) + * and added new debug loader firmware for it. + * Removed the put_char function as it isn't really needed. + * Added visor startup commands as found by the Win98 dump. + * + * (01/13/2000) gkh + * Fixed the vendor id for the generic driver to the one I meant it to be. + * + * (01/12/2000) gkh + * Forget the version numbering...that's pretty useless... + * Made the driver able to be compiled so that the user can select which + * converter they want to use. This allows people who only want the Visor + * support to not pay the memory size price of the WhiteHEAT. + * Fixed bug where the generic driver (idVendor=0000 and idProduct=0000) + * grabbed the root hub. Not good. + * + * version 0.4.0 (01/10/2000) gkh + * Added whiteheat.h containing the firmware for the ConnectTech WhiteHEAT + * device. Added startup function to allow firmware to be downloaded to + * a device if it needs to be. + * Added firmware download logic to the WhiteHEAT device. + * Started to add #defines to split up the different drivers for potential + * configuration option. + * * version 0.3.1 (12/30/99) gkh * Fixed problems with urb for bulk out. * Added initial support for multiple sets of endpoints. This enables @@ -63,6 +97,7 @@ * */ +#include <linux/config.h> #include <linux/kernel.h> #include <linux/sched.h> #include <linux/signal.h> @@ -77,21 +112,31 @@ #include <linux/module.h> #include <linux/spinlock.h> -#undef DEBUG +#define DEBUG #include "usb.h" +#ifdef CONFIG_USB_SERIAL_WHITEHEAT +#include "whiteheat.h" /* firmware for the ConnectTech WhiteHEAT device */ +#endif + /* Module information */ MODULE_AUTHOR("Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux-usb/"); MODULE_DESCRIPTION("USB Serial Driver"); -static __u16 vendor = 0; -static __u16 product = 0; +#ifdef CONFIG_USB_SERIAL_GENERIC +static __u16 vendor = 0x05f9; +static __u16 product = 0xffff; MODULE_PARM(vendor, "i"); MODULE_PARM_DESC(vendor, "User specified USB idVendor"); MODULE_PARM(product, "i"); MODULE_PARM_DESC(product, "User specified USB idProduct"); +#endif + + +static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum); +static void usb_serial_disconnect(struct usb_device *dev, void *ptr); /* USB Serial devices vendor ids and device ids that this driver supports */ @@ -106,12 +151,36 @@ MODULE_PARM_DESC(product, "User specified USB idProduct"); #define HANDSPRING_VISOR_ID 0x0100 -#define SERIAL_MAJOR 188 /* Nice legal number now */ -#define NUM_PORTS 16 /* Actually we are allowed 255, but this is good for now */ +#define SERIAL_TTY_MAJOR 188 /* Nice legal number now */ +#define SERIAL_TTY_MINORS 16 /* Actually we are allowed 255, but this is good for now */ -static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum); -static void usb_serial_disconnect(struct usb_device *dev, void *ptr); +#define MAX_NUM_PORTS 8 /* The maximum number of ports one device can grab at once */ + +struct usb_serial { + struct usb_device * dev; + struct usb_serial_device_type * type; + void * irq_handle; + unsigned int irqpipe; + struct tty_struct * tty; /* the coresponding tty for this device */ + unsigned char minor; + unsigned char num_ports; /* the number of ports this device has */ + char active[MAX_NUM_PORTS]; /* someone has this device open */ + + char num_interrupt_in; /* number of interrupt in endpoints we have */ + __u8 interrupt_in_interval[MAX_NUM_PORTS]; + unsigned char * interrupt_in_buffer[MAX_NUM_PORTS]; + struct urb control_urb[MAX_NUM_PORTS]; + + char num_bulk_in; /* number of bulk in endpoints we have */ + unsigned char * bulk_in_buffer[MAX_NUM_PORTS]; + struct urb read_urb[MAX_NUM_PORTS]; + + char num_bulk_out; /* number of bulk out endpoints we have */ + unsigned char * bulk_out_buffer[MAX_NUM_PORTS]; + int bulk_out_size[MAX_NUM_PORTS]; + struct urb write_urb[MAX_NUM_PORTS]; +}; #define MUST_HAVE_NOT 0x01 @@ -127,7 +196,6 @@ static void usb_serial_disconnect(struct usb_device *dev, void *ptr); static int serial_open (struct tty_struct *tty, struct file * filp); static void serial_close (struct tty_struct *tty, struct file * filp); static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count); -static void serial_put_char (struct tty_struct *tty, unsigned char ch); static int serial_write_room (struct tty_struct *tty); static int serial_chars_in_buffer (struct tty_struct *tty); static void serial_throttle (struct tty_struct * tty); @@ -145,15 +213,15 @@ struct usb_serial_device_type { char num_interrupt_in; char num_bulk_in; char num_bulk_out; + char num_ports; /* number of serial ports this device has */ /* function call to make before accepting driver */ - void (*startup) (void); + int (*startup) (struct usb_serial *serial); /* return 0 to continue initialization, anything else to abort */ /* serial function calls */ int (*open)(struct tty_struct * tty, struct file * filp); void (*close)(struct tty_struct * tty, struct file * filp); int (*write)(struct tty_struct * tty, int from_user,const unsigned char *buf, int count); - void (*put_char)(struct tty_struct *tty, unsigned char ch); int (*write_room)(struct tty_struct *tty); int (*chars_in_buffer)(struct tty_struct *tty); void (*throttle)(struct tty_struct * tty); @@ -162,13 +230,14 @@ struct usb_serial_device_type { /* function prototypes for a "generic" type serial converter (no flow control, not all endpoints needed) */ +/* need to always compile these in, as some of the other devices use these functions as their own. */ static int generic_serial_open (struct tty_struct *tty, struct file *filp); static void generic_serial_close (struct tty_struct *tty, struct file *filp); static int generic_serial_write (struct tty_struct *tty, int from_user, const unsigned char *buf, int count); -static void generic_serial_put_char (struct tty_struct *tty, unsigned char ch); static int generic_write_room (struct tty_struct *tty); static int generic_chars_in_buffer (struct tty_struct *tty); +#ifdef CONFIG_USB_SERIAL_GENERIC /* All of the device info needed for the Generic Serial Converter */ static struct usb_serial_device_type generic_device = { name: "Generic", @@ -180,19 +249,22 @@ static struct usb_serial_device_type generic_device = { num_interrupt_in: NUM_DONT_CARE, num_bulk_in: NUM_DONT_CARE, num_bulk_out: NUM_DONT_CARE, + num_ports: 1, open: generic_serial_open, close: generic_serial_close, write: generic_serial_write, - put_char: generic_serial_put_char, write_room: generic_write_room, chars_in_buffer: generic_chars_in_buffer, }; +#endif - +#if defined(CONFIG_USB_SERIAL_BELKIN) || defined(CONFIG_USB_SERIAL_PERACOM) /* function prototypes for the eTek type converters (this includes Belkin and Peracom) */ static int etek_serial_open (struct tty_struct *tty, struct file *filp); static void etek_serial_close (struct tty_struct *tty, struct file *filp); +#endif +#ifdef CONFIG_USB_SERIAL_BELKIN /* All of the device info needed for the Belkin Serial Converter */ static __u16 belkin_vendor_id = BELKIN_VENDOR_ID; static __u16 belkin_product_id = BELKIN_SERIAL_CONVERTER; @@ -206,14 +278,17 @@ static struct usb_serial_device_type belkin_device = { num_interrupt_in: 1, num_bulk_in: 1, num_bulk_out: 1, + num_ports: 1, open: etek_serial_open, close: etek_serial_close, write: generic_serial_write, - put_char: generic_serial_put_char, write_room: generic_write_room, chars_in_buffer: generic_chars_in_buffer, }; +#endif + +#ifdef CONFIG_USB_SERIAL_PERACOM /* All of the device info needed for the Peracom Serial Converter */ static __u16 peracom_vendor_id = PERACOM_VENDOR_ID; static __u16 peracom_product_id = PERACOM_SERIAL_CONVERTER; @@ -224,23 +299,26 @@ static struct usb_serial_device_type peracom_device = { needs_interrupt_in: MUST_HAVE, /* this device must have an interrupt in endpoint */ needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */ needs_bulk_out: MUST_HAVE, /* this device must have a bulk out endpoint */ + num_ports: 1, num_interrupt_in: 1, num_bulk_in: 1, num_bulk_out: 1, open: etek_serial_open, close: etek_serial_close, write: generic_serial_write, - put_char: generic_serial_put_char, write_room: generic_write_room, chars_in_buffer: generic_chars_in_buffer, }; +#endif +#ifdef CONFIG_USB_SERIAL_WHITEHEAT /* function prototypes for the Connect Tech WhiteHEAT serial converter */ static int whiteheat_serial_open (struct tty_struct *tty, struct file *filp); static void whiteheat_serial_close (struct tty_struct *tty, struct file *filp); static void whiteheat_throttle (struct tty_struct *tty); static void whiteheat_unthrottle (struct tty_struct *tty); +static int whiteheat_startup (struct usb_serial *serial); /* All of the device info needed for the Connect Tech WhiteHEAT */ static __u16 connecttech_vendor_id = CONNECT_TECH_VENDOR_ID; @@ -256,6 +334,7 @@ static struct usb_serial_device_type whiteheat_fake_device = { num_interrupt_in: NUM_DONT_CARE, num_bulk_in: NUM_DONT_CARE, num_bulk_out: NUM_DONT_CARE, + startup: whiteheat_startup }; static struct usb_serial_device_type whiteheat_device = { name: "Connect Tech - WhiteHEAT", @@ -267,22 +346,25 @@ static struct usb_serial_device_type whiteheat_device = { num_interrupt_in: NUM_DONT_CARE, num_bulk_in: NUM_DONT_CARE, num_bulk_out: NUM_DONT_CARE, + num_ports: 4, open: whiteheat_serial_open, close: whiteheat_serial_close, write: generic_serial_write, - put_char: generic_serial_put_char, write_room: generic_write_room, chars_in_buffer: generic_chars_in_buffer, throttle: whiteheat_throttle, unthrottle: whiteheat_unthrottle }; +#endif +#ifdef CONFIG_USB_SERIAL_VISOR /* function prototypes for a handspring visor */ static int visor_serial_open (struct tty_struct *tty, struct file *filp); static void visor_serial_close (struct tty_struct *tty, struct file *filp); static void visor_throttle (struct tty_struct *tty); static void visor_unthrottle (struct tty_struct *tty); +static int visor_startup (struct usb_serial *serial); /* All of the device info needed for the Handspring Visor */ static __u16 handspring_vendor_id = HANDSPRING_VENDOR_ID; @@ -297,72 +379,42 @@ static struct usb_serial_device_type handspring_device = { num_interrupt_in: 0, num_bulk_in: 2, num_bulk_out: 2, + num_ports: 2, open: visor_serial_open, close: visor_serial_close, write: generic_serial_write, - put_char: generic_serial_put_char, write_room: generic_write_room, chars_in_buffer: generic_chars_in_buffer, throttle: visor_throttle, - unthrottle: visor_unthrottle + unthrottle: visor_unthrottle, + startup: visor_startup }; - +#endif /* To add support for another serial converter, create a usb_serial_device_type structure for that device, and add it to this list, making sure that the last entry is NULL. */ static struct usb_serial_device_type *usb_serial_devices[] = { +#ifdef CONFIG_USB_SERIAL_GENERIC &generic_device, +#endif +#ifdef CONFIG_USB_SERIAL_WHITEHEAT &whiteheat_fake_device, &whiteheat_device, +#endif +#ifdef CONFIG_USB_SERIAL_BELKIN &belkin_device, +#endif +#ifdef CONFIG_USB_SERIAL_PERACOM &peracom_device, +#endif +#ifdef CONFIG_USB_SERIAL_VISOR &handspring_device, +#endif NULL }; -#define MAX_ENDPOINTS 8 - -struct usb_serial_state { - struct usb_device * dev; - struct usb_serial_device_type * type; - void * irq_handle; - unsigned int irqpipe; - struct tty_struct * tty; /* the coresponding tty for this device */ - unsigned char number; - char present; - char active; - - char num_interrupt_in; /* number of interrupt in endpoints we have */ - char interrupt_in_inuse; /* if the interrupt in endpoint is in use */ - __u8 interrupt_in_endpoint[MAX_ENDPOINTS]; - __u8 interrupt_in_interval[MAX_ENDPOINTS]; - __u16 interrupt_in_size[MAX_ENDPOINTS]; /* the size of the interrupt in endpoint */ - unsigned int interrupt_in_pipe[MAX_ENDPOINTS]; - unsigned char * interrupt_in_buffer[MAX_ENDPOINTS]; - void * interrupt_in_transfer[MAX_ENDPOINTS]; - struct urb control_urb; - - char num_bulk_in; /* number of bulk in endpoints we have */ - __u8 bulk_in_endpoint[MAX_ENDPOINTS]; - __u8 bulk_in_interval[MAX_ENDPOINTS]; - __u16 bulk_in_size[MAX_ENDPOINTS]; /* the size of the bulk in endpoint */ - unsigned int bulk_in_pipe[MAX_ENDPOINTS]; - unsigned char * bulk_in_buffer[MAX_ENDPOINTS]; - void * bulk_in_transfer[MAX_ENDPOINTS]; - struct urb read_urb; - - char num_bulk_out; /* number of bulk out endpoints we have */ - __u8 bulk_out_endpoint[MAX_ENDPOINTS]; - __u8 bulk_out_interval[MAX_ENDPOINTS]; - __u16 bulk_out_size[MAX_ENDPOINTS]; /* the size of the bulk out endpoint */ - unsigned int bulk_out_pipe[MAX_ENDPOINTS]; - unsigned char * bulk_out_buffer[MAX_ENDPOINTS]; - void * bulk_out_transfer[MAX_ENDPOINTS]; - struct urb write_urb; -}; - static struct usb_driver usb_serial_driver = { "serial", usb_serial_probe, @@ -371,16 +423,61 @@ static struct usb_driver usb_serial_driver = { }; static int serial_refcount; -static struct tty_struct * serial_tty[NUM_PORTS]; -static struct termios * serial_termios[NUM_PORTS]; -static struct termios * serial_termios_locked[NUM_PORTS]; -static struct usb_serial_state serial_state_table[NUM_PORTS]; +static struct tty_struct * serial_tty[SERIAL_TTY_MINORS]; +static struct termios * serial_termios[SERIAL_TTY_MINORS]; +static struct termios * serial_termios_locked[SERIAL_TTY_MINORS]; +static struct usb_serial *serial_table[SERIAL_TTY_MINORS] = {NULL, }; + + + +#define SERIAL_PTR_EMPTY ((void *)(-1)) + +static struct usb_serial *get_serial_by_minor (int minor) +{ + int i; + dbg("get_serial_by_minor %d", minor); + + for (i = 0; i < SERIAL_TTY_MINORS; ++i) + if (serial_table[i]) + if (serial_table[i] != SERIAL_PTR_EMPTY) + if (serial_table[i]->minor == minor) + return (serial_table[i]); + + return (NULL); +} + + +static struct usb_serial *get_free_serial (int num_ports, int *minor) +{ + struct usb_serial *serial = NULL; + int i; + + dbg("get_free_serial %d", num_ports); + + *minor = 0; + for (i = 0; i < SERIAL_TTY_MINORS; ++i) { + if (serial_table[i]) + continue; + if (!(serial = kmalloc(sizeof(struct usb_serial), GFP_KERNEL))) { + err("Out of memory"); + return NULL; + } + memset(serial, 0, sizeof(struct usb_serial)); + serial_table[i] = serial; + *minor = i; + dbg("minor base = %d", *minor); + for (i = *minor+1; (i < num_ports) && (i < SERIAL_TTY_MINORS); ++i) + serial_table[i] = SERIAL_PTR_EMPTY; + return (serial); + } + return (NULL); +} static void serial_read_bulk (struct urb *urb) { - struct usb_serial_state *serial = (struct usb_serial_state *)urb->context; + struct usb_serial *serial = (struct usb_serial *)urb->context; struct tty_struct *tty = serial->tty; unsigned char *data = urb->transfer_buffer; int i; @@ -412,7 +509,7 @@ static void serial_read_bulk (struct urb *urb) static void serial_write_bulk (struct urb *urb) { - struct usb_serial_state *serial = (struct usb_serial_state *) urb->context; + struct usb_serial *serial = (struct usb_serial *) urb->context; struct tty_struct *tty = serial->tty; dbg("serial_write_irq"); @@ -437,12 +534,12 @@ static void serial_write_bulk (struct urb *urb) *****************************************************************************/ static int serial_open (struct tty_struct *tty, struct file * filp) { - struct usb_serial_state *serial; + struct usb_serial *serial; dbg("serial_open"); - /* assign a serial object to the tty pointer */ - serial = &serial_state_table [MINOR(tty->device)-tty->driver.minor_start]; + /* get the serial object associated with this tty pointer */ + serial = get_serial_by_minor (MINOR(tty->device)); /* do some sanity checking that we really have a device present */ if (!serial) { @@ -469,8 +566,10 @@ static int serial_open (struct tty_struct *tty, struct file * filp) static void serial_close(struct tty_struct *tty, struct file * filp) { - struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; - dbg("serial_close"); + struct usb_serial *serial = (struct usb_serial *) tty->driver_data; + int port = MINOR(tty->device) - serial->minor; + + dbg("serial_close port %d", port); /* do some sanity checking that we really have a device present */ if (!serial) { @@ -481,11 +580,7 @@ static void serial_close(struct tty_struct *tty, struct file * filp) dbg("serial->type == NULL!"); return; } - if (!serial->present) { - dbg("no device registered"); - return; - } - if (!serial->active) { + if (!serial->active[port]) { dbg ("device already open"); return; } @@ -499,9 +594,10 @@ static void serial_close(struct tty_struct *tty, struct file * filp) static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count) { - struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; + struct usb_serial *serial = (struct usb_serial *) tty->driver_data; + int port = MINOR(tty->device) - serial->minor; - dbg("serial_write"); + dbg("serial_write port %d, %d byte(s)", port, count); /* do some sanity checking that we really have a device present */ if (!serial) { @@ -512,11 +608,7 @@ static int serial_write (struct tty_struct * tty, int from_user, const unsigned dbg("serial->type == NULL!"); return (-ENODEV); } - if (!serial->present) { - dbg("device not registered"); - return (-EINVAL); - } - if (!serial->active) { + if (!serial->active[port]) { dbg ("device not opened"); return (-EINVAL); } @@ -531,44 +623,12 @@ static int serial_write (struct tty_struct * tty, int from_user, const unsigned } -static void serial_put_char (struct tty_struct *tty, unsigned char ch) -{ - struct usb_serial_state *serial = (struct usb_serial_state *)tty->driver_data; - - dbg("serial_put_char"); - - /* do some sanity checking that we really have a device present */ - if (!serial) { - dbg("serial == NULL!"); - return; - } - if (!serial->type) { - dbg("serial->type == NULL!"); - return; - } - if (!serial->present) { - dbg("no device registered"); - return; - } - if (!serial->active) { - dbg ("device not open"); - return; - } - - /* pass on to the driver specific version of this function */ - if (serial->type->put_char) { - serial->type->put_char(tty, ch); - } - - return; -} - - static int serial_write_room (struct tty_struct *tty) { - struct usb_serial_state *serial = (struct usb_serial_state *)tty->driver_data; + struct usb_serial *serial = (struct usb_serial *)tty->driver_data; + int port = MINOR(tty->device) - serial->minor; - dbg("serial_write_room"); + dbg("serial_write_room port %d", port); /* do some sanity checking that we really have a device present */ if (!serial) { @@ -579,11 +639,7 @@ static int serial_write_room (struct tty_struct *tty) dbg("serial->type == NULL!"); return (-ENODEV); } - if (!serial->present) { - dbg("no device registered"); - return (-EINVAL); - } - if (!serial->active) { + if (!serial->active[port]) { dbg ("device not open"); return (-EINVAL); } @@ -599,9 +655,10 @@ static int serial_write_room (struct tty_struct *tty) static int serial_chars_in_buffer (struct tty_struct *tty) { - struct usb_serial_state *serial = (struct usb_serial_state *)tty->driver_data; + struct usb_serial *serial = (struct usb_serial *)tty->driver_data; + int port = MINOR(tty->device) - serial->minor; - dbg("serial_chars_in_buffer"); + dbg("serial_chars_in_buffer port %d", port); /* do some sanity checking that we really have a device present */ if (!serial) { @@ -612,11 +669,7 @@ static int serial_chars_in_buffer (struct tty_struct *tty) dbg("serial->type == NULL!"); return (-ENODEV); } - if (!serial->present) { - dbg("no device registered"); - return (-EINVAL); - } - if (!serial->active) { + if (!serial->active[port]) { dbg ("device not open"); return (-EINVAL); } @@ -632,9 +685,10 @@ static int serial_chars_in_buffer (struct tty_struct *tty) static void serial_throttle (struct tty_struct * tty) { - struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; + struct usb_serial *serial = (struct usb_serial *) tty->driver_data; + int port = MINOR(tty->device) - serial->minor; - dbg("serial_throttle"); + dbg("serial_throttle port %d", port); /* do some sanity checking that we really have a device present */ if (!serial) { @@ -645,11 +699,7 @@ static void serial_throttle (struct tty_struct * tty) dbg("serial->type == NULL!"); return; } - if (!serial->present) { - dbg("no device registered"); - return; - } - if (!serial->active) { + if (!serial->active[port]) { dbg ("device not open"); return; } @@ -665,9 +715,10 @@ static void serial_throttle (struct tty_struct * tty) static void serial_unthrottle (struct tty_struct * tty) { - struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; + struct usb_serial *serial = (struct usb_serial *) tty->driver_data; + int port = MINOR(tty->device) - serial->minor; - dbg("serial_unthrottle"); + dbg("serial_unthrottle port %d", port); /* do some sanity checking that we really have a device present */ if (!serial) { @@ -678,16 +729,11 @@ static void serial_unthrottle (struct tty_struct * tty) dbg("serial->type == NULL!"); return; } - if (!serial->present) { - dbg("no device registered"); - return; - } - if (!serial->active) { + if (!serial->active[port]) { dbg ("device not open"); return; } - /* pass on to the driver specific version of this function */ if (serial->type->unthrottle) { serial->type->unthrottle(tty); @@ -697,28 +743,25 @@ static void serial_unthrottle (struct tty_struct * tty) } +#if defined(CONFIG_USB_SERIAL_BELKIN) || defined(CONFIG_USB_SERIAL_PERACOM) /***************************************************************************** * eTek specific driver functions *****************************************************************************/ static int etek_serial_open (struct tty_struct *tty, struct file *filp) { - struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; + struct usb_serial *serial = (struct usb_serial *) tty->driver_data; + int port = MINOR(tty->device) - serial->minor; - dbg("etek_serial_open"); + dbg("etek_serial_open port %d", port); - if (!serial->present) { - dbg("no device registered"); - return -EINVAL; - } - - if (serial->active) { + if (serial->active[port]) { dbg ("device already open"); return -EINVAL; } - serial->active = 1; + serial->active[port] = 1; /*Start reading from the device*/ - if (usb_submit_urb(&serial->read_urb)) + if (usb_submit_urb(&serial->read_urb[port])) dbg("usb_submit_urb(read bulk) failed"); /* Need to do device specific setup here (control lines, baud rate, etc.) */ @@ -730,41 +773,42 @@ static int etek_serial_open (struct tty_struct *tty, struct file *filp) static void etek_serial_close(struct tty_struct *tty, struct file * filp) { - struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; - dbg("etek_serial_close"); + struct usb_serial *serial = (struct usb_serial *) tty->driver_data; + int port = MINOR(tty->device) - serial->minor; + + dbg("etek_serial_close port %d", port); /* Need to change the control lines here */ /* FIXME */ /* shutdown our bulk reads and writes */ - usb_unlink_urb (&serial->write_urb); - usb_unlink_urb (&serial->read_urb); - serial->active = 0; + usb_unlink_urb (&serial->write_urb[port]); + usb_unlink_urb (&serial->read_urb[port]); + serial->active[port] = 0; } +#endif /* defined(CONFIG_USB_SERIAL_BELKIN) || defined(CONFIG_USB_SERIAL_PERACOM) */ + +#ifdef CONFIG_USB_SERIAL_WHITEHEAT /***************************************************************************** * Connect Tech's White Heat specific driver functions *****************************************************************************/ static int whiteheat_serial_open (struct tty_struct *tty, struct file *filp) { - struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; + struct usb_serial *serial = (struct usb_serial *) tty->driver_data; + int port = MINOR(tty->device) - serial->minor; - dbg("whiteheat_serial_open"); + dbg("whiteheat_serial_open port %d", port); - if (!serial->present) { - dbg("no device registered"); - return -EINVAL; - } - - if (serial->active) { + if (serial->active[port]) { dbg ("device already open"); return -EINVAL; } - serial->active = 1; + serial->active[port] = 1; /*Start reading from the device*/ - if (usb_submit_urb(&serial->read_urb)) + if (usb_submit_urb(&serial->read_urb[port])) dbg("usb_submit_urb(read bulk) failed"); /* Need to do device specific setup here (control lines, baud rate, etc.) */ @@ -776,23 +820,28 @@ static int whiteheat_serial_open (struct tty_struct *tty, struct file *filp) static void whiteheat_serial_close(struct tty_struct *tty, struct file * filp) { - struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; - dbg("whiteheat_serial_close"); + struct usb_serial *serial = (struct usb_serial *) tty->driver_data; + int port = MINOR(tty->device) - serial->minor; + + dbg("whiteheat_serial_close port %d", port); /* Need to change the control lines here */ /* FIXME */ /* shutdown our bulk reads and writes */ - usb_unlink_urb (&serial->write_urb); - usb_unlink_urb (&serial->read_urb); - serial->active = 0; + usb_unlink_urb (&serial->write_urb[port]); + usb_unlink_urb (&serial->read_urb[port]); + serial->active[port] = 0; } static void whiteheat_throttle (struct tty_struct * tty) { - dbg("whiteheat_throttle"); - + struct usb_serial *serial = (struct usb_serial *) tty->driver_data; + int port = MINOR(tty->device) - serial->minor; + + dbg("whiteheat_throttle port %d", port); + /* Change the control signals */ /* FIXME!!! */ @@ -802,8 +851,11 @@ static void whiteheat_throttle (struct tty_struct * tty) static void whiteheat_unthrottle (struct tty_struct * tty) { - dbg("whiteheat_unthrottle"); - + struct usb_serial *serial = (struct usb_serial *) tty->driver_data; + int port = MINOR(tty->device) - serial->minor; + + dbg("whiteheat_unthrottle port %d", port); + /* Change the control signals */ /* FIXME!!! */ @@ -811,28 +863,131 @@ static void whiteheat_unthrottle (struct tty_struct * tty) } +static int whiteheat_writememory (struct usb_serial *serial, int address, unsigned char *data, int length, __u8 bRequest) +{ + int result; + unsigned char *transfer_buffer = kmalloc (length, GFP_KERNEL); + +// dbg("whiteheat_writememory %x, %d", address, length); + + if (!transfer_buffer) { + err("whiteheat_writememory: kmalloc(%d) failed.\n", length); + return -ENOMEM; + } + memcpy (transfer_buffer, data, length); + result = usb_control_msg (serial->dev, usb_sndctrlpipe(serial->dev, 0), bRequest, 0x40, address, 0, transfer_buffer, length, 300); + kfree (transfer_buffer); + return result; +} + +/* EZ-USB Control and Status Register. Bit 0 controls 8051 reset */ +#define CPUCS_REG 0x7F92 + +static int whiteheat_set_reset (struct usb_serial *serial, unsigned char reset_bit) +{ + int response; + dbg("whiteheat_set_reset: %d", reset_bit); + response = whiteheat_writememory (serial, CPUCS_REG, &reset_bit, 1, 0xa0); + if (response < 0) { + err("whiteheat_set_reset %d failed", reset_bit); + } + return (response); +} + + +/* steps to download the firmware to the WhiteHEAT device: + - hold the reset (by writing to the reset bit of the CPUCS register) + - download the VEND_AX.HEX file to the chip using VENDOR_REQUEST-ANCHOR_LOAD + - release the reset (by writing to the CPUCS register) + - download the WH.HEX file for all addresses greater than 0x1b3f using + VENDOR_REQUEST-ANCHOR_EXTERNAL_RAM_LOAD + - hold the reset + - download the WH.HEX file for all addresses less than 0x1b40 using + VENDOR_REQUEST_ANCHOR_LOAD + - release the reset + - device renumerated itself and comes up as new device id with all + firmware download completed. +*/ +static int whiteheat_startup (struct usb_serial *serial) +{ + int response; + const struct whiteheat_hex_record *record; + + dbg("whiteheat_startup"); + + response = whiteheat_set_reset (serial, 1); + + record = &whiteheat_loader[0]; + while (record->address != 0xffff) { + response = whiteheat_writememory (serial, record->address, + (unsigned char *)record->data, record->data_size, 0xa0); + if (response < 0) { + err("whiteheat_writememory failed for loader (%d %04X %p %d)", + response, record->address, record->data, record->data_size); + break; + } + ++record; + } + + response = whiteheat_set_reset (serial, 0); + + record = &whiteheat_firmware[0]; + while (record->address < 0x1b40) { + ++record; + } + while (record->address != 0xffff) { + response = whiteheat_writememory (serial, record->address, + (unsigned char *)record->data, record->data_size, 0xa0); + if (response < 0) { + err("whiteheat_writememory failed for first firmware step (%d %04X %p %d)", + response, record->address, record->data, record->data_size); + break; + } + ++record; + } + + response = whiteheat_set_reset (serial, 1); + + record = &whiteheat_firmware[0]; + while (record->address < 0x1b40) { + response = whiteheat_writememory (serial, record->address, + (unsigned char *)record->data, record->data_size, 0xa0); + if (response < 0) { + err("whiteheat_writememory failed for second firmware step (%d %04X %p %d)\n", + response, record->address, record->data, record->data_size); + break; + } + ++record; + } + + response = whiteheat_set_reset (serial, 0); + + /* we want this device to fail to have a driver assigned to it. */ + return (1); +} +#endif /* CONFIG_USB_SERIAL_WHITEHEAT */ + + +#ifdef CONFIG_USB_SERIAL_VISOR /****************************************************************************** * Handspring Visor specific driver functions ******************************************************************************/ static int visor_serial_open (struct tty_struct *tty, struct file *filp) { - struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; - dbg("visor_serial_open"); + struct usb_serial *serial = (struct usb_serial *) tty->driver_data; + int port = MINOR(tty->device) - serial->minor; - if (!serial->present) { - dbg("no device registered"); - return -EINVAL; - } + dbg("visor_serial_open port %d", port); - if (serial->active) { + if (serial->active[port]) { dbg ("device already open"); return -EINVAL; } - serial->active = 1; + serial->active[port] = 1; /*Start reading from the device*/ - if (usb_submit_urb(&serial->read_urb)) + if (usb_submit_urb(&serial->read_urb[port])) dbg("usb_submit_urb(read bulk) failed"); return (0); @@ -840,66 +995,146 @@ static int visor_serial_open (struct tty_struct *tty, struct file *filp) static void visor_serial_close(struct tty_struct *tty, struct file * filp) { - struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; + struct usb_serial *serial = (struct usb_serial *) tty->driver_data; + int port = MINOR(tty->device) - serial->minor; - dbg("USB: visor_serial_close"); + dbg("visor_serial_close port %d", port); /* shutdown our bulk reads and writes */ - usb_unlink_urb (&serial->write_urb); - usb_unlink_urb (&serial->read_urb); - serial->active = 0; + usb_unlink_urb (&serial->write_urb[port]); + usb_unlink_urb (&serial->read_urb[port]); + serial->active[port] = 0; } static void visor_throttle (struct tty_struct * tty) { -/* struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; */ + struct usb_serial *serial = (struct usb_serial *) tty->driver_data; + int port = MINOR(tty->device) - serial->minor; - dbg("visor_throttle"); + dbg("visor_throttle port %d", port); - /* Change the control signals */ - /* FIXME!!! */ + usb_unlink_urb (&serial->read_urb[port]); return; } + static void visor_unthrottle (struct tty_struct * tty) { -/* struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; */ + struct usb_serial *serial = (struct usb_serial *) tty->driver_data; + int port = MINOR(tty->device) - serial->minor; - dbg("visor_unthrottle"); + dbg("visor_unthrottle port %d", port); - /* Change the control signals */ - /* FIXME!!! */ + if (usb_unlink_urb (&serial->read_urb[port])) + dbg("usb_submit_urb(read bulk) failed"); return; } +/* + Here's the raw dump of the vendor specific command data that the Visor sends on Win98 +______________________________________________________________________ +SETUP(0xB4) ADDR(0x02) ENDP(0x0) CRC5(0x15) +______________________________________________________________________ +DATA0(0xC3) DATA(C2 03 00 00 00 00 12 00 ) CRC16(0xB0BB) +______________________________________________________________________ +ACK(0x4B) +______________________________________________________________________ +IN(0x96) ADDR(0x02) ENDP(0x0) CRC5(0x15) +______________________________________________________________________ +DATA1(0xD2) DATA(02 00 00 01 02 02 ) CRC16(0xF4E6) +______________________________________________________________________ +ACK(0x4B) +______________________________________________________________________ +OUT(0x87) ADDR(0x02) ENDP(0x0) CRC5(0x15) +______________________________________________________________________ +DATA1(0xD2) DATA() CRC16(0x0000) +______________________________________________________________________ +ACK(0x4B) +______________________________________________________________________ +SETUP(0xB4) ADDR(0x02) ENDP(0x0) CRC5(0x15) +______________________________________________________________________ +DATA0(0xC3) DATA(C2 01 00 00 05 00 02 00 ) CRC16(0xC488) +______________________________________________________________________ +ACK(0x4B) +______________________________________________________________________ +IN(0x96) ADDR(0x02) ENDP(0x0) CRC5(0x15) +______________________________________________________________________ +DATA1(0xD2) DATA(01 00 ) CRC16(0xFFFB) +______________________________________________________________________ +ACK(0x4B) +______________________________________________________________________ +OUT(0x87) ADDR(0x02) ENDP(0x0) CRC5(0x15) +______________________________________________________________________ +DATA1(0xD2) DATA() CRC16(0x0000) +______________________________________________________________________ +ACK(0x4B) +______________________________________________________________________ +*/ + +static int visor_startup (struct usb_serial *serial) +{ + /* send out two unknown commands that I found by looking at a Win98 trace */ + int response; + unsigned char *transfer_buffer = kmalloc (256, GFP_KERNEL); + + if (!transfer_buffer) { + err("visor_startup: kmalloc(%d) failed.\n", 256); + return -ENOMEM; + } + + dbg("visor_startup"); + + dbg("visor_setup: Set config to 1"); + usb_set_configuration (serial->dev, 1); + + response = usb_control_msg (serial->dev, usb_sndctrlpipe(serial->dev, 0), 0x03, 0xc2, 0x0000, 0x0000, transfer_buffer, 0x12, 300); + if (response < 0) { + err("visor_startup: error getting first vendor specific message"); + } else { + dbg("visor_startup: First vendor specific message successful"); + } + + response = usb_control_msg (serial->dev, usb_sndctrlpipe(serial->dev, 0), 0x01, 0xc2, 0x0000, 0x0005, transfer_buffer, 0x02, 300); + if (response < 0) { + err("visor_startup: error getting second vendor specific message"); + } else { + dbg("visor_startup: Second vendor specific message successful"); + } + + kfree (transfer_buffer); + + /* continue on with initialization */ + return (0); +} + + +#endif /* CONFIG_USB_SERIAL_VISOR*/ + + /***************************************************************************** * generic devices specific driver functions *****************************************************************************/ static int generic_serial_open (struct tty_struct *tty, struct file *filp) { - struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; + struct usb_serial *serial = (struct usb_serial *) tty->driver_data; + int port = MINOR(tty->device) - serial->minor; - dbg("generic_serial_open"); + dbg("generic_serial_open port %d", port); - if (!serial->present) { - dbg("no device registered"); - return -EINVAL; - } - - if (serial->active) { + if (serial->active[port]) { dbg ("device already open"); return -EINVAL; } - serial->active = 1; + serial->active[port] = 1; /* if we have a bulk interrupt, start reading from it */ if (serial->num_bulk_in) { /*Start reading from the device*/ - if (usb_submit_urb(&serial->read_urb)) + if (usb_submit_urb(&serial->read_urb[port])) dbg("usb_submit_urb(read bulk) failed"); } @@ -909,26 +1144,29 @@ static int generic_serial_open (struct tty_struct *tty, struct file *filp) static void generic_serial_close(struct tty_struct *tty, struct file * filp) { - struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; - dbg("generic_serial_close"); + struct usb_serial *serial = (struct usb_serial *) tty->driver_data; + int port = MINOR(tty->device) - serial->minor; + + dbg("generic_serial_close port %d", port); /* shutdown any bulk reads that might be going on */ if (serial->num_bulk_out) { - usb_unlink_urb (&serial->write_urb); + usb_unlink_urb (&serial->write_urb[port]); } if (serial->num_bulk_in) { - usb_unlink_urb (&serial->read_urb); + usb_unlink_urb (&serial->read_urb[port]); } - serial->active = 0; + serial->active[port] = 0; } static int generic_serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count) { - struct usb_serial_state *serial = (struct usb_serial_state *) tty->driver_data; - - dbg("generic_serial_write"); + struct usb_serial *serial = (struct usb_serial *) tty->driver_data; + int port = MINOR(tty->device) - serial->minor; + + dbg("generic_serial_write port %d", port); if (count == 0) { dbg("write request of 0 bytes"); @@ -937,24 +1175,24 @@ static int generic_serial_write (struct tty_struct * tty, int from_user, const u /* only do something if we have a bulk out endpoint */ if (serial->num_bulk_out) { - if (serial->write_urb.status == -EINPROGRESS) { + if (serial->write_urb[port].status == -EINPROGRESS) { dbg ("already writing"); return (0); } - count = (count > serial->bulk_out_size[0]) ? serial->bulk_out_size[0] : count; + count = (count > serial->bulk_out_size[port]) ? serial->bulk_out_size[port] : count; if (from_user) { - copy_from_user(serial->write_urb.transfer_buffer, buf, count); + copy_from_user(serial->write_urb[port].transfer_buffer, buf, count); } else { - memcpy (serial->write_urb.transfer_buffer, buf, count); + memcpy (serial->write_urb[port].transfer_buffer, buf, count); } /* send the data out the bulk port */ - serial->write_urb.transfer_buffer_length = count; + serial->write_urb[port].transfer_buffer_length = count; - if (usb_submit_urb(&serial->write_urb)) + if (usb_submit_urb(&serial->write_urb[port])) dbg("usb_submit_urb(write bulk) failed"); return (count); @@ -965,39 +1203,19 @@ static int generic_serial_write (struct tty_struct * tty, int from_user, const u } -static void generic_serial_put_char (struct tty_struct *tty, unsigned char ch) -{ - struct usb_serial_state *serial = (struct usb_serial_state *)tty->driver_data; - - dbg("generic_serial_put_char"); - - /* if we have a bulk out endpoint, then shove a character out it */ - if (serial->num_bulk_out) { - /* send the single character out the bulk port */ - memcpy (serial->write_urb.transfer_buffer, &ch, 1); - serial->write_urb.transfer_buffer_length = 1; - - if (usb_submit_urb(&serial->write_urb)) - dbg("usb_submit_urb(write bulk) failed"); - - } - - return; -} - - static int generic_write_room (struct tty_struct *tty) { - struct usb_serial_state *serial = (struct usb_serial_state *)tty->driver_data; + struct usb_serial *serial = (struct usb_serial *)tty->driver_data; + int port = MINOR(tty->device) - serial->minor; int room; - dbg("generic_write_room"); + dbg("generic_write_room port %d", port); if (serial->num_bulk_out) { - if (serial->write_urb.status == -EINPROGRESS) + if (serial->write_urb[port].status == -EINPROGRESS) room = 0; else - room = serial->bulk_out_size[0]; + room = serial->bulk_out_size[port]; dbg("generic_write_room returns %d", room); return (room); } @@ -1008,13 +1226,14 @@ static int generic_write_room (struct tty_struct *tty) static int generic_chars_in_buffer (struct tty_struct *tty) { - struct usb_serial_state *serial = (struct usb_serial_state *)tty->driver_data; + struct usb_serial *serial = (struct usb_serial *)tty->driver_data; + int port = MINOR(tty->device) - serial->minor; - dbg("generic_chars_in_buffer"); + dbg("generic_chars_in_buffer port %d", port); if (serial->num_bulk_out) { - if (serial->write_urb.status == -EINPROGRESS) { - return (serial->bulk_out_size[0]); + if (serial->write_urb[port].status == -EINPROGRESS) { + return (serial->bulk_out_size[port]); } } @@ -1022,29 +1241,18 @@ static int generic_chars_in_buffer (struct tty_struct *tty) } -static int Get_Free_Serial (void) -{ - int i; - - for (i=0; i < NUM_PORTS; ++i) { - if (!serial_state_table[i].present) - return (i); - } - return (-1); -} - - static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum) { - struct usb_serial_state *serial = NULL; + struct usb_serial *serial = NULL; struct usb_interface_descriptor *interface; struct usb_endpoint_descriptor *endpoint; - struct usb_endpoint_descriptor *interrupt_in_endpoint[MAX_ENDPOINTS]; - struct usb_endpoint_descriptor *bulk_in_endpoint[MAX_ENDPOINTS]; - struct usb_endpoint_descriptor *bulk_out_endpoint[MAX_ENDPOINTS]; + struct usb_endpoint_descriptor *interrupt_in_endpoint[MAX_NUM_PORTS]; + struct usb_endpoint_descriptor *bulk_in_endpoint[MAX_NUM_PORTS]; + struct usb_endpoint_descriptor *bulk_out_endpoint[MAX_NUM_PORTS]; struct usb_serial_device_type *type; int device_num; - int serial_num; + int minor; + int buffer_size; int i; char interrupt_pipe; char bulk_in_pipe; @@ -1109,83 +1317,69 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum) /* found all that we need */ info("%s converter detected", type->name); - if (0>(serial_num = Get_Free_Serial())) { - dbg("Too many devices connected"); + serial = get_free_serial (type->num_ports, &minor); + if (serial == NULL) { + err("No more free serial devices"); return NULL; } - serial = &serial_state_table[serial_num]; - - memset(serial, 0, sizeof(struct usb_serial_state)); serial->dev = dev; serial->type = type; - serial->number = serial_num; + serial->minor = minor; + serial->num_ports = type->num_ports; serial->num_bulk_in = num_bulk_in; serial->num_bulk_out = num_bulk_out; serial->num_interrupt_in = num_interrupt_in; + /* if this device type has a startup function, call it */ + if (type->startup) { + if (type->startup (serial)) + return NULL; + } + /* set up the endpoint information */ for (i = 0; i < num_bulk_in; ++i) { - serial->bulk_in_endpoint[i] = bulk_in_endpoint[i]->bEndpointAddress; - serial->bulk_in_size[i] = bulk_in_endpoint[i]->wMaxPacketSize; - serial->bulk_in_interval[i] = bulk_in_endpoint[i]->bInterval; - serial->bulk_in_pipe[i] = usb_rcvbulkpipe (dev, serial->bulk_in_endpoint[i]); - serial->bulk_in_buffer[i] = kmalloc (serial->bulk_in_size[i], GFP_KERNEL); + buffer_size = bulk_in_endpoint[i]->wMaxPacketSize; + serial->bulk_in_buffer[i] = kmalloc (buffer_size, GFP_KERNEL); if (!serial->bulk_in_buffer[i]) { err("Couldn't allocate bulk_in_buffer"); goto probe_error; } + FILL_BULK_URB(&serial->read_urb[i], dev, usb_rcvbulkpipe (dev, bulk_in_endpoint[i]->bEndpointAddress), + serial->bulk_in_buffer[i], buffer_size, serial_read_bulk, serial); } - if (num_bulk_in) - FILL_BULK_URB(&serial->read_urb, dev, usb_rcvbulkpipe (dev, serial->bulk_in_endpoint[0]), - serial->bulk_in_buffer[0], serial->bulk_in_size[0], serial_read_bulk, serial); for (i = 0; i < num_bulk_out; ++i) { - serial->bulk_out_endpoint[i] = bulk_out_endpoint[i]->bEndpointAddress; serial->bulk_out_size[i] = bulk_out_endpoint[i]->wMaxPacketSize; - serial->bulk_out_interval[i] = bulk_out_endpoint[i]->bInterval; - serial->bulk_out_pipe[i] = usb_rcvbulkpipe (dev, serial->bulk_out_endpoint[i]); serial->bulk_out_buffer[i] = kmalloc (serial->bulk_out_size[i], GFP_KERNEL); if (!serial->bulk_out_buffer[i]) { err("Couldn't allocate bulk_out_buffer"); goto probe_error; } + FILL_BULK_URB(&serial->write_urb[i], dev, usb_sndbulkpipe (dev, bulk_out_endpoint[i]->bEndpointAddress), + serial->bulk_out_buffer[i], serial->bulk_out_size[i], serial_write_bulk, serial); } - if (num_bulk_out) - FILL_BULK_URB(&serial->write_urb, dev, usb_sndbulkpipe (dev, serial->bulk_in_endpoint[0]), - serial->bulk_in_buffer[0], serial->bulk_in_size[0], serial_write_bulk, serial); +#if 0 /* use this code when WhiteHEAT is up and running */ for (i = 0; i < num_interrupt_in; ++i) { - serial->interrupt_in_inuse = 0; - serial->interrupt_in_endpoint[i] = interrupt_in_endpoint[i]->bEndpointAddress; - serial->interrupt_in_size[i] = interrupt_in_endpoint[i]->wMaxPacketSize; - serial->interrupt_in_interval[i] = interrupt_in_endpoint[i]->bInterval; - /* serial->interrupt_in_pipe = usb_rcvbulkpipe (dev, serial->bulk_in_endpoint); */ - serial->interrupt_in_buffer[i] = kmalloc (serial->bulk_in_size[i], GFP_KERNEL); + buffer_size = interrupt_in_endpoint[i]->wMaxPacketSize; + serial->interrupt_in_buffer[i] = kmalloc (buffer_size, GFP_KERNEL); if (!serial->interrupt_in_buffer[i]) { err("Couldn't allocate interrupt_in_buffer"); goto probe_error; } + FILL_INT_URB(&serial->control_urb[i], dev, usb_rcvintpipe (dev, interrupt_in_endpoint[i]->bEndpointAddress), + serial->interrupt_in_buffer[i], buffer_size, serial_control_irq, + serial, interrupt_in_endpoint[i]->bInterval); } +#endif - #if 0 - /* set up an interrupt for out bulk in pipe */ - /* ask for a bulk read */ - serial->bulk_in_inuse = 1; - serial->bulk_in_transfer = usb_request_bulk (serial->dev, serial->bulk_in_pipe, serial_read_irq, serial->bulk_in_buffer, serial->bulk_in_size, serial); - - /* set up our interrupt to be the time for the bulk in read */ - ret = usb_request_irq (dev, serial->bulk_in_pipe, usb_serial_irq, serial->bulk_in_interval, serial, &serial->irq_handle); - if (ret) { - info("failed usb_request_irq (0x%x)", ret); - goto probe_error; + for (i = 0; i < serial->num_ports; ++i) { + info("%s converter now attached to ttyUSB%d", type->name, serial->minor + i); } - #endif - serial->present = 1; MOD_INC_USE_COUNT; - info("%s converter now attached to ttyUSB%d", type->name, serial_num); return serial; } else { info("descriptors matched, but endpoints did not"); @@ -1214,19 +1408,16 @@ probe_error: static void usb_serial_disconnect(struct usb_device *dev, void *ptr) { - struct usb_serial_state *serial = (struct usb_serial_state *) ptr; + struct usb_serial *serial = (struct usb_serial *) ptr; int i; if (serial) { - if (!serial->present) { - /* something strange is going on */ - dbg("disconnect but not present?"); - return; - } - /* need to stop any transfers...*/ - usb_unlink_urb (&serial->write_urb); - usb_unlink_urb (&serial->read_urb); + for (i = 0; i < serial->num_ports; ++i) { + usb_unlink_urb (&serial->write_urb[i]); + usb_unlink_urb (&serial->read_urb[i]); + serial->active[i] = 0; + } /* free up any memory that we allocated */ for (i = 0; i < serial->num_bulk_in; ++i) @@ -1239,17 +1430,18 @@ static void usb_serial_disconnect(struct usb_device *dev, void *ptr) if (serial->interrupt_in_buffer[i]) kfree (serial->interrupt_in_buffer[i]); - serial->present = 0; - serial->active = 0; + for (i = 0; i < serial->num_ports; ++i) { + info("%s converter now disconnected from ttyUSB%d", serial->type->name, serial->minor + i); + } - info("%s converter now disconnected from ttyUSB%d", serial->type->name, serial->number); + serial_table[serial->minor] = NULL; + kfree (serial); } else { info("device disconnected"); } MOD_DEC_USE_COUNT; - } @@ -1257,9 +1449,9 @@ static struct tty_driver serial_tty_driver = { magic: TTY_DRIVER_MAGIC, driver_name: "usb", name: "ttyUSB", - major: SERIAL_MAJOR, + major: SERIAL_TTY_MAJOR, minor_start: 0, - num: NUM_PORTS, + num: SERIAL_TTY_MINORS, type: TTY_DRIVER_TYPE_SERIAL, subtype: SERIAL_TYPE_NORMAL, flags: TTY_DRIVER_REAL_RAW, @@ -1273,7 +1465,7 @@ static struct tty_driver serial_tty_driver = { open: serial_open, close: serial_close, write: serial_write, - put_char: serial_put_char, + put_char: NULL, flush_chars: NULL, write_room: serial_write_room, ioctl: NULL, @@ -1298,8 +1490,8 @@ int usb_serial_init(void) int i; /* Initalize our global data */ - for (i = 0; i < NUM_PORTS; ++i) { - memset(&serial_state_table[i], 0x00, sizeof(struct usb_serial_state)); + for (i = 0; i < SERIAL_TTY_MINORS; ++i) { + serial_table[i] = NULL; } /* register the tty driver */ |