patch-2.3.40 linux/drivers/usb/usb-serial.c
Next file: linux/drivers/usb/usb.c
Previous file: linux/drivers/usb/usb-debug.c
Back to the patch index
Back to the overall index
- Lines: 1476
- Date:
Thu Jan 20 09:48:48 2000
- Orig file:
v2.3.39/linux/drivers/usb/usb-serial.c
- Orig date:
Fri Jan 7 19:13:22 2000
diff -u --recursive --new-file v2.3.39/linux/drivers/usb/usb-serial.c linux/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 @@
#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 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 @@
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 @@
/* 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 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_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 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 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 @@
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 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 @@
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 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 @@
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_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 @@
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 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 @@
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_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 @@
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 @@
}
+#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;
-
- dbg("etek_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("etek_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");
/* Need to do device specific setup here (control lines, baud rate, etc.) */
@@ -730,41 +773,42 @@
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 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_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 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 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 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 @@
/* 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 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_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 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 @@
/* 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 @@
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 @@
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 @@
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 @@
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 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 */
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)