summaryrefslogtreecommitdiffstats
path: root/drivers/usb/serial
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/serial')
-rw-r--r--drivers/usb/serial/Makefile2
-rw-r--r--drivers/usb/serial/ftdi_sio.c10
-rw-r--r--drivers/usb/serial/keyspan_pda.c198
-rw-r--r--drivers/usb/serial/omninet.c339
-rw-r--r--drivers/usb/serial/usb-serial.h21
-rw-r--r--drivers/usb/serial/usbserial.c468
6 files changed, 699 insertions, 339 deletions
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
index 95a686e7a..bd4d51a6a 100644
--- a/drivers/usb/serial/Makefile
+++ b/drivers/usb/serial/Makefile
@@ -4,7 +4,7 @@
O_TARGET := usb-serial.o
M_OBJS := usb-serial.o
-O_OBJS := usbserial.o visor.o whiteheat.o ftdi_sio.o keyspan_pda.o
+O_OBJS := usbserial.o visor.o whiteheat.o ftdi_sio.o keyspan_pda.o omninet.o
MOD_LIST_NAME := USB_SERIAL_MODULES
include $(TOPDIR)/Rules.make
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 151c4bfe7..a305283bb 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -153,7 +153,7 @@ struct usb_serial_device_type ftdi_sio_device = {
/* do some startup allocations not currently performed by usb_serial_probe() */
static int ftdi_sio_startup (struct usb_serial *serial)
{
- init_waitqueue_head(&serial->write_wait);
+ init_waitqueue_head(&serial->port[0].write_wait);
return (0);
}
@@ -291,7 +291,7 @@ static int ftdi_sio_write (struct usb_serial_port *port, int from_user,
/* Was seeing a race here, got a read callback, then write callback before
hitting interuptible_sleep_on - so wrapping in add_wait_queue stuff */
- add_wait_queue(&serial->write_wait, &wait);
+ add_wait_queue(&port->write_wait, &wait);
set_current_state (TASK_INTERRUPTIBLE);
while (port->write_urb->status == -EINPROGRESS) {
dbg("ftdi_sio - write in progress - retrying");
@@ -301,13 +301,13 @@ static int ftdi_sio_write (struct usb_serial_port *port, int from_user,
}
if (signal_pending(current)) {
current->state = TASK_RUNNING;
- remove_wait_queue(&serial->write_wait, &wait);
+ remove_wait_queue(&port->write_wait, &wait);
rc = -ERESTARTSYS;
goto err;
}
schedule();
}
- remove_wait_queue(&serial->write_wait, &wait);
+ remove_wait_queue(&port->write_wait, &wait);
set_current_state(TASK_RUNNING);
count += data_offset;
@@ -388,7 +388,7 @@ static void ftdi_sio_write_bulk_callback (struct urb *urb)
return;
}
- wake_up_interruptible(&serial->write_wait);
+ wake_up_interruptible(&port->write_wait);
if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
(tty->ldisc.write_wakeup)(tty);
diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
index 9fb22e4a8..c63f1b856 100644
--- a/drivers/usb/serial/keyspan_pda.c
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -52,78 +52,20 @@ struct ezusb_hex_record {
#include "usb-serial.h"
+struct keyspan_pda_private {
+ int tx_room;
+ int tx_throttled;
+};
+
#define KEYSPAN_VENDOR_ID 0x06cd
#define KEYSPAN_PDA_FAKE_ID 0x0103
#define KEYSPAN_PDA_ID 0x0104 /* no clue */
-/* function prototypes for a Keyspan PDA serial converter */
-static int keyspan_pda_open (struct usb_serial_port *port,
- struct file *filp);
-static void keyspan_pda_close (struct usb_serial_port *port,
- struct file *filp);
-static int keyspan_pda_startup (struct usb_serial *serial);
-static void keyspan_pda_rx_throttle (struct usb_serial_port *port);
-static void keyspan_pda_rx_unthrottle (struct usb_serial_port *port);
-static int keyspan_pda_setbaud (struct usb_serial *serial, int baud);
-static int keyspan_pda_write_room (struct usb_serial_port *port);
-static int keyspan_pda_write (struct usb_serial_port *port,
- int from_user,
- const unsigned char *buf,
- int count);
-static void keyspan_pda_write_bulk_callback (struct urb *urb);
-static int keyspan_pda_chars_in_buffer (struct usb_serial_port *port);
-static int keyspan_pda_ioctl (struct usb_serial_port *port,
- struct file *file,
- unsigned int cmd,
- unsigned long arg);
-static void keyspan_pda_set_termios (struct usb_serial_port *port,
- struct termios *old);
-static void keyspan_pda_break_ctl (struct usb_serial_port *port,
- int break_state);
-static int keyspan_pda_fake_startup (struct usb_serial *serial);
-
-
/* All of the device info needed for the Keyspan PDA serial converter */
static __u16 keyspan_vendor_id = KEYSPAN_VENDOR_ID;
static __u16 keyspan_pda_fake_product_id = KEYSPAN_PDA_FAKE_ID;
static __u16 keyspan_pda_product_id = KEYSPAN_PDA_ID;
-struct usb_serial_device_type keyspan_pda_fake_device = {
- name: "Keyspan PDA - (prerenumeration)",
- idVendor: &keyspan_vendor_id, /* the Keyspan PDA vendor ID */
- idProduct: &keyspan_pda_fake_product_id, /* the Keyspan PDA initial product id */
- needs_interrupt_in: DONT_CARE, /* don't have to have an interrupt in endpoint */
- needs_bulk_in: DONT_CARE, /* don't have to have a bulk in endpoint */
- needs_bulk_out: DONT_CARE, /* don't have to have a bulk out endpoint */
- num_interrupt_in: NUM_DONT_CARE,
- num_bulk_in: NUM_DONT_CARE,
- num_bulk_out: NUM_DONT_CARE,
- num_ports: 1,
- startup: keyspan_pda_fake_startup
-};
-struct usb_serial_device_type keyspan_pda_device = {
- name: "Keyspan PDA",
- idVendor: &keyspan_vendor_id, /* the Keyspan PDA vendor ID */
- idProduct: &keyspan_pda_product_id, /* the Keyspan PDA product id */
- needs_interrupt_in: MUST_HAVE,
- needs_bulk_in: DONT_CARE,
- needs_bulk_out: MUST_HAVE,
- num_interrupt_in: 1,
- num_bulk_in: 0,
- num_bulk_out: 1,
- num_ports: 1,
- open: keyspan_pda_open,
- close: keyspan_pda_close,
- write: keyspan_pda_write,
- write_room: keyspan_pda_write_room,
- write_bulk_callback: keyspan_pda_write_bulk_callback,
- chars_in_buffer: keyspan_pda_chars_in_buffer,
- throttle: keyspan_pda_rx_throttle,
- unthrottle: keyspan_pda_rx_unthrottle,
- startup: keyspan_pda_startup,
- ioctl: keyspan_pda_ioctl,
- set_termios: keyspan_pda_set_termios,
- break_ctl: keyspan_pda_break_ctl,
-};
+
static void keyspan_pda_rx_interrupt (struct urb *urb)
@@ -133,6 +75,8 @@ static void keyspan_pda_rx_interrupt (struct urb *urb)
struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
int i;
+ struct keyspan_pda_private *priv;
+ priv = (struct keyspan_pda_private *)(port->private);
/* the urb might have been killed. */
if (urb->status)
@@ -167,8 +111,8 @@ static void keyspan_pda_rx_interrupt (struct urb *urb)
break;
case 2: /* tx unthrottle interrupt */
tty = serial->port[0].tty;
- serial->tx_throttled = 0;
- wake_up(&serial->write_wait); /* wake up writer */
+ priv->tx_throttled = 0;
+ wake_up(&port->write_wait); /* wake up writer */
wake_up(&tty->write_wait); /* them too */
break;
default:
@@ -193,7 +137,7 @@ static void keyspan_pda_rx_throttle (struct usb_serial_port *port)
upon the device too. */
dbg("keyspan_pda_rx_throttle port %d", port->number);
- usb_unlink_urb(port->read_urb);
+ usb_unlink_urb(port->interrupt_in_urb);
}
@@ -201,7 +145,7 @@ static void keyspan_pda_rx_unthrottle (struct usb_serial_port *port)
{
/* just restart the receive interrupt URB */
dbg("keyspan_pda_rx_unthrottle port %d", port->number);
- if (usb_submit_urb(port->read_urb))
+ if (usb_submit_urb(port->interrupt_in_urb))
dbg(" usb_submit_urb(read urb) failed");
return;
}
@@ -409,8 +353,10 @@ static int keyspan_pda_write(struct usb_serial_port *port, int from_user,
struct usb_serial *serial = port->serial;
int request_unthrottle = 0;
int rc = 0;
+ struct keyspan_pda_private *priv;
DECLARE_WAITQUEUE(wait, current);
+ priv = (struct keyspan_pda_private *)(port->private);
/* guess how much room is left in the device's ring buffer, and if we
want to send more than that, check first, updating our notion of
what is left. If our write will result in no room left, ask the
@@ -419,7 +365,7 @@ static int keyspan_pda_write(struct usb_serial_port *port, int from_user,
select() or poll() too) until we receive that unthrottle interrupt.
Block if we can't write anything at all, otherwise write as much as
we can. */
-
+ dbg("keyspan_pda_write(%d)",count);
if (count == 0) {
dbg(" write request of 0 bytes");
return (0);
@@ -434,7 +380,7 @@ static int keyspan_pda_write(struct usb_serial_port *port, int from_user,
rc = -EAGAIN;
goto err;
}
- interruptible_sleep_on(&serial->write_wait);
+ interruptible_sleep_on(&port->write_wait);
if (signal_pending(current)) {
rc = -ERESTARTSYS;
goto err;
@@ -451,16 +397,16 @@ static int keyspan_pda_write(struct usb_serial_port *port, int from_user,
have to be careful to avoid a race that would cause us to sleep
forever. */
- add_wait_queue(&serial->write_wait, &wait);
+ add_wait_queue(&port->write_wait, &wait);
set_current_state(TASK_INTERRUPTIBLE);
- while (serial->tx_throttled) {
+ while (priv->tx_throttled) {
/* device can't accomodate any more characters. Sleep until it
can. Woken up by an Rx interrupt message, which clears
tx_throttled first. */
dbg(" tx_throttled, going to sleep");
if (signal_pending(current)) {
current->state = TASK_RUNNING;
- remove_wait_queue(&serial->write_wait, &wait);
+ remove_wait_queue(&port->write_wait, &wait);
dbg(" woke up because of signal");
rc = -ERESTARTSYS;
goto err;
@@ -468,11 +414,11 @@ static int keyspan_pda_write(struct usb_serial_port *port, int from_user,
schedule();
dbg(" woke up");
}
- remove_wait_queue(&serial->write_wait, &wait);
+ remove_wait_queue(&port->write_wait, &wait);
set_current_state(TASK_RUNNING);
count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
- if (count > serial->tx_room) {
+ if (count > priv->tx_room) {
unsigned char room;
/* Looks like we might overrun the Tx buffer. Ask the device
how much room it really has */
@@ -495,15 +441,15 @@ static int keyspan_pda_write(struct usb_serial_port *port, int from_user,
return -EIO; /* device didn't return any data */
}
dbg(" roomquery says %d", room);
- serial->tx_room = room;
- if (count > serial->tx_room) {
+ priv->tx_room = room;
+ if (count > priv->tx_room) {
/* we're about to completely fill the Tx buffer, so
we'll be throttled afterwards. */
- count = serial->tx_room;
+ count = priv->tx_room;
request_unthrottle = 1;
}
}
- serial->tx_room -= count;
+ priv->tx_room -= count;
if (count) {
/* now transfer data */
@@ -529,7 +475,7 @@ static int keyspan_pda_write(struct usb_serial_port *port, int from_user,
dbg(" request_unthrottle");
/* ask the device to tell us when the tx buffer becomes
sufficiently empty */
- serial->tx_throttled = 1; /* block writers */
+ priv->tx_throttled = 1; /* block writers */
rc = usb_control_msg(serial->dev,
usb_sndctrlpipe(serial->dev, 0),
7, /* request_unthrottle */
@@ -563,7 +509,7 @@ static void keyspan_pda_write_bulk_callback (struct urb *urb)
return;
}
- wake_up_interruptible(&serial->write_wait);
+ wake_up_interruptible(&port->write_wait);
tty = port->tty;
if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
@@ -576,23 +522,25 @@ static void keyspan_pda_write_bulk_callback (struct urb *urb)
static int keyspan_pda_write_room (struct usb_serial_port *port)
{
- struct usb_serial *serial = port->serial;
+ struct keyspan_pda_private *priv;
+ priv = (struct keyspan_pda_private *)(port->private);
/* used by n_tty.c for processing of tabs and such. Giving it our
conservative guess is probably good enough, but needs testing by
running a console through the device. */
- return (serial->tx_room);
+ return (priv->tx_room);
}
static int keyspan_pda_chars_in_buffer (struct usb_serial_port *port)
{
- struct usb_serial *serial = port->serial;
+ struct keyspan_pda_private *priv;
+ priv = (struct keyspan_pda_private *)(port->private);
/* when throttled, return at least WAKEUP_CHARS to tell select() (via
n_tty.c:normal_poll() ) that we're not writeable. */
- if (serial->tx_throttled)
+ if (priv->tx_throttled)
return 256;
return 0;
}
@@ -603,6 +551,8 @@ static int keyspan_pda_open (struct usb_serial_port *port, struct file *filp)
struct usb_serial *serial = port->serial;
unsigned char room;
int rc;
+ struct keyspan_pda_private *priv;
+ priv = (struct keyspan_pda_private *)(port->private);
if (port->active) {
return -EINVAL;
@@ -627,8 +577,8 @@ static int keyspan_pda_open (struct usb_serial_port *port, struct file *filp)
dbg(" roomquery returned 0 bytes");
return -EIO; /* device didn't return any data */
}
- serial->tx_room = room;
- serial->tx_throttled = room ? 0 : 1;
+ priv->tx_room = room;
+ priv->tx_throttled = room ? 0 : 1;
/* the normal serial device seems to always turn on DTR and RTS here,
so do the same */
@@ -638,7 +588,7 @@ static int keyspan_pda_open (struct usb_serial_port *port, struct file *filp)
keyspan_pda_set_modem_info(serial, 0);
/*Start reading from the device*/
- if (usb_submit_urb(port->read_urb))
+ if (usb_submit_urb(port->interrupt_in_urb))
dbg(" usb_submit_urb(read int) failed");
return (0);
@@ -655,7 +605,7 @@ static void keyspan_pda_close(struct usb_serial_port *port, struct file *filp)
/* shutdown our bulk reads and writes */
usb_unlink_urb (port->write_urb);
- usb_unlink_urb (port->read_urb);
+ usb_unlink_urb (port->interrupt_in_urb);
port->active = 0;
}
@@ -691,27 +641,63 @@ static int keyspan_pda_fake_startup (struct usb_serial *serial)
return (1);
}
-
-/* do some startup allocations not currently performed by usb_serial_probe() */
static int keyspan_pda_startup (struct usb_serial *serial)
{
- struct usb_endpoint_descriptor *intin;
- intin = serial->port[0].interrupt_in_endpoint;
-
- /* set up the receive interrupt urb */
- FILL_INT_URB(serial->port[0].read_urb, serial->dev,
- usb_rcvintpipe(serial->dev, intin->bEndpointAddress),
- serial->port[0].interrupt_in_buffer,
- intin->wMaxPacketSize,
- keyspan_pda_rx_interrupt,
- serial,
- intin->bInterval);
-
- init_waitqueue_head(&serial->write_wait);
-
+ /* allocate the private data structures for all ports. Well, for all
+ one ports. */
+
+ serial->port[0].private = kmalloc(sizeof(struct keyspan_pda_private),
+ GFP_KERNEL);
+ if (!serial->port[0].private)
+ return (1); /* error */
+ init_waitqueue_head(&serial->port[0].write_wait);
return (0);
}
-#endif /* CONFIG_USB_SERIAL_KEYSPAN_PDA */
+static void keyspan_pda_shutdown (struct usb_serial *serial)
+{
+ kfree(serial->port[0].private);
+}
+struct usb_serial_device_type keyspan_pda_fake_device = {
+ name: "Keyspan PDA - (prerenumeration)",
+ idVendor: &keyspan_vendor_id,
+ idProduct: &keyspan_pda_fake_product_id,
+ needs_interrupt_in: DONT_CARE,
+ needs_bulk_in: DONT_CARE,
+ needs_bulk_out: DONT_CARE,
+ num_interrupt_in: NUM_DONT_CARE,
+ num_bulk_in: NUM_DONT_CARE,
+ num_bulk_out: NUM_DONT_CARE,
+ num_ports: 1,
+ startup: keyspan_pda_fake_startup,
+};
+struct usb_serial_device_type keyspan_pda_device = {
+ name: "Keyspan PDA",
+ idVendor: &keyspan_vendor_id,
+ idProduct: &keyspan_pda_product_id,
+ needs_interrupt_in: MUST_HAVE,
+ needs_bulk_in: DONT_CARE,
+ needs_bulk_out: MUST_HAVE,
+ num_interrupt_in: 1,
+ num_bulk_in: 0,
+ num_bulk_out: 1,
+ num_ports: 1,
+ open: keyspan_pda_open,
+ close: keyspan_pda_close,
+ write: keyspan_pda_write,
+ write_room: keyspan_pda_write_room,
+ write_bulk_callback: keyspan_pda_write_bulk_callback,
+ read_int_callback: keyspan_pda_rx_interrupt,
+ chars_in_buffer: keyspan_pda_chars_in_buffer,
+ throttle: keyspan_pda_rx_throttle,
+ unthrottle: keyspan_pda_rx_unthrottle,
+ ioctl: keyspan_pda_ioctl,
+ set_termios: keyspan_pda_set_termios,
+ break_ctl: keyspan_pda_break_ctl,
+ startup: keyspan_pda_startup,
+ shutdown: keyspan_pda_shutdown,
+};
+
+#endif /* CONFIG_USB_SERIAL_KEYSPAN_PDA */
diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c
new file mode 100644
index 000000000..2edcb6e86
--- /dev/null
+++ b/drivers/usb/serial/omninet.c
@@ -0,0 +1,339 @@
+/*
+ * USB ZyXEL omni.net LCD PLUS driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * See Documentation/usb/usb-serial.txt for more information on using this driver
+ *
+ */
+
+#include <linux/config.h>
+
+#ifdef CONFIG_USB_SERIAL_OMNINET
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <linux/fcntl.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+ #define isalpha(x) ( ( x > 96 && x < 123) || ( x > 64 && x < 91) || (x > 47 && x < 58) )
+ #define DEBUG
+#else
+ #undef DEBUG
+#endif
+
+#include <linux/usb.h>
+
+#include "usb-serial.h"
+
+
+#define ZYXEL_VENDOR_ID 0x0586
+#define ZYXEL_OMNINET_ID 0x1000
+
+/* function prototypes */
+static int omninet_open (struct usb_serial_port *port, struct file *filp);
+static void omninet_close (struct usb_serial_port *port, struct file *filp);
+static void omninet_read_bulk_callback (struct urb *urb);
+static void omninet_write_bulk_callback (struct urb *urb);
+static int omninet_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count);
+static int omninet_write_room (struct usb_serial_port *port);
+
+/* All of the device info needed for the omni.net */
+static __u16 zyxel_vendor_id = ZYXEL_VENDOR_ID;
+static __u16 zyxel_omninet_product_id = ZYXEL_OMNINET_ID;
+
+struct usb_serial_device_type zyxel_omninet_device = {
+ name: "ZyXEL - omni.net lcd plus usb",
+ idVendor: &zyxel_vendor_id,
+ idProduct: &zyxel_omninet_product_id,
+ needs_interrupt_in: MUST_HAVE,
+ needs_bulk_in: MUST_HAVE,
+ needs_bulk_out: MUST_HAVE,
+ num_interrupt_in: 1,
+ num_bulk_in: 1,
+ num_bulk_out: 2,
+ num_ports: 1,
+ open: omninet_open,
+ close: omninet_close,
+ write: omninet_write,
+ write_room: omninet_write_room,
+ read_bulk_callback: omninet_read_bulk_callback,
+ write_bulk_callback: omninet_write_bulk_callback,
+};
+
+
+/* The protocol.
+ *
+ * The omni.net always exchange 64 bytes of data with the host. The first
+ * four bytes are the control header, you can see it in the above structure.
+ *
+ * oh_seq is a sequence number. Don't know if/how it's used.
+ * oh_len is the length of the data bytes in the packet.
+ * oh_xxx Bit-mapped, related to handshaking and status info.
+ * I normally set it to 0x03 in trasmitted frames.
+ * 7: Active when the TA is in a CONNECTed state.
+ * 6: unknown
+ * 5: handshaking, unknown
+ * 4: handshaking, unknown
+ * 3: unknown, usually 0
+ * 2: unknown, usually 0
+ * 1: handshaking, unknown, usually set to 1 in trasmitted frames
+ * 0: handshaking, unknown, usually set to 1 in trasmitted frames
+ * oh_pad Probably a pad byte.
+ *
+ * After the header you will find data bytes if oh_len was greater than zero.
+ *
+ */
+
+struct omninet_header
+{
+ __u8 oh_seq;
+ __u8 oh_len;
+ __u8 oh_xxx;
+ __u8 oh_pad;
+};
+
+struct omninet_data
+{
+ __u8 od_outseq; // Sequence number for bulk_out URBs
+};
+
+static int omninet_open (struct usb_serial_port *port, struct file *filp)
+{
+ struct usb_serial *serial = port->serial;
+ struct usb_serial_port *wport = &serial->port[1];
+ struct omninet_data *od;
+
+ dbg("omninet_open port %d", port->number);
+
+ if (port->active) {
+ dbg ("device already open");
+ return -EINVAL;
+ }
+ port->active = 1;
+
+ od = kmalloc( sizeof(struct omninet_data), GFP_KERNEL );
+
+ if( !od )
+ {
+ err("omninet_open: kmalloc(%d) failed.", sizeof(struct omninet_data));
+ return -ENOMEM;
+ }
+
+ port->private = od;
+
+ /* Start reading from the device */
+ if (usb_submit_urb(port->read_urb))
+ dbg("usb_submit_urb(read bulk, %p) failed", port->read_urb);
+
+ wport->tty = port->tty;
+
+ return (0);
+}
+
+static void omninet_close (struct usb_serial_port *port, struct file * filp)
+{
+ struct usb_serial *serial = port->serial;
+ struct usb_serial_port *wport = &serial->port[1];
+ struct omninet_data *od = (struct omninet_data *) port->private;
+
+ port->active = 0;
+
+
+ dbg("zyxel_close port %d", port->number);
+
+ usb_unlink_urb (wport->write_urb);
+ usb_unlink_urb (port->read_urb);
+
+ if(od) kfree(od);
+}
+
+
+#define OMNINET_DATAOFFSET 0x04
+#define OMNINET_HEADERLEN sizeof(struct omninet_header)
+#define OMNINET_BULKOUTSIZE (64 - OMNINET_HEADERLEN)
+
+static void omninet_read_bulk_callback (struct urb *urb)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial *serial = port->serial;
+
+ unsigned char *data = urb->transfer_buffer;
+ struct omninet_header *header = (struct omninet_header *) &data[0];
+
+ int i;
+
+// dbg("omninet_read_bulk_callback");
+
+ if (port_paranoia_check (port, "omninet_read_bulk_callback")) {
+ return;
+ }
+
+ if (serial_paranoia_check (serial, "omninet_read_bulk_callback")) {
+ return;
+ }
+
+ if (urb->status) {
+ dbg("nonzero read bulk status received: %d", urb->status);
+ return;
+ }
+
+#ifdef DEBUG
+ if(header->oh_xxx != 0x30)
+ {
+ if (urb->actual_length) {
+ printk (KERN_DEBUG __FILE__ ": omninet_read %d: ", header->oh_len);
+ for (i = 0; i < (header->oh_len + OMNINET_HEADERLEN); i++) {
+ printk ("%.2x ", data[i]);
+ }
+ printk ("\n");
+ }
+ }
+#endif
+
+ if (urb->actual_length && header->oh_len)
+ {
+ for (i = 0; i < header->oh_len; i++) {
+ tty_insert_flip_char(port->tty, data[OMNINET_DATAOFFSET + i], 0);
+ }
+ tty_flip_buffer_push(port->tty);
+ }
+
+ /* Continue trying to always read */
+ if (usb_submit_urb(urb))
+ dbg("failed resubmitting read urb");
+
+ return;
+}
+
+static int omninet_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count)
+{
+ struct usb_serial *serial = port->serial;
+ struct usb_serial_port *wport = &serial->port[1];
+
+ struct omninet_data *od = (struct omninet_data *) port->private;
+ struct omninet_header *header = (struct omninet_header *) wport->write_urb->transfer_buffer;
+/*
+#ifdef DEBUG
+ int i;
+#endif
+*/
+
+// dbg("omninet_write port %d", port->number);
+
+ if (count == 0) {
+ dbg("write request of 0 bytes");
+ return (0);
+ }
+/*
+#ifdef DEBUG
+ printk (KERN_DEBUG __FILE__ ": omninet_write %d: ", count);
+ for (i = 0; i < count; i++) {
+ if( isalpha(buf[i]) )
+ printk ("%c ", buf[i]);
+ else
+ printk ("%.2x ", buf[i]);
+ }
+ printk ("\n");
+#endif
+*/
+ if (wport->write_urb->status == -EINPROGRESS) {
+ dbg ("already writing");
+ return (0);
+ }
+
+ count = (count > OMNINET_BULKOUTSIZE) ? OMNINET_BULKOUTSIZE : count;
+
+ if (from_user) {
+ copy_from_user(wport->write_urb->transfer_buffer + OMNINET_DATAOFFSET, buf, count);
+ }
+ else {
+ memcpy (wport->write_urb->transfer_buffer + OMNINET_DATAOFFSET, buf, count);
+ }
+
+
+ header->oh_seq = od->od_outseq++;
+ header->oh_len = count;
+ header->oh_xxx = 0x03;
+ header->oh_pad = 0x00;
+
+ /* send the data out the bulk port, always 64 bytes */
+ wport->write_urb->transfer_buffer_length = 64;
+
+ if (usb_submit_urb(wport->write_urb))
+ dbg("usb_submit_urb(write bulk) failed");
+
+// dbg("omninet_write returns %d", count);
+
+ return (count);
+}
+
+
+static int omninet_write_room (struct usb_serial_port *port)
+{
+ struct usb_serial *serial = port->serial;
+ struct usb_serial_port *wport = &serial->port[1];
+
+ int room = 0; // Default: no room
+
+ if (wport->write_urb->status != -EINPROGRESS)
+ room = wport->bulk_out_size - OMNINET_HEADERLEN;
+
+// dbg("omninet_write_room returns %d", room);
+
+ return (room);
+}
+
+static void omninet_write_bulk_callback (struct urb *urb)
+{
+/* struct omninet_header *header = (struct omninet_header *) urb->transfer_buffer; */
+ struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
+ struct usb_serial *serial;
+ struct tty_struct *tty;
+
+// dbg("omninet_write_bulk_callback, port %0x\n", port);
+
+
+ if (port_paranoia_check (port, "omninet_write_bulk_callback")) {
+ return;
+ }
+
+ serial = port->serial;
+ if (serial_paranoia_check (serial, "omninet_write_bulk_callback")) {
+ return;
+ }
+
+ if (urb->status) {
+ dbg("nonzero write bulk status received: %d", urb->status);
+ return;
+ }
+
+ tty = port->tty;
+
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
+ (tty->ldisc.write_wakeup)(tty);
+
+ wake_up_interruptible(&tty->write_wait);
+
+// dbg("omninet_write_bulk_callback, tty %0x\n", tty);
+
+ return;
+}
+
+#endif /* CONFIG_USB_SERIAL_OMNINET */
+
+
diff --git a/drivers/usb/serial/usb-serial.h b/drivers/usb/serial/usb-serial.h
index 6211a6309..8991f4be9 100644
--- a/drivers/usb/serial/usb-serial.h
+++ b/drivers/usb/serial/usb-serial.h
@@ -39,10 +39,8 @@ struct usb_serial_port {
unsigned char number;
char active; /* someone has this device open */
- struct usb_endpoint_descriptor * interrupt_in_endpoint;
- __u8 interrupt_in_interval;
unsigned char * interrupt_in_buffer;
- struct urb * control_urb;
+ struct urb * interrupt_in_urb;
unsigned char * bulk_in_buffer;
struct urb * read_urb;
@@ -50,7 +48,10 @@ struct usb_serial_port {
unsigned char * bulk_out_buffer;
int bulk_out_size;
struct urb * write_urb;
- void * private; /* data private to the specific driver */
+
+ wait_queue_head_t write_wait;
+
+ void * private; /* data private to the specific port */
};
struct usb_serial {
@@ -65,11 +66,6 @@ struct usb_serial {
char num_bulk_out; /* number of bulk out endpoints we have */
struct usb_serial_port port[MAX_NUM_PORTS];
- /* FIXME! These should move to the private area of the keyspan driver */
- int tx_room;
- int tx_throttled;
- wait_queue_head_t write_wait;
-
void * private; /* data private to the specific driver */
};
@@ -99,7 +95,8 @@ struct usb_serial_device_type {
/* function call to make before accepting driver */
int (*startup) (struct usb_serial *serial); /* return 0 to continue initialization, anything else to abort */
-
+ void (*shutdown) (struct usb_serial *serial);
+
/* serial function calls */
int (*open) (struct usb_serial_port *port, struct file * filp);
void (*close) (struct usb_serial_port *port, struct file * filp);
@@ -111,7 +108,8 @@ struct usb_serial_device_type {
int (*chars_in_buffer) (struct usb_serial_port *port);
void (*throttle) (struct usb_serial_port *port);
void (*unthrottle) (struct usb_serial_port *port);
-
+
+ void (*read_int_callback)(struct urb *urb);
void (*read_bulk_callback)(struct urb *urb);
void (*write_bulk_callback)(struct urb *urb);
};
@@ -124,6 +122,7 @@ extern struct usb_serial_device_type whiteheat_device;
extern struct usb_serial_device_type ftdi_sio_device;
extern struct usb_serial_device_type keyspan_pda_fake_device;
extern struct usb_serial_device_type keyspan_pda_device;
+extern struct usb_serial_device_type zyxel_omninet_device;
/* determine if we should include the EzUSB loader functions */
diff --git a/drivers/usb/serial/usbserial.c b/drivers/usb/serial/usbserial.c
index 0c1972675..588fed5d1 100644
--- a/drivers/usb/serial/usbserial.c
+++ b/drivers/usb/serial/usbserial.c
@@ -14,6 +14,14 @@
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
+ * (04/23/2000) gkh
+ * Fixed bug that Randy Dunlap found for Generic devices with no bulk out ports.
+ * Moved when the startup code printed out the devices that are supported.
+ *
+ * (04/19/2000) gkh
+ * Added driver for ZyXEL omni.net lcd plus ISDN TA
+ * Made startup info message specify which drivers were compiled in.
+ *
* (04/03/2000) gkh
* Changed the probe process to remove the module unload races.
* Changed where the tty layer gets initialized to have devfs work nicer.
@@ -211,6 +219,7 @@ MODULE_DESCRIPTION("USB Serial Driver");
#include "usb-serial.h"
+#define MAX(a,b) (((a)>(b))?(a):(b))
/* 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. */
@@ -270,6 +279,9 @@ static struct usb_serial_device_type *usb_serial_devices[] = {
&keyspan_pda_fake_device,
&keyspan_pda_device,
#endif
+#ifdef CONFIG_USB_SERIAL_OMNINET
+ &zyxel_omninet_device,
+#endif
NULL
};
@@ -424,14 +436,9 @@ static int serial_open (struct tty_struct *tty, struct file * filp)
return -ENODEV;
}
- /* set up our port structure */
+ /* set up our port structure making the tty driver remember our port object, and us it */
portNumber = MINOR(tty->device) - serial->minor;
port = &serial->port[portNumber];
- port->number = portNumber;
- port->serial = serial;
- port->magic = USB_SERIAL_PORT_MAGIC;
-
- /* make the tty driver remember our port object, and us it */
tty->driver_data = port;
port->tty = tty;
@@ -996,236 +1003,248 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum)
int num_bulk_in = 0;
int num_bulk_out = 0;
int num_ports;
+ int max_endpoints;
- /* loop through our list of known serial converters, and see if this device matches */
- device_num = 0;
- while (usb_serial_devices[device_num] != NULL) {
+ /* loop through our list of known serial converters, and see if this
+ device matches. */
+ for (device_num = 0; usb_serial_devices[device_num]; device_num++) {
type = usb_serial_devices[device_num];
- dbg ("Looking at %s Vendor id=%.4x Product id=%.4x", type->name, *(type->idVendor), *(type->idProduct));
+ dbg ("Looking at %s Vendor id=%.4x Product id=%.4x",
+ type->name, *(type->idVendor), *(type->idProduct));
/* look at the device descriptor */
if ((dev->descriptor.idVendor == *(type->idVendor)) &&
(dev->descriptor.idProduct == *(type->idProduct))) {
+ dbg("descriptor matches");
+ break;
+ }
+ }
+ if (!usb_serial_devices[device_num]) {
+ /* no match */
+ dbg("none matched");
+ return(NULL);
+ }
- dbg("descriptor matches...looking at the endpoints");
-
- /* descriptor matches, let's try to find the endpoints needed */
- interrupt_pipe = bulk_in_pipe = bulk_out_pipe = HAS_NOT;
+ /* descriptor matches, let's find the endpoints needed */
+ interrupt_pipe = bulk_in_pipe = bulk_out_pipe = HAS_NOT;
- /* check out the endpoints */
- interface = &dev->actconfig->interface[ifnum].altsetting[0];
- for (i = 0; i < interface->bNumEndpoints; ++i) {
- endpoint = &interface->endpoint[i];
+ /* check out the endpoints */
+ interface = &dev->actconfig->interface[ifnum].altsetting[0];
+ for (i = 0; i < interface->bNumEndpoints; ++i) {
+ endpoint = &interface->endpoint[i];
- if ((endpoint->bEndpointAddress & 0x80) &&
- ((endpoint->bmAttributes & 3) == 0x02)) {
- /* we found a bulk in endpoint */
- dbg("found bulk in");
- bulk_in_pipe = HAS;
- bulk_in_endpoint[num_bulk_in] = endpoint;
- ++num_bulk_in;
- }
-
- if (((endpoint->bEndpointAddress & 0x80) == 0x00) &&
- ((endpoint->bmAttributes & 3) == 0x02)) {
- /* we found a bulk out endpoint */
- dbg("found bulk out");
- bulk_out_pipe = HAS;
- bulk_out_endpoint[num_bulk_out] = endpoint;
- ++num_bulk_out;
- }
-
- if ((endpoint->bEndpointAddress & 0x80) &&
- ((endpoint->bmAttributes & 3) == 0x03)) {
- /* we found a interrupt in endpoint */
- dbg("found interrupt in");
- interrupt_pipe = HAS;
- interrupt_in_endpoint[num_interrupt_in] = endpoint;
- ++num_interrupt_in;
- }
+ if ((endpoint->bEndpointAddress & 0x80) &&
+ ((endpoint->bmAttributes & 3) == 0x02)) {
+ /* we found a bulk in endpoint */
+ dbg("found bulk in");
+ bulk_in_pipe = HAS;
+ bulk_in_endpoint[num_bulk_in] = endpoint;
+ ++num_bulk_in;
+ }
- }
+ if (((endpoint->bEndpointAddress & 0x80) == 0x00) &&
+ ((endpoint->bmAttributes & 3) == 0x02)) {
+ /* we found a bulk out endpoint */
+ dbg("found bulk out");
+ bulk_out_pipe = HAS;
+ bulk_out_endpoint[num_bulk_out] = endpoint;
+ ++num_bulk_out;
+ }
+
+ if ((endpoint->bEndpointAddress & 0x80) &&
+ ((endpoint->bmAttributes & 3) == 0x03)) {
+ /* we found a interrupt in endpoint */
+ dbg("found interrupt in");
+ interrupt_pipe = HAS;
+ interrupt_in_endpoint[num_interrupt_in] = endpoint;
+ ++num_interrupt_in;
+ }
+ }
- /* verify that we found all of the endpoints that we need */
- if ((interrupt_pipe & type->needs_interrupt_in) &&
- (bulk_in_pipe & type->needs_bulk_in) &&
- (bulk_out_pipe & type->needs_bulk_out)) {
- /* found all that we need */
- MOD_INC_USE_COUNT;
- info("%s converter detected", type->name);
+ /* verify that we found all of the endpoints that we need */
+ if (!((interrupt_pipe & type->needs_interrupt_in) &&
+ (bulk_in_pipe & type->needs_bulk_in) &&
+ (bulk_out_pipe & type->needs_bulk_out))) {
+ /* nope, they don't match what we expected */
+ info("descriptors matched, but endpoints did not");
+ return NULL;
+ }
+
+ /* found all that we need */
+ MOD_INC_USE_COUNT;
+ info("%s converter detected", type->name);
#ifdef CONFIG_USB_SERIAL_GENERIC
- if (type == &generic_device)
- num_ports = num_bulk_out;
- else
-#endif
- num_ports = type->num_ports;
-
- serial = get_free_serial (num_ports, &minor);
- if (serial == NULL) {
- err("No more free serial devices");
- MOD_DEC_USE_COUNT;
- return NULL;
- }
-
- serial->dev = dev;
- serial->type = type;
- serial->minor = minor;
- serial->num_ports = num_ports;
- serial->num_bulk_in = num_bulk_in;
- serial->num_bulk_out = num_bulk_out;
- serial->num_interrupt_in = num_interrupt_in;
-
- /* initialize a tty_driver for this device */
- serial->tty_driver = usb_serial_tty_driver_init (serial);
- if (serial->tty_driver == NULL) {
- err("Can't create a tty_serial_driver");
- goto probe_error;
- }
-
- if (tty_register_driver (serial->tty_driver)) {
- err("failed to register tty driver");
- goto probe_error;
- }
-
- /* collect interrupt_in endpoints now, because
- the keyspan_pda startup function needs
- to know about them */
- for (i = 0; i < num_interrupt_in; ++i) {
- port = &serial->port[i];
- buffer_size = interrupt_in_endpoint[i]->wMaxPacketSize;
- port->interrupt_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
- if (!port->interrupt_in_buffer) {
- err("Couldn't allocate interrupt_in_buffer");
- goto probe_error;
- }
- port->interrupt_in_endpoint = interrupt_in_endpoint[i];
- }
-
- /* if this device type has a startup function, call it */
- if (type->startup) {
- if (type->startup (serial)) {
- goto probe_error;
- }
- }
-
- /* set up the endpoint information */
- for (i = 0; i < num_bulk_in; ++i) {
- port = &serial->port[i];
- port->read_urb = usb_alloc_urb (0);
- if (!port->read_urb) {
- err("No free urbs available");
- goto probe_error;
- }
- buffer_size = bulk_in_endpoint[i]->wMaxPacketSize;
- port->bulk_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
- if (!port->bulk_in_buffer) {
- err("Couldn't allocate bulk_in_buffer");
- goto probe_error;
- }
- if (serial->type->read_bulk_callback) {
- FILL_BULK_URB(port->read_urb, dev, usb_rcvbulkpipe (dev, bulk_in_endpoint[i]->bEndpointAddress),
- port->bulk_in_buffer, buffer_size, serial->type->read_bulk_callback, port);
- } else {
- FILL_BULK_URB(port->read_urb, dev, usb_rcvbulkpipe (dev, bulk_in_endpoint[i]->bEndpointAddress),
- port->bulk_in_buffer, buffer_size, generic_read_bulk_callback, port);
- }
- }
-
- for (i = 0; i < num_bulk_out; ++i) {
- port = &serial->port[i];
- port->write_urb = usb_alloc_urb(0);
- if (!port->write_urb) {
- err("No free urbs available");
- goto probe_error;
- }
- port->bulk_out_size = bulk_out_endpoint[i]->wMaxPacketSize;
- port->bulk_out_buffer = kmalloc (port->bulk_out_size, GFP_KERNEL);
- if (!port->bulk_out_buffer) {
- err("Couldn't allocate bulk_out_buffer");
- goto probe_error;
- }
- if (serial->type->write_bulk_callback) {
- FILL_BULK_URB(port->write_urb, dev, usb_sndbulkpipe (dev, bulk_out_endpoint[i]->bEndpointAddress),
- port->bulk_out_buffer, port->bulk_out_size, serial->type->write_bulk_callback, port);
- } else {
- FILL_BULK_URB(port->write_urb, dev, usb_sndbulkpipe (dev, bulk_out_endpoint[i]->bEndpointAddress),
- port->bulk_out_buffer, port->bulk_out_size, generic_write_bulk_callback, port);
- }
- }
-
-#if 0 /* use this code when WhiteHEAT is up and running */
- for (i = 0; i < num_interrupt_in; ++i) {
- port = &serial->port[i];
- port->control_urb = usb_alloc_urb(0);
- if (!port->control_urb) {
- err("No free urbs available");
- goto probe_error;
- }
- buffer_size = interrupt_in_endpoint[i]->wMaxPacketSize;
- port->interrupt_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
- if (!port->interrupt_in_buffer) {
- err("Couldn't allocate interrupt_in_buffer");
- goto probe_error;
- }
- FILL_INT_URB(port->control_urb, dev, usb_rcvintpipe (dev, interrupt_in_endpoint[i]->bEndpointAddress),
- port->interrupt_in_buffer, buffer_size, serial_control_irq,
- port, interrupt_in_endpoint[i]->bInterval);
- }
+ if (type == &generic_device) {
+ num_ports = num_bulk_out;
+ if (num_ports == 0) {
+ err("Generic device with no bulk out, not allowed.");
+ MOD_DEC_USE_COUNT;
+ return NULL;
+ }
+ } else
#endif
+ num_ports = type->num_ports;
- for (i = 0; i < serial->num_ports; ++i) {
- info("%s converter now attached to ttyUSB%d", type->name, serial->minor + i);
- }
+ serial = get_free_serial (num_ports, &minor);
+ if (serial == NULL) {
+ err("No more free serial devices");
+ MOD_DEC_USE_COUNT;
+ return NULL;
+ }
+
+ serial->dev = dev;
+ serial->type = type;
+ serial->minor = minor;
+ serial->num_ports = num_ports;
+ serial->num_bulk_in = num_bulk_in;
+ serial->num_bulk_out = num_bulk_out;
+ serial->num_interrupt_in = num_interrupt_in;
+
+ /* initialize a tty_driver for this device */
+ serial->tty_driver = usb_serial_tty_driver_init (serial);
+ if (serial->tty_driver == NULL) {
+ err("Can't create a tty_serial_driver");
+ goto probe_error;
+ }
- return serial;
- } else {
- info("descriptors matched, but endpoints did not");
- }
+ if (tty_register_driver (serial->tty_driver)) {
+ err("failed to register tty driver");
+ goto probe_error;
+ }
+
+ /* if this device type has a startup function, call it */
+ if (type->startup) {
+ if (type->startup (serial)) {
+ goto probe_error;
}
-
- /* look at the next type in our list */
- ++device_num;
}
-probe_error:
- if (serial) {
- for (i = 0; i < num_bulk_in; ++i) {
- port = &serial->port[i];
- if (port->read_urb)
- usb_free_urb (port->read_urb);
- if (serial->port[i].bulk_in_buffer[i])
- kfree (serial->port[i].bulk_in_buffer);
+ /* set up the endpoint information */
+ for (i = 0; i < num_bulk_in; ++i) {
+ endpoint = bulk_in_endpoint[i];
+ port = &serial->port[i];
+ port->read_urb = usb_alloc_urb (0);
+ if (!port->read_urb) {
+ err("No free urbs available");
+ goto probe_error;
}
- for (i = 0; i < num_bulk_out; ++i) {
- port = &serial->port[i];
- if (port->write_urb)
- usb_free_urb (port->write_urb);
- if (serial->port[i].bulk_out_buffer)
- kfree (serial->port[i].bulk_out_buffer);
+ buffer_size = endpoint->wMaxPacketSize;
+ port->bulk_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
+ if (!port->bulk_in_buffer) {
+ err("Couldn't allocate bulk_in_buffer");
+ goto probe_error;
}
- for (i = 0; i < num_interrupt_in; ++i) {
- port = &serial->port[i];
- if (port->control_urb)
- usb_free_urb (port->control_urb);
- if (serial->port[i].interrupt_in_buffer)
- kfree (serial->port[i].interrupt_in_buffer);
+ FILL_BULK_URB(port->read_urb, dev,
+ usb_rcvbulkpipe(dev, endpoint->bEndpointAddress),
+ port->bulk_in_buffer, buffer_size,
+ ((serial->type->read_bulk_callback) ?
+ serial->type->read_bulk_callback :
+ generic_read_bulk_callback),
+ port);
+ }
+
+ for (i = 0; i < num_bulk_out; ++i) {
+ endpoint = bulk_out_endpoint[i];
+ port = &serial->port[i];
+ port->write_urb = usb_alloc_urb(0);
+ if (!port->write_urb) {
+ err("No free urbs available");
+ goto probe_error;
}
-
- /* return the minor range that this device had */
- return_serial (serial);
+ buffer_size = endpoint->wMaxPacketSize;
+ port->bulk_out_size = buffer_size;
+ port->bulk_out_buffer = kmalloc (buffer_size, GFP_KERNEL);
+ if (!port->bulk_out_buffer) {
+ err("Couldn't allocate bulk_out_buffer");
+ goto probe_error;
+ }
+ FILL_BULK_URB(port->write_urb, dev,
+ usb_sndbulkpipe(dev, endpoint->bEndpointAddress),
+ port->bulk_out_buffer, buffer_size,
+ ((serial->type->write_bulk_callback) ?
+ serial->type->write_bulk_callback :
+ generic_write_bulk_callback),
+ port);
+ }
- /* if this device has a tty_driver, then unregister it and free it */
- if (serial->tty_driver) {
- tty_unregister_driver (serial->tty_driver);
- kfree (serial->tty_driver);
- serial->tty_driver = NULL;
+ for (i = 0; i < num_interrupt_in; ++i) {
+ endpoint = interrupt_in_endpoint[i];
+ port = &serial->port[i];
+ port->interrupt_in_urb = usb_alloc_urb(0);
+ if (!port->interrupt_in_urb) {
+ err("No free urbs available");
+ goto probe_error;
+ }
+ buffer_size = endpoint->wMaxPacketSize;
+ port->interrupt_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
+ if (!port->interrupt_in_buffer) {
+ err("Couldn't allocate interrupt_in_buffer");
+ goto probe_error;
}
+ FILL_INT_URB(port->interrupt_in_urb, dev,
+ usb_rcvintpipe(dev, endpoint->bEndpointAddress),
+ port->interrupt_in_buffer, buffer_size,
+ serial->type->read_int_callback,
+ port,
+ endpoint->bInterval);
+ }
- /* free up any memory that we allocated */
- kfree (serial);
- MOD_DEC_USE_COUNT;
+ /* initialize some parts of the port structures */
+ /* we don't use num_ports here cauz some devices have more endpoint pairs than ports */
+ max_endpoints = MAX(num_bulk_in, num_bulk_out);
+ max_endpoints = MAX(max_endpoints, num_interrupt_in);
+ for (i = 0; i < max_endpoints; ++i) {
+ port = &serial->port[i];
+ port->number = i;
+ port->serial = serial;
+ port->magic = USB_SERIAL_PORT_MAGIC;
+ }
+
+ for (i = 0; i < serial->num_ports; ++i) {
+ info("%s converter now attached to ttyUSB%d",
+ type->name, serial->minor + i);
+ }
+
+ return serial; /* success */
+
+
+probe_error:
+ for (i = 0; i < num_bulk_in; ++i) {
+ port = &serial->port[i];
+ if (port->read_urb)
+ usb_free_urb (port->read_urb);
+ if (port->bulk_in_buffer)
+ kfree (port->bulk_in_buffer);
+ }
+ for (i = 0; i < num_bulk_out; ++i) {
+ port = &serial->port[i];
+ if (port->write_urb)
+ usb_free_urb (port->write_urb);
+ if (port->bulk_out_buffer)
+ kfree (port->bulk_out_buffer);
+ }
+ for (i = 0; i < num_interrupt_in; ++i) {
+ port = &serial->port[i];
+ if (port->interrupt_in_urb)
+ usb_free_urb (port->interrupt_in_urb);
+ if (port->interrupt_in_buffer)
+ kfree (port->interrupt_in_buffer);
+ }
+
+ /* return the minor range that this device had */
+ return_serial (serial);
+
+ /* if this device has a tty_driver, then unregister it and free it */
+ if (serial->tty_driver) {
+ tty_unregister_driver (serial->tty_driver);
+ kfree (serial->tty_driver);
+ serial->tty_driver = NULL;
}
+
+ /* free up any memory that we allocated */
+ kfree (serial);
+ MOD_DEC_USE_COUNT;
return NULL;
}
@@ -1237,6 +1256,9 @@ static void usb_serial_disconnect(struct usb_device *dev, void *ptr)
int i;
if (serial) {
+ if (serial->type->shutdown)
+ serial->type->shutdown(serial);
+
for (i = 0; i < serial->num_ports; ++i)
serial->port[i].active = 0;
@@ -1260,9 +1282,9 @@ static void usb_serial_disconnect(struct usb_device *dev, void *ptr)
}
for (i = 0; i < serial->num_interrupt_in; ++i) {
port = &serial->port[i];
- if (port->control_urb) {
- usb_unlink_urb (port->control_urb);
- usb_free_urb (port->control_urb);
+ if (port->interrupt_in_urb) {
+ usb_unlink_urb (port->interrupt_in_urb);
+ usb_free_urb (port->interrupt_in_urb);
}
if (port->interrupt_in_buffer)
kfree (port->interrupt_in_buffer);
@@ -1295,18 +1317,32 @@ static void usb_serial_disconnect(struct usb_device *dev, void *ptr)
int usb_serial_init(void)
{
int i;
+ int something;
+ int result;
/* Initalize our global data */
for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
serial_table[i] = NULL;
}
+ /* tell the world what devices this driver currently supports */
+ something = 0;
+ for (i = 0; usb_serial_devices[i]; ++i) {
+ if (!strstr (usb_serial_devices[i]->name, "prerenumeration")) {
+ info ("USB Serial support registered for %s", usb_serial_devices[i]->name);
+ something = 1;
+ }
+ }
+ if (!something)
+ info ("USB Serial driver is not configured for any devices!");
+
/* register the USB driver */
- if (usb_register(&usb_serial_driver) < 0) {
+ result = usb_register(&usb_serial_driver);
+ if (result < 0) {
+ err("usb_register failed for the usb-serial driver. Error number %d", result);
return -1;
}
-
- info("support registered");
+
return 0;
}