With relation to the Openwrt with WL500GP-v2 test (BCM5354 chipset), I have
obtained a  BUG response. After the first secs of the test with usb-serial or
pl2303 with microcom, the system reboot.

I would like to  know if the problem is in the driver (usb-uhci, usb-serial)
or if is there some chipset inconsistency with the kernel?.

# Miscellaneous USB options

#

# CONFIG_USB_DEVICEFS is not set

# CONFIG_USB_BANDWIDTH is not set

#


# USB Host Controller Drivers

#

CONFIG_USB_EHCI_HCD=m

CONFIG_USB_UHCI=m

CONFIG_USB_UHCI_HIGH_BANDWIDTH=y

# CONFIG_USB_UHCI_ALT is not set

# CONFIG_USB_OHCI is not set

Find some diff files including the option.c (needing some corrections) GSM
driver adapted to the kernel 2.4 as follows:

diff -uNr --exclude='.*' --exclude='*.o' --exclude='*~'
a/drivers/usb/serial/Config.in drivers/usb/serial/Config.in
--- a/drivers/usb/serial/Config.in      2008-05-06 19:00:29.000000000 -0400
+++ b/drivers/usb/serial/Config.in      2008-05-19 18:29:25.000000000 -0400
@@ -8,6 +8,7 @@
 if [ "$CONFIG_USB_SERIAL" != "n" ]; then
    dep_bool '  USB Serial Converter verbose debug' CONFIG_USB_SERIAL_DEBUG
$CONFIG_USB_SERIAL
    dep_mbool '  USB Generic Serial Driver' CONFIG_USB_SERIAL_GENERIC
$CONFIG_USB_SERIAL
+   dep_tristate '  USB 3G MODEM' CONFIG_USB_SERIAL_OPTION $CONFIG_USB_SERIAL
    dep_tristate '  USB Belkin and Peracom Single Port Serial Driver'
CONFIG_USB_SERIAL_BELKIN $CONFIG_USB_SERIAL
    dep_tristate '  USB ConnectTech WhiteHEAT Serial Driver'
CONFIG_USB_SERIAL_WHITEHEAT $CONFIG_USB_SERIAL
    dep_tristate '  USB Digi International AccelePort USB Serial Driver'
CONFIG_USB_SERIAL_DIGI_ACCELEPORT $CONFIG_USB_SERIAL
diff -uNr --exclude='.*' --exclude='*.o' --exclude='*~'
a/drivers/usb/serial/Makefile drivers/usb/serial/Makefile
--- a/drivers/usb/serial/Makefile       2008-05-06 19:00:29.000000000 -0400
+++ b/drivers/usb/serial/Makefile       2008-05-22 14:29:13.000000000 -0400
@@ -26,7 +26,7 @@
 obj-$(CONFIG_USB_SERIAL_IR)                    += ir-usb.o
 obj-$(CONFIG_USB_SERIAL_KLSI)                  += kl5kusb105.o
 obj-$(CONFIG_USB_SERIAL_KOBIL_SCT)             += kobil_sct.o
-
+obj-$(CONFIG_USB_SERIAL_OPTION)                 += option.o
 # Objects that export symbols.
 export-objs    := usbserial.o

diff -uNr --exclude='.*' --exclude='*.o' --exclude='*~'
a/drivers/usb/serial/option.c drivers/usb/serial/option.c
--- a/drivers/usb/serial/option.c       1969-12-31 19:00:00.000000000 -0500
+++ b/drivers/usb/serial/option.c       2008-05-22 14:22:06.000000000 -0400
@@ -0,0 +1,840 @@
+/*
+  USB Driver for GSM modems
+
+  Copyright (C) 2005  Matthias Urlichs <[EMAIL PROTECTED]>
+
+  This driver is free software; you can redistribute it and/or modify
+  it under the terms of Version 2 of the GNU General Public License as
+  published by the Free Software Foundation.
+
+  Portions copied from the Keyspan driver by Hugh Blemings <[EMAIL PROTECTED]>
+
+  History: see the git log.
+
+  Work sponsored by: Sigos GmbH, Germany <[EMAIL PROTECTED]>
+
+  This driver exists because the "normal" serial driver doesn't work too well
+  with GSM modems. Issues:
+  - data loss -- one single Receive URB is not nearly enough
+  - nonstandard flow (Option devices) control
+  - controlling the baud rate doesn't make sense
+
+  This driver is named "option" because the most common device it's
+  used for is a PC-Card (with an internal OHCI-USB interface, behind
+  which the GSM interface sits), made by Option Inc.
+
+  Some of the "one port" devices actually exhibit multiple USB instances
+  on the USB bus. This is not a bug, these ports are used for different
+  device features.
+
+  Kernel 2.4.36.4 (2008), Felipe Maya <[EMAIL PROTECTED]>
+
+*/
+
+#define DRIVER_VERSION "v0.7.1"
+#define DRIVER_AUTHOR "Matthias Urlichs <[EMAIL PROTECTED]>"
+#define DRIVER_DESC "USB Driver for GSM modems"
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/module.h>
+#include <linux/bitops.h>
+#include <linux/usb.h>
+#include <linux/spinlock.h>
+#include <asm/uaccess.h>
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+       static int debug = 1;
+#else
+       static int debug;
+#endif
+
+#include "usb-serial.h"
+
+
+
+/* Function prototypes */
+static int  option_open(struct usb_serial_port *port, struct file *filp);
+static void option_close(struct usb_serial_port *port, struct file *filp);
+static int  option_startup(struct usb_serial *serial);
+static void option_shutdown(struct usb_serial *serial);
+static void option_rx_throttle(struct usb_serial_port *port);
+static void option_rx_unthrottle(struct usb_serial_port *port);
+static int  option_write_room(struct usb_serial_port *port);
+
+static void option_instat_callback(struct urb *urb);
+
+static int option_write(struct usb_serial_port *port, int from_user,
+                       const unsigned char *buf, int count);
+
+static int  option_chars_in_buffer(struct usb_serial_port *port);
+static int  option_ioctl(struct usb_serial_port *port, struct file *file,
+                       unsigned int cmd, unsigned long arg);
+static void option_set_termios(struct usb_serial_port *port,
+                               struct termios *old);
+static void option_break_ctl(struct usb_serial_port *port, int break_state);
+static int  option_tiocmget(struct usb_serial_port *port, struct file *file);
+static int  option_tiocmset(struct usb_serial_port *port, struct file *file,
+                               unsigned int set, unsigned int clear);
+static int  option_send_setup(struct usb_serial_port *port);
+
+/* Vendor and product IDs */
+#define HUAWEI_VENDOR_ID                       0x12D1
+#define HUAWEI_PRODUCT_E226                    0x1003
+
+#define ZTE_VENDOR_ID                          0x19D2
+#define ZTE_PRODUCT_MF622                      0x0001
+
+
+#define N_IN_URB 4
+#define N_OUT_URB 1
+#define IN_BUFLEN 4096
+#define OUT_BUFLEN 128
+
+#define UART_STATE                     0x08
+#define UART_STATE_TRANSIENT_MASK      0x74
+#define UART_DCD                       0x01
+#define UART_DSR                       0x02
+#define UART_BREAK_ERROR               0x04
+#define UART_RING                      0x08
+#define UART_FRAME_ERROR               0x10
+#define UART_PARITY_ERROR              0x20
+#define UART_OVERRUN_ERROR             0x40
+#define UART_CTS                       0x80
+
+struct option_port_private {
+       spinlock_t lock;
+       u8 line_status;
+       wait_queue_head_t delta_msr_wait;
+       /* Input endpoints and buffer for this port */
+       struct urb *in_urbs[N_IN_URB];
+       char in_buffer[N_IN_URB][IN_BUFLEN];
+       /* Output endpoints and buffer for this port */
+       struct urb *out_urbs[N_OUT_URB];
+       char out_buffer[N_OUT_URB][OUT_BUFLEN];
+       unsigned long out_busy;         /* Bit vector of URBs in use */
+
+       /* Settings for the port */
+       int rts_state;  /* Handshaking pins (outputs) */
+       int dtr_state;
+       int cts_state;  /* Handshaking pins (inputs) */
+       int dsr_state;
+       int dcd_state;
+       int ri_state;
+
+       unsigned long tx_start_time[N_OUT_URB];
+};
+
+static struct usb_device_id id_table [] = {
+//     { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_ID) },
+//     { USB_DEVICE(ZTExx_VENDOR_ID, ZTExx_PRODUCT_ID) },
+       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E226,
0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF622, 0xff,
0xff, 0xff) },
+       { }                                     /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+
+static void option_rx_throttle(struct usb_serial_port *port)
+{
+       dbg("%s", __FUNCTION__);
+}
+
+static void option_rx_unthrottle(struct usb_serial_port *port)
+{
+       dbg("%s", __FUNCTION__);
+}
+
+static void option_set_termios(struct usb_serial_port *port,
+                              struct termios *old)
+{
+       dbg("%s", __FUNCTION__);
+
+       option_send_setup(port);
+}
+
+static int option_tiocmget(struct usb_serial_port *port, struct file *file)
+{
+       unsigned int value;
+       struct option_port_private *portdata;
+
+       portdata = usb_get_serial_port_data(port);
+
+       value = ((portdata->rts_state) ? TIOCM_RTS : 0) |
+               ((portdata->dtr_state) ? TIOCM_DTR : 0) |
+               ((portdata->cts_state) ? TIOCM_CTS : 0) |
+               ((portdata->dsr_state) ? TIOCM_DSR : 0) |
+               ((portdata->dcd_state) ? TIOCM_CAR : 0) |
+               ((portdata->ri_state) ? TIOCM_RNG : 0);
+
+       return value;
+}
+
+static int option_tiocmset(struct usb_serial_port *port, struct file *file,
+                          unsigned int set, unsigned int clear)
+{
+       struct option_port_private *portdata;
+
+       portdata = usb_get_serial_port_data(port);
+
+       if (set & TIOCM_RTS)
+               portdata->rts_state = 1;
+       if (set & TIOCM_DTR)
+               portdata->dtr_state = 1;
+
+       if (clear & TIOCM_RTS)
+               portdata->rts_state = 0;
+       if (clear & TIOCM_DTR)
+               portdata->dtr_state = 0;
+
+       return option_send_setup(port);
+}
+
+static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
+{
+       struct option_port_private *portdata = usb_get_serial_port_data(port);
+       unsigned long flags;
+       unsigned int prevstatus;
+       unsigned int status;
+       unsigned int changed;
+
+       spin_lock_irqsave(&portdata->lock, flags);
+       prevstatus = portdata->line_status;
+       spin_unlock_irqrestore(&portdata->lock, flags);
+
+       while (1) {
+               interruptible_sleep_on(&portdata->delta_msr_wait);
+               /* see if a signal did it */
+               if (signal_pending(current))
+                       return -ERESTARTSYS;
+
+               spin_lock_irqsave(&portdata->lock, flags);
+               status = portdata->line_status;
+               spin_unlock_irqrestore(&portdata->lock, flags);
+
+               changed=prevstatus^status;
+
+               if (((arg & TIOCM_RNG) && (changed & UART_RING)) ||
+                   ((arg & TIOCM_DSR) && (changed & UART_DSR)) ||
+                   ((arg & TIOCM_CD)  && (changed & UART_DCD)) ||
+                   ((arg & TIOCM_CTS) && (changed & UART_CTS)) ) {
+                       return 0;
+               }
+               prevstatus = status;
+       }
+       /* NOTREACHED */
+       return 0;
+}
+
+static int option_ioctl(struct usb_serial_port *port, struct file *file,
+                       unsigned int cmd, unsigned long arg)
+{
+       int value;
+       dbg("%s (%d) cmd = 0x%04x", __FUNCTION__, port->number, cmd);
+
+       switch (cmd) {
+               case TIOCMGET:
+                       dbg("%s (%d) TIOCMGET", __FUNCTION__, port->number);
+                       value = option_tiocmget(port, file);
+                       if (copy_to_user((unsigned int *)arg, &value, 
sizeof(int)))
+                               return -EFAULT;
+                       return 0;
+               case TIOCMSET:
+                       dbg("%s (%d) TIOCMSET", __FUNCTION__,  port->number);
+                       if (copy_from_user(&value, (unsigned int *)arg, 
sizeof(int)))
+                               return -EFAULT;
+                       /* turn off RTS and DTR and then only turn
+                          on what was asked to */
+                       return option_tiocmset(port, file, value, 
value^(TIOCM_RTS|TIOCM_DTR));
+               case TIOCMIWAIT:
+                       dbg("%s (%d) TIOCMIWAIT", __FUNCTION__,  port->number);
+                       return wait_modem_info(port, arg);
+               default:
+                       dbg("%s not supported = 0x%04x", __FUNCTION__, cmd);
+                       break;
+       }
+       return -ENOIOCTLCMD;
+}
+
+static void option_break_ctl(struct usb_serial_port *port, int break_state)
+{
+       dbg("%s", __FUNCTION__);
+}
+
+static int option_write(struct usb_serial_port *port, int from_user,
+                       const unsigned char *buf, int count)
+{
+       struct option_port_private *portdata;
+       int i;
+       int left, todo;
+       struct urb *this_urb = NULL; /* spurious */
+       int err;
+
+       portdata = usb_get_serial_port_data(port);
+
+       dbg("%s: write (%d chars)", __FUNCTION__, count);
+
+       i = 0;
+       left = count;
+       for (i=0; left > 0 && i < N_OUT_URB; i++) {
+               todo = left;
+               if (todo > OUT_BUFLEN)
+                       todo = OUT_BUFLEN;
+
+               this_urb = portdata->out_urbs[i];
+               if (test_and_set_bit(i, &portdata->out_busy)) {
+                       if (time_before(jiffies,
+                                       portdata->tx_start_time[i] + 10 * HZ))
+                               continue;
+                       usb_unlink_urb(this_urb);
+                       continue;
+               }
+               if (this_urb->status != 0)
+                       dbg("usb_write %p failed (err=%d)",
+                               this_urb, this_urb->status);
+
+               dbg("%s: endpoint %d buf %d", __FUNCTION__,
+                       usb_pipeendpoint(this_urb->pipe), i);
+
+               /* send the data */
+               memcpy (this_urb->transfer_buffer, buf, todo);
+               this_urb->transfer_buffer_length = todo;
+
+               this_urb->dev = port->serial->dev;
+               err = usb_submit_urb(this_urb);
+               if (err) {
+                       dbg("usb_submit_urb %p (write bulk) failed "
+                               "(%d, has %d)", this_urb,
+                               err, this_urb->status);
+                       clear_bit(i, &portdata->out_busy);
+                       continue;
+               }
+               portdata->tx_start_time[i] = jiffies;
+               buf += todo;
+               left -= todo;
+       }
+
+       count -= left;
+       dbg("%s: wrote (did %d)", __FUNCTION__, count);
+       return count;
+}
+
+static void option_indat_callback(struct urb *urb)
+{
+       int i, err;
+       int endpoint;
+       struct usb_serial_port *port;
+       struct option_port_private *portdata = usb_get_serial_port_data(port);
+       struct tty_struct *tty;
+       unsigned char *data = urb->transfer_buffer;
+       unsigned long flags;
+       int status = urb->status;
+       char tty_flag;
+       u8 line_status;
+
+       dbg("%s: %p", __FUNCTION__, urb);
+
+       endpoint = usb_pipeendpoint(urb->pipe);
+       port = (struct usb_serial_port *) urb->context;
+
+       switch (status) {
+       case 0:
+               /* success */
+               break;
+       case -ECONNRESET:
+       case -ENOENT:
+       case -ESHUTDOWN:
+               /* this urb is terminated, clean up */
+               dbg("%s - urb shutting down with status: %d", __FUNCTION__,
+                   status);
+               return;
+       default:
+               dbg("%s - nonzero urb status received: %d", __FUNCTION__,
+                   status);
+               return;
+       }
+
+       /* get tty_flag from status */
+       tty_flag = TTY_NORMAL;
+
+       spin_lock_irqsave(&portdata->lock, flags);
+       line_status = portdata->line_status;
+       portdata->line_status &= ~UART_STATE_TRANSIENT_MASK;
+       spin_unlock_irqrestore(&portdata->lock, flags);
+       wake_up_interruptible(&portdata->delta_msr_wait);
+
+       /* break takes precedence over parity, */
+       /* which takes precedence over framing errors */
+       if (line_status & UART_BREAK_ERROR )
+               tty_flag = TTY_BREAK;
+       else if (line_status & UART_PARITY_ERROR)
+               tty_flag = TTY_PARITY;
+       else if (line_status & UART_FRAME_ERROR)
+               tty_flag = TTY_FRAME;
+       dbg("%s - tty_flag = %d", __FUNCTION__, tty_flag);
+
+       tty = port->tty;
+       if (tty && urb->actual_length) {
+               /* overrun is special, not associated with a char */
+               if (line_status & UART_OVERRUN_ERROR)
+                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+
+               for (i = 0; i < urb->actual_length; ++i) {
+                       if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+                               tty_flip_buffer_push(tty);
+                       tty_insert_flip_char(tty, data[i], tty_flag);
+               }
+               tty_flip_buffer_push(tty);
+       }
+
+       /* Resubmit urb so we continue receiving */
+       if (port->open_count && status != -ESHUTDOWN) {
+               err = usb_submit_urb(urb);
+               if (err)
+                       printk(KERN_ERR "%s: resubmit read urb failed. "
+                               "(%d)", __FUNCTION__, err);
+       }
+
+       if(UART_STATE+1 < urb->actual_length)
+               return;
+
+       //update line status
+       /* Save off the uart status for others to look at */
+       spin_lock_irqsave(&portdata->lock, flags);
+       portdata->line_status = data[UART_STATE];
+       spin_unlock_irqrestore(&portdata->lock, flags);
+       wake_up_interruptible(&portdata->delta_msr_wait);
+
+       return;
+}
+
+static void option_outdat_callback(struct urb *urb)
+{
+       struct usb_serial_port *port;
+       struct option_port_private *portdata;
+       int i;
+
+       dbg("%s", __FUNCTION__);
+
+       port = (struct usb_serial_port *) urb->context;
+       //FIXME
+       //schedule_work(&port->work);
+
+       portdata = usb_get_serial_port_data(port);
+       for (i = 0; i < N_OUT_URB; ++i) {
+               if (portdata->out_urbs[i] == urb) {
+                       smp_mb__before_clear_bit();
+                       clear_bit(i, &portdata->out_busy);
+                       break;
+               }
+       }
+}
+
+static void option_instat_callback(struct urb *urb)
+{
+       int err;
+       int status = urb->status;
+       struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
+       struct option_port_private *portdata = usb_get_serial_port_data(port);
+       struct usb_serial *serial = port->serial;
+
+       dbg("%s", __FUNCTION__);
+       dbg("%s: urb %p port %p has data %p", __FUNCTION__,urb,port,portdata);
+
+       if (status == 0) {
+               struct usb_ctrlrequest *req_pkt =
+                               (struct usb_ctrlrequest *)urb->transfer_buffer;
+
+               if (!req_pkt) {
+                       dbg("%s: NULL req_pkt\n", __FUNCTION__);
+                       return;
+               }
+               if ((req_pkt->bRequestType == 0xA1) &&
+                               (req_pkt->bRequest == 0x20)) {
+                       int old_dcd_state;
+                       unsigned char signals = *((unsigned char *)
+                                       urb->transfer_buffer +
+                                       sizeof(struct usb_ctrlrequest));
+
+                       dbg("%s: signal x%x", __FUNCTION__, signals);
+
+                       old_dcd_state = portdata->dcd_state;
+                       portdata->cts_state = 1;
+                       portdata->dcd_state = ((signals & 0x01) ? 1 : 0);
+                       portdata->dsr_state = ((signals & 0x02) ? 1 : 0);
+                       portdata->ri_state = ((signals & 0x08) ? 1 : 0);
+
+                       if (port->tty && !C_CLOCAL(port->tty) &&
+                                       old_dcd_state && !portdata->dcd_state)
+                               tty_hangup(port->tty);
+               } else {
+                       dbg("%s: type %x req %x", __FUNCTION__,
+                               req_pkt->bRequestType,req_pkt->bRequest);
+               }
+       } else
+               dbg("%s: error %d", __FUNCTION__, status);
+
+       /* Resubmit urb so we continue receiving IRQ data */
+       if (status != -ESHUTDOWN) {
+               urb->dev = serial->dev;
+               err = usb_submit_urb(urb);
+               if (err)
+                       dbg("%s: resubmit intr urb failed. (%d)",
+                               __FUNCTION__, err);
+       }
+
+}
+
+static int option_write_room(struct usb_serial_port *port)
+{
+       struct option_port_private *portdata;
+       int i;
+       int data_len = 0;
+       struct urb *this_urb;
+
+       portdata = usb_get_serial_port_data(port);
+
+       for (i=0; i < N_OUT_URB; i++) {
+               this_urb = portdata->out_urbs[i];
+               if (this_urb && !test_bit(i, &portdata->out_busy))
+                       data_len += OUT_BUFLEN;
+       }
+
+       dbg("%s: %d", __FUNCTION__, data_len);
+       return data_len;
+}
+
+static int option_chars_in_buffer(struct usb_serial_port *port)
+{
+       struct option_port_private *portdata;
+       int i;
+       int data_len = 0;
+       struct urb *this_urb;
+
+       portdata = usb_get_serial_port_data(port);
+
+       for (i=0; i < N_OUT_URB; i++) {
+               this_urb = portdata->out_urbs[i];
+               if (this_urb && test_bit(i, &portdata->out_busy))
+                       data_len += this_urb->transfer_buffer_length;
+       }
+       dbg("%s: %d", __FUNCTION__, data_len);
+       return data_len;
+}
+
+static int option_open(struct usb_serial_port *port, struct file *filp)
+{
+       struct option_port_private *portdata;
+       struct usb_serial *serial = port->serial;
+       int i, err;
+       struct urb *urb;
+
+       portdata = usb_get_serial_port_data(port);
+
+       dbg("%s", __FUNCTION__);
+
+       /* Set some sane defaults */
+       portdata->rts_state = 1;
+       portdata->dtr_state = 1;
+
+       /* Reset low level data toggle and start reading from endpoints */
+       for (i = 0; i < N_IN_URB; i++) {
+               urb = portdata->in_urbs[i];
+               if (! urb)
+                       continue;
+               if (urb->dev != serial->dev) {
+                       dbg("%s: dev %p != %p", __FUNCTION__,
+                               urb->dev, serial->dev);
+                       continue;
+               }
+
+               /*
+                * make sure endpoint data toggle is synchronized with the
+                * device
+                */
+               usb_clear_halt(urb->dev, urb->pipe);
+
+               err = usb_submit_urb(urb);
+               if (err) {
+                       dbg("%s: submit urb %d failed (%d) %d",
+                               __FUNCTION__, i, err,
+                               urb->transfer_buffer_length);
+               }
+       }
+
+       /* Reset low level data toggle on out endpoints */
+       for (i = 0; i < N_OUT_URB; i++) {
+               urb = portdata->out_urbs[i];
+               if (! urb)
+                       continue;
+               urb->dev = serial->dev;
+               /* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+                               usb_pipeout(urb->pipe), 0); */
+       }
+
+       port->tty->low_latency = 1;
+
+       option_send_setup(port);
+
+       return (0);
+}
+
+static void option_close(struct usb_serial_port *port, struct file *filp)
+{
+       int i, result;
+       struct usb_serial *serial = port->serial;
+       struct option_port_private *portdata;
+
+       dbg("%s", __FUNCTION__);
+       portdata = usb_get_serial_port_data(port);
+
+       portdata->rts_state = 0;
+       portdata->dtr_state = 0;
+
+       if (serial->dev) {
+               option_send_setup(port);
+               dbg("%s - shutting down urbs", __FUNCTION__);
+
+               /* Stop reading/writing urbs */
+               for (i = 0; i < N_IN_URB; i++){
+                       result = usb_unlink_urb (portdata->in_urbs[i]);
+                       if (result)
+                               dbg("%s - usb_unlink_urb (in_urbs)"
+                                       " failed with reason: %d", __FUNCTION__,
+                                       result);
+               }
+               for (i = 0; i < N_OUT_URB; i++){
+                       result = usb_unlink_urb (portdata->out_urbs[i]);
+                       if (result)
+                               dbg("%s - usb_unlink_urb (out_urbs)"
+                                       " failed with reason: %d", __FUNCTION__,
+                                       result);
+               }
+       }
+       port->tty = NULL;
+}
+
+//Helper functions used by option_setup_urbs
+static struct urb *option_setup_urb(struct usb_serial *serial, int endpoint,
+               int dir, void *ctx, char *buf, int len,
+               void (*callback)(struct urb *))
+{
+       struct urb *urb;
+
+       if (endpoint == -1)
+               return NULL;            // endpoint not needed
+
+       urb = usb_alloc_urb(0);         // No ISO
+       if (urb == NULL) {
+               dbg("%s: alloc for endpoint %d failed.", __FUNCTION__, 
endpoint);
+               return NULL;
+       }
+
+               // Fill URB using supplied data.
+       usb_fill_bulk_urb(urb, serial->dev,
+                     usb_sndbulkpipe(serial->dev, endpoint) | dir,
+                     buf, len, callback, ctx);
+
+       return urb;
+}
+
+/* Setup urbs */
+static void option_setup_urbs(struct usb_serial *serial)
+{
+       int i,j;
+       struct option_port_private *portdata;
+
+       dbg("%s", __FUNCTION__);
+
+       for (i = 0; i < serial->num_ports; i++) {
+               portdata = usb_get_serial_port_data(&serial->port[i]);
+
+       /* Do indat endpoints first */
+               for (j = 0; j < N_IN_URB; ++j) {
+                       portdata->in_urbs[j] = option_setup_urb (serial,
+                       (serial->port[i]).bulk_in_endpointAddress, USB_DIR_IN,
&serial->port[i],
+                       portdata->in_buffer[j], IN_BUFLEN, 
option_indat_callback);
+               }
+
+               /* outdat endpoints */
+               for (j = 0; j < N_OUT_URB; ++j) {
+                       portdata->out_urbs[j] = option_setup_urb (serial,
+                       (serial->port[i]).bulk_out_endpointAddress, USB_DIR_OUT,
&serial->port[i],
+                       portdata->out_buffer[j], OUT_BUFLEN,
option_outdat_callback);
+               }
+       }
+}
+
+
+static int option_send_setup(struct usb_serial_port *port)
+{
+       struct usb_serial *serial = port->serial;
+       struct option_port_private *portdata;
+
+       dbg("%s", __FUNCTION__);
+
+       if (port->number != 0)
+               return 0;
+
+       portdata = usb_get_serial_port_data(port);
+
+       if (port->tty) {
+               int val = 0;
+               if (portdata->dtr_state)
+                       val |= 0x01;
+               if (portdata->rts_state)
+                       val |= 0x02;
+
+               return usb_control_msg(serial->dev,
+                               usb_rcvctrlpipe(serial->dev, 0),
+                               0x22,0x21,val,0,NULL,0,USB_CTRL_SET_TIMEOUT);
+       }
+
+       return 0;
+}
+
+static int option_startup(struct usb_serial *serial)
+{
+       int i, err;
+       struct option_port_private *portdata;
+
+       dbg("%s", __FUNCTION__);
+
+       // Now setup per port private data
+       for (i = 0; i < serial->num_ports; i++) {
+               portdata = kmalloc(sizeof(*portdata), GFP_KERNEL);
+               if (!portdata) {
+                       dbg("%s: kmalloc for option_port_private (%d) failed!.",
+                                       __FUNCTION__, i);
+                       return (1);
+               }
+
+               init_waitqueue_head(&portdata->delta_msr_wait);
+               usb_set_serial_port_data(&serial->port[i], portdata);
+
+               if (! (serial->port[i]).interrupt_in_urb)
+                       continue;
+               err = usb_submit_urb((serial->port[i]).interrupt_in_urb);
+               if (err)
+                       dbg("%s: submit irq_in urb failed %d",
+                               __FUNCTION__, err);
+       }
+
+       option_setup_urbs(serial);
+
+       return (0);
+}
+
+static void option_shutdown(struct usb_serial *serial)
+{
+       int i, j;
+       struct option_port_private *portdata;
+
+       dbg("%s", __FUNCTION__);
+
+       /* Stop reading/writing urbs */
+       for (i = 0; i < serial->num_ports; ++i) {
+               portdata = usb_get_serial_port_data(&serial->port[i]);
+               for (j = 0; j < N_IN_URB; j++)
+                       usb_unlink_urb (portdata->in_urbs[j]);
+               for (j = 0; j < N_OUT_URB; j++)
+                       usb_unlink_urb (portdata->out_urbs[j]);
+       }
+
+       /* Now free them */
+       for (i = 0; i < serial->num_ports; ++i) {
+               portdata = usb_get_serial_port_data(&serial->port[i]);
+
+               for (j = 0; j < N_IN_URB; j++) {
+                       if (portdata->in_urbs[j]) {
+                               usb_free_urb(portdata->in_urbs[j]);
+                               portdata->in_urbs[j] = NULL;
+                       }
+               }
+               for (j = 0; j < N_OUT_URB; j++) {
+                       if (portdata->out_urbs[j]) {
+                               usb_free_urb(portdata->out_urbs[j]);
+                               portdata->out_urbs[j] = NULL;
+                       }
+               }
+       }
+
+       /* Now free per port private data */
+       for (i = 0; i < serial->num_ports; i++) {
+               kfree(usb_get_serial_port_data(&serial->port[i]));
+       }
+}
+
+static struct usb_driver option_driver = {
+       .name =                 "option",
+       .probe =                usb_serial_probe,
+       .disconnect =           usb_serial_disconnect,
+       .id_table =             id_table,
+};
+
+static struct usb_serial_device_type option_device = {
+       .owner =                THIS_MODULE,
+       .name =                 "GSM modem (1-port)",
+       .id_table =             id_table,
+       .num_interrupt_in =     NUM_DONT_CARE,//1
+       .num_bulk_in =          NUM_DONT_CARE,//1
+       .num_bulk_out =         NUM_DONT_CARE,//1,
+       .num_ports =            1,
+       .open =                 option_open,
+       .close =                option_close,
+       .write =                option_write,
+       .ioctl =                option_ioctl,
+       .break_ctl =            option_break_ctl,
+       .set_termios =          option_set_termios,
+// 2.6 .tiocmget =             option_tiocmget,
+// 2.6 .tiocmset =             option_tiocmset,
+       .throttle =             option_rx_throttle,
+       .unthrottle =           option_rx_unthrottle,
+       .read_int_callback =    option_instat_callback,
+       .write_room =           option_write_room,
+       .chars_in_buffer =      option_chars_in_buffer,
+       .startup =              option_startup,
+       .shutdown =             option_shutdown,
+};
+
+static int __init option_init(void)
+{
+       int retval=0;
+       retval = usb_serial_register(&option_device);
+       if (retval)
+               goto failed_1port_device_register;
+       retval = usb_register(&option_driver);
+       if (retval)
+               goto failed_driver_register;
+
+       info(DRIVER_DESC ": " DRIVER_VERSION);
+
+       return 0;
+
+failed_driver_register:
+       usb_serial_deregister (&option_device);
+failed_1port_device_register:
+       return retval;
+}
+
+static void __exit option_exit(void)
+{
+       usb_deregister (&option_driver);
+       usb_serial_deregister (&option_device);
+}
+
+module_init(option_init);
+module_exit(option_exit);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+
diff -uNr --exclude='.*' --exclude='*.o' --exclude='*~'
a/drivers/usb/serial/pl2303.c drivers/usb/serial/pl2303.c
--- a/drivers/usb/serial/pl2303.c       2008-05-06 19:00:29.000000000 -0400
+++ b/drivers/usb/serial/pl2303.c       2008-05-22 15:33:28.000000000 -0400
@@ -67,10 +67,10 @@
  */
 #define DRIVER_DESC "Prolific PL2303 USB to serial adaptor driver"

-#define PL2303_CLOSING_WAIT    (30*HZ)
+#define PL2303_CLOSING_WAIT    (300*HZ)

-#define PL2303_BUF_SIZE                1024
-#define PL2303_TMP_BUF_SIZE    1024
+#define PL2303_BUF_SIZE                4096
+#define PL2303_TMP_BUF_SIZE    4096

 struct pl2303_buf {
        unsigned int    buf_size;
@@ -115,6 +115,8 @@
        { USB_DEVICE(DATAPILOT_U2_VENDOR_ID, DATAPILOT_U2_PRODUCT_ID) },
        { USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) },
        { USB_DEVICE(ALCOR_VENDOR_ID, ALCOR_PRODUCT_ID) },
+       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_ID, 
0xff,
0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTExx_VENDOR_ID,  ZTExx_PRODUCT_ID, 
0xff,
0xff, 0xff) },
        { USB_DEVICE(WS002IN_VENDOR_ID, WS002IN_PRODUCT_ID) },
        { USB_DEVICE(COREGA_VENDOR_ID, COREGA_PRODUCT_ID) },
        { USB_DEVICE(HL340_VENDOR_ID, HL340_PRODUCT_ID) },
@@ -1081,7 +1083,7 @@
        u8 line_status;
        char tty_flag;

-       dbg("%s - port %d", __FUNCTION__, port->number);
+       //dbg("%s - port %d", __FUNCTION__, port->number);

        if (!get_usb_serial (port, __FUNCTION__)) {
                dbg("%s - bad serial pointer, exiting", __FUNCTION__);
@@ -1164,7 +1166,7 @@

        if (port_paranoia_check (port, __FUNCTION__))
                return;
-
+
        dbg("%s - port %d", __FUNCTION__, port->number);

        switch (status) {
@@ -1204,11 +1206,11 @@
 /* All of the device info needed for the PL2303 SIO serial converter */
 static struct usb_serial_device_type pl2303_device = {
        .owner =                THIS_MODULE,
-       .name =                 "PL-2303",
+       .name =                 "PL-2303 HSDPA modem",
        .id_table =             id_table,
        .num_interrupt_in =     NUM_DONT_CARE,
-       .num_bulk_in =          1,
-       .num_bulk_out =         1,
+       .num_bulk_in =          NUM_DONT_CARE,
+       .num_bulk_out =         NUM_DONT_CARE,
        .num_ports =            1,
        .open =                 pl2303_open,
        .close =                pl2303_close,
diff -uNr --exclude='.*' --exclude='*.o' --exclude='*~'
a/drivers/usb/serial/pl2303.h drivers/usb/serial/pl2303.h
--- a/drivers/usb/serial/pl2303.h       2008-05-06 19:00:29.000000000 -0400
+++ b/drivers/usb/serial/pl2303.h       2008-05-19 08:20:24.000000000 -0400
@@ -112,3 +112,13 @@
 /* Y.C. Cable U.S.A., Inc - USB to RS-232 */
 #define YCCABLE_VENDOR_ID      0x05ad
 #define YCCABLE_PRODUCT_ID     0x0fba
+
+/* Huawei E226 HSDPA card (ID: 12d1:1003) --fmay*/
+#define HUAWEI_VENDOR_ID        0x12d1
+#define HUAWEI_PRODUCT_ID       0x1003
+
+/*ZTExx HSDPA card (0x19d2:0x0001) --fmay*/
+#define ZTExx_VENDOR_ID        0x19d2
+#define ZTExx_PRODUCT_ID       0x0001
+
+
diff -uNr --exclude='.*' --exclude='*.o' --exclude='*~'
a/drivers/usb/serial/usbserial.c drivers/usb/serial/usbserial.c
--- a/drivers/usb/serial/usbserial.c    2008-05-19 11:19:57.000000000 -0400
+++ drivers/usb/serial/usbserial.c      2008-05-21 16:35:48.000000000 -0400
@@ -333,7 +333,7 @@
 static __u16   product = 0xffff;
 static int     maxSize = 0;

-static struct usb_device_id generic_device_ids[10]; /* Initially all zeroes. */
+static struct usb_device_id generic_device_ids[11]; /* Initially all zeroes. */

 /* All of the device info needed for the Generic Serial Converter */
 static struct usb_serial_device_type generic_device = {
@@ -1558,11 +1558,18 @@
                        err("No free urbs available");
                        goto probe_error;
                }
+
 #ifdef CONFIG_USB_SERIAL_GENERIC
                buffer_size = (endpoint->wMaxPacketSize > maxSize) ?
endpoint->wMaxPacketSize : maxSize;
+               endpoint->wMaxPacketSize = buffer_size;
+               //HSDPA--fmay
+               buffer_size = ( (serial->vendor==0x12d1 && 
serial->product==0x1003) ||
+                               (serial->vendor==0x19d2 && 
serial->product==0x0001) )  ? 4096 :
buffer_size;
+               //---
 #else
                buffer_size = endpoint->wMaxPacketSize;
 #endif
+               printk("KERNEL DEBUG => USBSERIAL.O buffer_size = %d", 
buffer_size);
                port->bulk_in_endpointAddress = endpoint->bEndpointAddress;
                port->bulk_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
                if (!port->bulk_in_buffer) {
@@ -1864,6 +1871,14 @@
        generic_device_ids[7].idVendor = 0x1410;
        generic_device_ids[7].idProduct = 0x1430;
        generic_device_ids[7].match_flags = USB_DEVICE_ID_MATCH_VENDOR |
USB_DEVICE_ID_MATCH_PRODUCT;
+       /* Huawei E226 *////--fmay
+        generic_device_ids[8].idVendor = 0x12d1;
+        generic_device_ids[8].idProduct = 0x1003;
+        generic_device_ids[8].match_flags = USB_DEVICE_ID_MATCH_VENDOR |
USB_DEVICE_ID_MATCH_PRODUCT;
+       /* ZTExx MF622 *////--fmay
+       generic_device_ids[9].idVendor = 0x19d2;
+        generic_device_ids[9].idProduct = 0x0001;
+        generic_device_ids[9].match_flags = USB_DEVICE_ID_MATCH_VENDOR |
USB_DEVICE_ID_MATCH_PRODUCT;
        /* register our generic driver with ourselves */
        usb_serial_register (&generic_device);
 #endif
@@ -1934,6 +1949,8 @@
    need these symbols to load properly as modules. */
 EXPORT_SYMBOL(usb_serial_register);
 EXPORT_SYMBOL(usb_serial_deregister);
+EXPORT_SYMBOL(usb_serial_probe);
+EXPORT_SYMBOL(usb_serial_disconnect);
 #ifdef USES_EZUSB_FUNCTIONS
        EXPORT_SYMBOL(ezusb_writememory);
        EXPORT_SYMBOL(ezusb_set_reset);
diff -uNr --exclude='.*' --exclude='*.o' --exclude='*~'
a/drivers/usb/serial/usb-serial.h drivers/usb/serial/usb-serial.h
--- a/drivers/usb/serial/usb-serial.h   2008-05-06 19:00:29.000000000 -0400
+++ b/drivers/usb/serial/usb-serial.h   2008-05-20 17:27:37.000000000 -0400
@@ -245,6 +245,8 @@

 extern int  usb_serial_register(struct usb_serial_device_type *new_device);
 extern void usb_serial_deregister(struct usb_serial_device_type *device);
+extern void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum,
const struct usb_device_id *id);
+extern void usb_serial_disconnect(struct usb_device *dev, void *ptr);

 /* determine if we should include the EzUSB loader functions */
 #undef USES_EZUSB_FUNCTIONS
diff -uNr --exclude='.*' --exclude='*.o' --exclude='*~'
a/drivers/usb/storage/initializers.c drivers/usb/storage/initializers.c
--- a/drivers/usb/storage/initializers.c        2008-05-06 19:00:29.000000000 
-0400
+++ b/drivers/usb/storage/initializers.c        2008-05-19 17:01:18.000000000 
-0400
@@ -41,13 +41,34 @@
 #include "debug.h"
 #include "transport.h"

+
+/* This places the HSDPA with storage devices in multi-port mode *///--fmay
+int usb_stor_hsdpa_init(struct us_data *us)
+{
+       int result = 0;
+       unsigned char data = 0x1;
+       unsigned long flags;
+
+       printk("HSDPA storage init performing...\n");
+
+       result = usb_stor_control_msg(us, usb_sndctrlpipe(us->pusb_dev, 0),
+                                       USB_REQ_SET_FEATURE, USB_TYPE_STANDARD 
| USB_RECIP_DEVICE,
+                                       0x01, 0x0, &data, 0x1);
+
+
+
+       US_DEBUGP("HSDPA storage init performing result is %d\n", result);
+
+       return (result ? 0 : -1);
+}
+
 /* This places the Shuttle/SCM USB<->SCSI bridge devices in multi-target
  * mode */
 int usb_stor_euscsi_init(struct us_data *us)
 {
        unsigned char data = 0x1;
        int result;
-
+
        US_DEBUGP("Attempting to init eUSCSI bridge...\n");
        result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev, 0),
                        0x0C, USB_RECIP_INTERFACE | USB_TYPE_VENDOR,

diff -uNr --exclude='.*' --exclude='*.o' --exclude='*~'
a/drivers/usb/storage/initializers.h drivers/usb/storage/initializers.h
--- a/drivers/usb/storage/initializers.h        2008-05-06 19:00:29.000000000 
-0400
+++ b/drivers/usb/storage/initializers.h        2008-05-21 16:03:32.000000000 
-0400
@@ -53,3 +53,7 @@
 /* This function is required to activate all four slots on the UCR-61S2B
  * flash reader */
 int usb_stor_ucr61s2b_init(struct us_data *us);
+
+/* This places the HSDPA devices in multi-port mode --fmay*/
+int usb_stor_hsdpa_init(struct us_data *us);
+
diff -uNr --exclude='.*' --exclude='*.o' --exclude='*~'
a/drivers/usb/storage/unusual_devs.h drivers/usb/storage/unusual_devs.h
--- a/drivers/usb/storage/unusual_devs.h        2008-05-06 19:00:29.000000000 
-0400
+++ b/drivers/usb/storage/unusual_devs.h        2008-05-19 09:45:35.000000000 
-0400
@@ -1012,3 +1012,18 @@
                "Finecam L3",
                US_SC_SCSI, US_PR_BULK, NULL,
                US_FL_FIX_INQUIRY),
+
+/*HUAWEI HSDPA with storage device support --fmay*/
+UNUSUAL_DEV( 0x12d1, 0x1003, 0x0000, 0x0000,
+               "HSDPA Support",
+                "HSDPA Mass Storage",
+                US_SC_DEVICE, US_PR_DEVICE, usb_stor_hsdpa_init,
+                0),
+
+/*ZTExx HSDPA with storage device support --fmay*/
+UNUSUAL_DEV( 0x19d2, 0x2000, 0x0000, 0x0000,
+                "HSDPA Support",
+                "HSDPA Mass Storage",
+                US_SC_DEVICE, US_PR_DEVICE,
+               usb_stor_hsdpa_init, 0),
+
diff -uNr --exclude='.*' --exclude='*.o' --exclude='*~'
a/include/linux/tty_flip.h include/linux/tty_flip.h
--- a/include/linux/tty_flip.h  2008-05-21 08:18:31.000000000 -0400
+++ b/include/linux/tty_flip.h  2008-05-20 14:34:48.000000000 -0400
@@ -7,6 +7,9 @@
 #define _INLINE_ static __inline__
 #endif

+extern int tty_buffer_request_room(struct tty_struct *tty, size_t size);
+extern int tty_insert_flip_string(struct tty_struct *tty, const unsigned
char *chars, size_t size);
+
 _INLINE_ void tty_insert_flip_char(struct tty_struct *tty,
                                   unsigned char ch, char flag)
 {
diff -uNr --exclude='.*' --exclude='*.o' --exclude='*~' a/include/linux/usb.h
include/linux/usb.h
--- a/include/linux/usb.h       2008-05-19 11:19:54.000000000 -0400
+++ b/include/linux/usb.h       2008-05-21 16:03:19.000000000 -0400
@@ -225,6 +225,8 @@
 #define USB_MAXALTSETTING      128  /* Hard limit */
 #define USB_MAXINTERFACES      32
 #define USB_MAXENDPOINTS       32
+#define USB_CTRL_SET_TIMEOUT    5000
+

 /* All standard descriptors have these 2 fields in common */
 struct usb_descriptor_header {
@@ -361,6 +363,15 @@
 #define USB_INTERFACE_INFO(cl,sc,pr) \
        match_flags: USB_DEVICE_ID_MATCH_INT_INFO, bInterfaceClass: (cl),
bInterfaceSubClass: (sc), bInterfaceProtocol: (pr)

+#define USB_DEVICE_AND_INTERFACE_INFO(vend, prod, cl, sc, pr) \
+        match_flags: USB_DEVICE_ID_MATCH_INT_INFO \
+                | USB_DEVICE_ID_MATCH_DEVICE, \
+        idVendor: (vend), \
+        idProduct: (prod), \
+        bInterfaceClass: (cl), \
+        bInterfaceSubClass: (sc), \
+        bInterfaceProtocol: (pr)
+
 struct usb_device_id {
        /* This bitmask is used to determine which of the following fields
         * are to be used for matching.


_______________________________________________
openwrt-devel mailing list
openwrt-devel@lists.openwrt.org
http://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel

Reply via email to