aboutsummaryrefslogtreecommitdiff
path: root/drivers/usb/serial
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/serial')
-rw-r--r--drivers/usb/serial/Kconfig37
-rw-r--r--drivers/usb/serial/Makefile1
-rw-r--r--drivers/usb/serial/airprime.c5
-rw-r--r--drivers/usb/serial/ark3116.c4
-rw-r--r--drivers/usb/serial/belkin_sa.c37
-rw-r--r--drivers/usb/serial/console.c90
-rw-r--r--drivers/usb/serial/cp2101.c17
-rw-r--r--drivers/usb/serial/cyberjack.c1
-rw-r--r--drivers/usb/serial/cypress_m8.c25
-rw-r--r--drivers/usb/serial/digi_acceleport.c13
-rw-r--r--drivers/usb/serial/ezusb.c4
-rw-r--r--drivers/usb/serial/ftdi_sio.c293
-rw-r--r--drivers/usb/serial/ftdi_sio.h15
-rw-r--r--drivers/usb/serial/garmin_gps.c17
-rw-r--r--drivers/usb/serial/generic.c13
-rw-r--r--drivers/usb/serial/io_edgeport.c8
-rw-r--r--drivers/usb/serial/io_ti.c47
-rw-r--r--drivers/usb/serial/iuu_phoenix.c1217
-rw-r--r--drivers/usb/serial/iuu_phoenix.h122
-rw-r--r--drivers/usb/serial/keyspan.c14
-rw-r--r--drivers/usb/serial/keyspan_pda.c38
-rw-r--r--drivers/usb/serial/kl5kusb105.c26
-rw-r--r--drivers/usb/serial/kobil_sct.c1
-rw-r--r--drivers/usb/serial/mct_u232.c43
-rw-r--r--drivers/usb/serial/mct_u232.h2
-rw-r--r--drivers/usb/serial/mos7720.c61
-rw-r--r--drivers/usb/serial/mos7840.c10
-rw-r--r--drivers/usb/serial/option.c10
-rw-r--r--drivers/usb/serial/oti6858.c131
-rw-r--r--drivers/usb/serial/pl2303.c120
-rw-r--r--drivers/usb/serial/pl2303.h16
-rw-r--r--drivers/usb/serial/sierra.c227
-rw-r--r--drivers/usb/serial/ti_usb_3410_5052.c75
-rw-r--r--drivers/usb/serial/usb-serial.c42
-rw-r--r--drivers/usb/serial/visor.c22
-rw-r--r--drivers/usb/serial/whiteheat.c10
36 files changed, 2022 insertions, 792 deletions
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index 4a86696e6c7..c1e65dfd935 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -2,10 +2,7 @@
# USB Serial device configuration
#
-menu "USB Serial Converter support"
- depends on USB!=n
-
-config USB_SERIAL
+menuconfig USB_SERIAL
tristate "USB Serial Converter support"
depends on USB
---help---
@@ -20,6 +17,8 @@ config USB_SERIAL
To compile this driver as a module, choose M here: the
module will be called usbserial.
+if USB_SERIAL
+
config USB_SERIAL_CONSOLE
bool "USB Serial Console device support (EXPERIMENTAL)"
depends on USB_SERIAL=y && EXPERIMENTAL
@@ -43,6 +42,12 @@ config USB_SERIAL_CONSOLE
If unsure, say N.
+config USB_EZUSB
+ bool "Functions for loading firmware on EZUSB chips"
+ depends on USB_SERIAL
+ help
+ Say Y here if you need EZUSB device support.
+
config USB_SERIAL_GENERIC
bool "USB Generic Serial Driver"
depends on USB_SERIAL
@@ -105,6 +110,7 @@ config USB_SERIAL_CH341
config USB_SERIAL_WHITEHEAT
tristate "USB ConnectTech WhiteHEAT Serial Driver"
depends on USB_SERIAL
+ select USB_EZUSB
help
Say Y here if you want to use a ConnectTech WhiteHEAT 4 port
USB to serial converter device.
@@ -282,9 +288,21 @@ config USB_SERIAL_IPW
To compile this driver as a module, choose M here: the
module will be called ipw.
+config USB_SERIAL_IUU
+ tristate "USB Infinity USB Unlimited Phoenix Driver (Experimental)"
+ depends on USB_SERIAL && EXPERIMENTAL
+ help
+ Say Y here if you want to use a IUU in phoenix mode and get
+ an extra ttyUSBx device. More information available on
+ http://eczema.ecze.com/iuu_phoenix.html
+
+ To compile this driver as a module, choose M here: the
+ module will be called iuu_phoenix.o
+
config USB_SERIAL_KEYSPAN_PDA
tristate "USB Keyspan PDA Single Port Serial Driver"
depends on USB_SERIAL
+ select USB_EZUSB
help
Say Y here if you want to use a Keyspan PDA single port USB to
serial converter device. This driver makes use of firmware
@@ -296,6 +314,7 @@ config USB_SERIAL_KEYSPAN_PDA
config USB_SERIAL_KEYSPAN
tristate "USB Keyspan USA-xxx Serial Driver"
depends on USB_SERIAL
+ select USB_EZUSB
---help---
Say Y here if you want to use Keyspan USB to serial converter
devices. This driver makes use of Keyspan's official firmware
@@ -538,6 +557,7 @@ config USB_SERIAL_CYBERJACK
config USB_SERIAL_XIRCOM
tristate "USB Xircom / Entregra Single Port Serial Driver"
depends on USB_SERIAL
+ select USB_EZUSB
help
Say Y here if you want to use a Xircom or Entregra single port USB to
serial converter device. This driver makes use of firmware
@@ -585,11 +605,4 @@ config USB_SERIAL_DEBUG
To compile this driver as a module, choose M here: the
module will be called usb-debug.
-config USB_EZUSB
- bool
- depends on USB_SERIAL_KEYSPAN_PDA || USB_SERIAL_XIRCOM || USB_SERIAL_KEYSPAN || USB_SERIAL_WHITEHEAT
- default y
-
-
-endmenu
-
+endif # USB_SERIAL
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
index d6fb384e52b..0db109a54d1 100644
--- a/drivers/usb/serial/Makefile
+++ b/drivers/usb/serial/Makefile
@@ -30,6 +30,7 @@ obj-$(CONFIG_USB_SERIAL_GARMIN) += garmin_gps.o
obj-$(CONFIG_USB_SERIAL_HP4X) += hp4x.o
obj-$(CONFIG_USB_SERIAL_IPAQ) += ipaq.o
obj-$(CONFIG_USB_SERIAL_IPW) += ipw.o
+obj-$(CONFIG_USB_SERIAL_IUU) += iuu_phoenix.o
obj-$(CONFIG_USB_SERIAL_IR) += ir-usb.o
obj-$(CONFIG_USB_SERIAL_KEYSPAN) += keyspan.o
obj-$(CONFIG_USB_SERIAL_KEYSPAN_PDA) += keyspan_pda.o
diff --git a/drivers/usb/serial/airprime.c b/drivers/usb/serial/airprime.c
index 77bb893bf2e..f156dba0300 100644
--- a/drivers/usb/serial/airprime.c
+++ b/drivers/usb/serial/airprime.c
@@ -217,7 +217,10 @@ static void airprime_close(struct usb_serial_port *port, struct file * filp)
priv->rts_state = 0;
priv->dtr_state = 0;
- airprime_send_setup(port);
+ mutex_lock(&port->serial->disc_mutex);
+ if (!port->serial->disconnected)
+ airprime_send_setup(port);
+ mutex_lock(&port->serial->disc_mutex);
for (i = 0; i < NUM_READ_URBS; ++i) {
usb_kill_urb (priv->read_urbp[i]);
diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c
index ddfee918000..fe2bfd67ba8 100644
--- a/drivers/usb/serial/ark3116.c
+++ b/drivers/usb/serial/ark3116.c
@@ -151,8 +151,10 @@ static int ark3116_attach(struct usb_serial *serial)
return 0;
cleanup:
- for (--i; i >= 0; --i)
+ for (--i; i >= 0; --i) {
+ kfree(usb_get_serial_port_data(serial->port[i]));
usb_set_serial_port_data(serial->port[i], NULL);
+ }
return -ENOMEM;
}
diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c
index 86724e88570..df0a2b3b029 100644
--- a/drivers/usb/serial/belkin_sa.c
+++ b/drivers/usb/serial/belkin_sa.c
@@ -350,14 +350,12 @@ static void belkin_sa_set_termios (struct usb_serial_port *port, struct ktermios
unsigned long control_state;
int bad_flow_control;
speed_t baud;
+ struct ktermios *termios = port->tty->termios;
- if ((!port->tty) || (!port->tty->termios)) {
- dbg ("%s - no tty or termios structure", __FUNCTION__);
- return;
- }
+ iflag = termios->c_iflag;
+ cflag = termios->c_cflag;
- iflag = port->tty->termios->c_iflag;
- cflag = port->tty->termios->c_cflag;
+ termios->c_cflag &= ~CMSPAR;
/* get a local copy of the current port settings */
spin_lock_irqsave(&priv->lock, flags);
@@ -369,33 +367,30 @@ static void belkin_sa_set_termios (struct usb_serial_port *port, struct ktermios
old_cflag = old_termios->c_cflag;
/* Set the baud rate */
- if( (cflag&CBAUD) != (old_cflag&CBAUD) ) {
+ if ((cflag & CBAUD) != (old_cflag & CBAUD)) {
/* reassert DTR and (maybe) RTS on transition from B0 */
if( (old_cflag&CBAUD) == B0 ) {
control_state |= (TIOCM_DTR|TIOCM_RTS);
if (BSA_USB_CMD(BELKIN_SA_SET_DTR_REQUEST, 1) < 0)
err("Set DTR error");
/* don't set RTS if using hardware flow control */
- if (!(old_cflag&CRTSCTS) )
+ if (!(old_cflag & CRTSCTS))
if (BSA_USB_CMD(BELKIN_SA_SET_RTS_REQUEST, 1) < 0)
err("Set RTS error");
}
}
baud = tty_get_baud_rate(port->tty);
- if (baud == 0) {
- dbg("%s - tty_get_baud_rate says 0 baud", __FUNCTION__);
- return;
- }
- urb_value = BELKIN_SA_BAUD(baud);
- /* Clip to maximum speed */
- if (urb_value == 0)
- urb_value = 1;
- /* Turn it back into a resulting real baud rate */
- baud = BELKIN_SA_BAUD(urb_value);
- /* FIXME: Once the tty updates are done then push this back to the tty */
-
- if ((cflag & CBAUD) != B0 ) {
+ if (baud) {
+ urb_value = BELKIN_SA_BAUD(baud);
+ /* Clip to maximum speed */
+ if (urb_value == 0)
+ urb_value = 1;
+ /* Turn it back into a resulting real baud rate */
+ baud = BELKIN_SA_BAUD(urb_value);
+
+ /* Report the actual baud rate back to the caller */
+ tty_encode_baud_rate(port->tty, baud, baud);
if (BSA_USB_CMD(BELKIN_SA_SET_BAUDRATE_REQUEST, urb_value) < 0)
err("Set baudrate error");
} else {
diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c
index 0362654d3b5..66ce30c1b75 100644
--- a/drivers/usb/serial/console.c
+++ b/drivers/usb/serial/console.c
@@ -64,8 +64,8 @@ static int usb_console_setup(struct console *co, char *options)
struct usb_serial *serial;
struct usb_serial_port *port;
int retval = 0;
- struct tty_struct *tty;
- struct ktermios *termios;
+ struct tty_struct *tty = NULL;
+ struct ktermios *termios = NULL, dummy;
dbg ("%s", __FUNCTION__);
@@ -133,11 +133,14 @@ static int usb_console_setup(struct console *co, char *options)
}
co->cflag = cflag;
- /* grab the first serial port that happens to be connected */
- serial = usb_serial_get_by_index(0);
+ /*
+ * no need to check the index here: if the index is wrong, console
+ * code won't call us
+ */
+ serial = usb_serial_get_by_index(co->index);
if (serial == NULL) {
/* no device is connected yet, sorry :( */
- err ("No USB device connected to ttyUSB0");
+ err ("No USB device connected to ttyUSB%i", co->index);
return -ENODEV;
}
@@ -148,49 +151,64 @@ static int usb_console_setup(struct console *co, char *options)
++port->open_count;
if (port->open_count == 1) {
+ if (serial->type->set_termios) {
+ /*
+ * allocate a fake tty so the driver can initialize
+ * the termios structure, then later call set_termios to
+ * configure according to command line arguments
+ */
+ tty = kzalloc(sizeof(*tty), GFP_KERNEL);
+ if (!tty) {
+ retval = -ENOMEM;
+ err("no more memory");
+ goto reset_open_count;
+ }
+ termios = kzalloc(sizeof(*termios), GFP_KERNEL);
+ if (!termios) {
+ retval = -ENOMEM;
+ err("no more memory");
+ goto free_tty;
+ }
+ memset(&dummy, 0, sizeof(struct ktermios));
+ tty->termios = termios;
+ port->tty = tty;
+ }
+
/* only call the device specific open if this
* is the first time the port is opened */
if (serial->type->open)
retval = serial->type->open(port, NULL);
else
retval = usb_serial_generic_open(port, NULL);
- if (retval)
- port->open_count = 0;
- }
- if (retval) {
- err ("could not open USB console port");
- return retval;
- }
-
- if (serial->type->set_termios) {
- struct ktermios dummy;
- /* build up a fake tty structure so that the open call has something
- * to look at to get the cflag value */
- tty = kzalloc(sizeof(*tty), GFP_KERNEL);
- if (!tty) {
- err ("no more memory");
- return -ENOMEM;
+ if (retval) {
+ err("could not open USB console port");
+ goto free_termios;
}
- termios = kzalloc(sizeof(*termios), GFP_KERNEL);
- if (!termios) {
- err ("no more memory");
- kfree (tty);
- return -ENOMEM;
- }
- memset(&dummy, 0, sizeof(struct ktermios));
- termios->c_cflag = cflag;
- tty->termios = termios;
- port->tty = tty;
- /* set up the initial termios settings */
- serial->type->set_termios(port, &dummy);
- port->tty = NULL;
- kfree (termios);
- kfree (tty);
+ if (serial->type->set_termios) {
+ termios->c_cflag = cflag;
+ serial->type->set_termios(port, &dummy);
+
+ port->tty = NULL;
+ kfree(termios);
+ kfree(tty);
+ }
}
+ port->console = 1;
+ retval = 0;
+
+out:
return retval;
+free_termios:
+ kfree(termios);
+ port->tty = NULL;
+free_tty:
+ kfree(tty);
+reset_open_count:
+ port->open_count = 0;
+goto out;
}
static void usb_console_write(struct console *co, const char *buf, unsigned count)
diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c
index 3a83cb4c4bc..f3ca66017a0 100644
--- a/drivers/usb/serial/cp2101.c
+++ b/drivers/usb/serial/cp2101.c
@@ -55,9 +55,11 @@ static int debug;
static struct usb_device_id id_table [] = {
{ USB_DEVICE(0x08e6, 0x5501) }, /* Gemalto Prox-PU/CU contactless smartcard reader */
{ USB_DEVICE(0x0FCF, 0x1003) }, /* Dynastream ANT development board */
+ { USB_DEVICE(0x0FCF, 0x1004) }, /* Dynastream ANT2USB */
{ USB_DEVICE(0x10A6, 0xAA26) }, /* Knock-off DCU-11 cable */
{ USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */
{ USB_DEVICE(0x10B5, 0xAC70) }, /* Nokia CA-42 USB */
+ { USB_DEVICE(0x10C4, 0x800A) }, /* SPORTident BSM7-D-USB main station */
{ USB_DEVICE(0x10C4, 0x803B) }, /* Pololu USB-serial converter */
{ USB_DEVICE(0x10C4, 0x8053) }, /* Enfora EDG1228 */
{ USB_DEVICE(0x10C4, 0x8066) }, /* Argussoft In-System Programmer */
@@ -71,11 +73,17 @@ static struct usb_device_id id_table [] = {
{ USB_DEVICE(0x10C4, 0x815E) }, /* Helicomm IP-Link 1220-DVM */
{ USB_DEVICE(0x10C4, 0x81C8) }, /* Lipowsky Industrie Elektronik GmbH, Baby-JTAG */
{ USB_DEVICE(0x10C4, 0x81E2) }, /* Lipowsky Industrie Elektronik GmbH, Baby-LIN */
+ { USB_DEVICE(0x10C4, 0x81E7) }, /* Aerocomm Radio */
{ USB_DEVICE(0x10C4, 0x8218) }, /* Lipowsky Industrie Elektronik GmbH, HARP-1 */
{ USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */
{ USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */
+ { USB_DEVICE(0x10C4, 0xF001) }, /* Elan Digital Systems USBscope50 */
+ { USB_DEVICE(0x10C4, 0xF002) }, /* Elan Digital Systems USBwave12 */
+ { USB_DEVICE(0x10C4, 0xF003) }, /* Elan Digital Systems USBpulse100 */
+ { USB_DEVICE(0x10C4, 0xF004) }, /* Elan Digital Systems USBcount50 */
{ USB_DEVICE(0x10C5, 0xEA61) }, /* Silicon Labs MobiData GPRS USB Modem */
{ USB_DEVICE(0x13AD, 0x9999) }, /* Baltech card reader */
+ { USB_DEVICE(0x166A, 0x0303) }, /* Clipsal 5500PCU C-Bus USB interface */
{ USB_DEVICE(0x16D6, 0x0001) }, /* Jablotron serial interface */
{ } /* Terminating Entry */
};
@@ -98,8 +106,8 @@ static struct usb_serial_driver cp2101_device = {
.usb_driver = &cp2101_driver,
.id_table = id_table,
.num_interrupt_in = 0,
- .num_bulk_in = 0,
- .num_bulk_out = 0,
+ .num_bulk_in = NUM_DONT_CARE,
+ .num_bulk_out = NUM_DONT_CARE,
.num_ports = 1,
.open = cp2101_open,
.close = cp2101_close,
@@ -340,7 +348,10 @@ static void cp2101_close (struct usb_serial_port *port, struct file * filp)
usb_kill_urb(port->write_urb);
usb_kill_urb(port->read_urb);
- cp2101_set_config_single(port, CP2101_UART, UART_DISABLE);
+ mutex_lock(&port->serial->disc_mutex);
+ if (!port->serial->disconnected)
+ cp2101_set_config_single(port, CP2101_UART, UART_DISABLE);
+ mutex_unlock(&port->serial->disc_mutex);
}
/*
diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c
index 4353df92487..8d9b045aa7e 100644
--- a/drivers/usb/serial/cyberjack.c
+++ b/drivers/usb/serial/cyberjack.c
@@ -319,7 +319,6 @@ static void cyberjack_read_int_callback( struct urb *urb )
/* React only to interrupts signaling a bulk_in transfer */
if( (urb->actual_length==4) && (data[0]==0x01) ) {
short old_rdtodo;
- int result;
/* This is a announcement of coming bulk_ins. */
unsigned short size = ((unsigned short)data[3]<<8)+data[2]+3;
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
index 163386336a5..08c65c1a377 100644
--- a/drivers/usb/serial/cypress_m8.c
+++ b/drivers/usb/serial/cypress_m8.c
@@ -682,7 +682,6 @@ static void cypress_close(struct usb_serial_port *port, struct file * filp)
{
struct cypress_private *priv = usb_get_serial_port_data(port);
unsigned int c_cflag;
- unsigned long flags;
int bps;
long timeout;
wait_queue_t wait;
@@ -690,7 +689,7 @@ static void cypress_close(struct usb_serial_port *port, struct file * filp)
dbg("%s - port %d", __FUNCTION__, port->number);
/* wait for data to drain from buffer */
- spin_lock_irqsave(&priv->lock, flags);
+ spin_lock_irq(&priv->lock);
timeout = CYPRESS_CLOSING_WAIT;
init_waitqueue_entry(&wait, current);
add_wait_queue(&port->tty->write_wait, &wait);
@@ -698,18 +697,25 @@ static void cypress_close(struct usb_serial_port *port, struct file * filp)
set_current_state(TASK_INTERRUPTIBLE);
if (cypress_buf_data_avail(priv->buf) == 0
|| timeout == 0 || signal_pending(current)
- || !usb_get_intfdata(port->serial->interface))
+ /* without mutex, allowed due to harmless failure mode */
+ || port->serial->disconnected)
break;
- spin_unlock_irqrestore(&priv->lock, flags);
+ spin_unlock_irq(&priv->lock);
timeout = schedule_timeout(timeout);
- spin_lock_irqsave(&priv->lock, flags);
+ spin_lock_irq(&priv->lock);
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&port->tty->write_wait, &wait);
/* clear out any remaining data in the buffer */
cypress_buf_clear(priv->buf);
- spin_unlock_irqrestore(&priv->lock, flags);
-
+ spin_unlock_irq(&priv->lock);
+
+ /* writing is potentially harmful, lock must be taken */
+ mutex_lock(&port->serial->disc_mutex);
+ if (port->serial->disconnected) {
+ mutex_unlock(&port->serial->disc_mutex);
+ return;
+ }
/* wait for characters to drain from device */
bps = tty_get_baud_rate(port->tty);
if (bps > 1200)
@@ -727,10 +733,10 @@ static void cypress_close(struct usb_serial_port *port, struct file * filp)
if (c_cflag & HUPCL) {
/* drop dtr and rts */
priv = usb_get_serial_port_data(port);
- spin_lock_irqsave(&priv->lock, flags);
+ spin_lock_irq(&priv->lock);
priv->line_control = 0;
priv->cmd_ctrl = 1;
- spin_unlock_irqrestore(&priv->lock, flags);
+ spin_unlock_irq(&priv->lock);
cypress_write(port, NULL, 0);
}
}
@@ -738,6 +744,7 @@ static void cypress_close(struct usb_serial_port *port, struct file * filp)
if (stats)
dev_info (&port->dev, "Statistics: %d Bytes In | %d Bytes Out | %d Commands Issued\n",
priv->bytes_in, priv->bytes_out, priv->cmd_count);
+ mutex_unlock(&port->serial->disc_mutex);
} /* cypress_close */
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index ae410c4678e..5f9c6e46bee 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -1405,19 +1405,19 @@ static void digi_close(struct usb_serial_port *port, struct file *filp)
unsigned char buf[32];
struct tty_struct *tty = port->tty;
struct digi_port *priv = usb_get_serial_port_data(port);
- unsigned long flags = 0;
dbg("digi_close: TOP: port=%d, open_count=%d",
priv->dp_port_num, port->open_count);
+ mutex_lock(&port->serial->disc_mutex);
/* if disconnected, just clear flags */
- if (!usb_get_intfdata(port->serial->interface))
+ if (port->serial->disconnected)
goto exit;
/* do cleanup only after final close on this port */
- spin_lock_irqsave(&priv->dp_port_lock, flags);
+ spin_lock_irq(&priv->dp_port_lock);
priv->dp_in_close = 1;
- spin_unlock_irqrestore(&priv->dp_port_lock, flags);
+ spin_unlock_irq(&priv->dp_port_lock);
/* tell line discipline to process only XON/XOFF */
tty->closing = 1;
@@ -1482,11 +1482,12 @@ static void digi_close(struct usb_serial_port *port, struct file *filp)
}
tty->closing = 0;
exit:
- spin_lock_irqsave(&priv->dp_port_lock, flags);
+ spin_lock_irq(&priv->dp_port_lock);
priv->dp_write_urb_in_use = 0;
priv->dp_in_close = 0;
wake_up_interruptible(&priv->dp_close_wait);
- spin_unlock_irqrestore(&priv->dp_port_lock, flags);
+ spin_unlock_irq(&priv->dp_port_lock);
+ mutex_unlock(&port->serial->disc_mutex);
dbg("digi_close: done");
}
diff --git a/drivers/usb/serial/ezusb.c b/drivers/usb/serial/ezusb.c
index 97ee718b1da..3f698baa0ab 100644
--- a/drivers/usb/serial/ezusb.c
+++ b/drivers/usb/serial/ezusb.c
@@ -53,6 +53,6 @@ int ezusb_set_reset (struct usb_serial *serial, unsigned char reset_bit)
}
-EXPORT_SYMBOL(ezusb_writememory);
-EXPORT_SYMBOL(ezusb_set_reset);
+EXPORT_SYMBOL_GPL(ezusb_writememory);
+EXPORT_SYMBOL_GPL(ezusb_set_reset);
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index c40e77dccf8..90dcc625f70 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -17,226 +17,8 @@
* See http://ftdi-usb-sio.sourceforge.net for upto date testing info
* and extra documentation
*
- * (21/Jul/2004) Ian Abbott
- * Incorporated Steven Turner's code to add support for the FT2232C chip.
- * The prelimilary port to the 2.6 kernel was by Rus V. Brushkoff. I have
- * fixed a couple of things.
- *
- * (27/May/2004) Ian Abbott
- * Improved throttling code, mostly stolen from the WhiteHEAT driver.
- *
- * (26/Mar/2004) Jan Capek
- * Added PID's for ICD-U20/ICD-U40 - incircuit PIC debuggers from CCS Inc.
- *
- * (09/Feb/2004) Ian Abbott
- * Changed full name of USB-UIRT device to avoid "/" character.
- * Added FTDI's alternate PID (0x6006) for FT232/245 devices.
- * Added PID for "ELV USB Module UO100" from Stefan Frings.
- *
- * (21/Oct/2003) Ian Abbott
- * Renamed some VID/PID macros for Matrix Orbital and Perle Systems
- * devices. Removed Matrix Orbital and Perle Systems devices from the
- * 8U232AM device table, but left them in the FT232BM table, as they are
- * known to use only FT232BM.
- *
- * (17/Oct/2003) Scott Allen
- * Added vid/pid for Perle Systems UltraPort USB serial converters
- *
- * (21/Sep/2003) Ian Abbott
- * Added VID/PID for Omnidirectional Control Technology US101 USB to
- * RS-232 adapter (also rebadged as Dick Smith Electronics XH6381).
- * VID/PID supplied by Donald Gordon.
- *
- * (19/Aug/2003) Ian Abbott
- * Freed urb's transfer buffer in write bulk callback.
- * Omitted some paranoid checks in write bulk callback that don't matter.
- * Scheduled work in write bulk callback regardless of port's open count.
- *
- * (05/Aug/2003) Ian Abbott
- * Added VID/PID for ID TECH IDT1221U USB to RS-232 adapter.
- * VID/PID provided by Steve Briggs.
- *
- * (23/Jul/2003) Ian Abbott
- * Added PIDs for CrystalFontz 547, 633, 631, 635, 640 and 640 from
- * Wayne Wylupski.
- *
- * (10/Jul/2003) David Glance
- * Added PID for DSS-20 SyncStation cradle for Sony-Ericsson P800.
- *
- * (27/Jun/2003) Ian Abbott
- * Reworked the urb handling logic. We have no more pool, but dynamically
- * allocate the urb and the transfer buffer on the fly. In testing this
- * does not incure any measurable overhead. This also relies on the fact
- * that we have proper reference counting logic for urbs. I nicked this
- * from Greg KH's Visor driver.
- *
- * (23/Jun/2003) Ian Abbott
- * Reduced flip buffer pushes and corrected a data length test in
- * ftdi_read_bulk_callback.
- * Defererence pointers after any paranoid checks, not before.
- *
- * (21/Jun/2003) Erik Nygren
- * Added support for Home Electronics Tira-1 IR transceiver using FT232BM chip.
- * See <http://www.home-electro.com/tira1.htm>. Only operates properly
- * at 100000 and RTS-CTS, so set custom divisor mode on startup.
- * Also force the Tira-1 and USB-UIRT to only use their custom baud rates.
- *
- * (18/Jun/2003) Ian Abbott
- * Added Device ID of the USB relais from Rudolf Gugler (backported from
- * Philipp Gühring's patch for 2.5.x kernel).
- * Moved read transfer buffer reallocation into startup function.
- * Free existing write urb and transfer buffer in startup function.
- * Only use urbs in write urb pool that were successfully allocated.
- * Moved some constant macros out of functions.
- * Minor whitespace and comment changes.
- *
- * (12/Jun/2003) David Norwood
- * Added support for USB-UIRT IR transceiver using 8U232AM chip.
- * See <http://home.earthlink.net/~jrhees/USBUIRT/index.htm>. Only
- * operates properly at 312500, so set custom divisor mode on startup.
- *
- * (12/Jun/2003) Ian Abbott
- * Added Sealevel SeaLINK+ 210x, 220x, 240x, 280x vid/pids from Tuan Hoang
- * - I've eliminated some that don't seem to exist!
- * Added Home Electronics Tira-1 IR transceiver pid from Chris Horn
- * Some whitespace/coding-style cleanups
- *
- * (11/Jun/2003) Ian Abbott
- * Fixed unsafe spinlock usage in ftdi_write
- *
- * (24/Feb/2003) Richard Shooter
- * Increase read buffer size to improve read speeds at higher baud rates
- * (specifically tested with up to 1Mb/sec at 1.5M baud)
- *
- * (23/Feb/2003) John Wilkins
- * Added Xon/xoff flow control (activating support in the ftdi device)
- * Added vid/pid for Videonetworks/Homechoice (UK ISP)
- *
- * (23/Feb/2003) Bill Ryder
- * Added matrix orb device vid/pids from Wayne Wylupski
- *
- * (19/Feb/2003) Ian Abbott
- * For TIOCSSERIAL, set alt_speed to 0 when ASYNC_SPD_MASK value has
- * changed to something other than ASYNC_SPD_HI, ASYNC_SPD_VHI,
- * ASYNC_SPD_SHI or ASYNC_SPD_WARP. Also, unless ASYNC_SPD_CUST is in
- * force, don't bother changing baud rate when custom_divisor has changed.
- *
- * (18/Feb/2003) Ian Abbott
- * Fixed TIOCMGET handling to include state of DTR and RTS, the state
- * of which are now saved by set_dtr() and set_rts().
- * Fixed improper storage class for buf in set_dtr() and set_rts().
- * Added FT232BM chip type and support for its extra baud rates (compared
- * to FT8U232AM).
- * Took account of special case divisor values for highest baud rates of
- * FT8U232AM and FT232BM.
- * For TIOCSSERIAL, forced alt_speed to 0 when ASYNC_SPD_CUST kludge used,
- * as previous alt_speed setting is now stale.
- * Moved startup code common between the startup routines for the
- * different chip types into a common subroutine.
- *
- * (17/Feb/2003) Bill Ryder
- * Added write urb buffer pool on a per device basis
- * Added more checking for open file on callbacks (fixed OOPS)
- * Added CrystalFontz 632 and 634 PIDs
- * (thanx to CrystalFontz for the sample devices - they flushed out
- * some driver bugs)
- * Minor debugging message changes
- * Added throttle, unthrottle and chars_in_buffer functions
- * Fixed FTDI_SIO (the original device) bug
- * Fixed some shutdown handling
- *
- *
- *
- *
- * (07/Jun/2002) Kuba Ober
- * Changed FTDI_SIO_BASE_BAUD_TO_DIVISOR macro into ftdi_baud_to_divisor
- * function. It was getting too complex.
- * Fix the divisor calculation logic which was setting divisor of 0.125
- * instead of 0.5 for fractional parts of divisor equal to 5/8, 6/8, 7/8.
- * Also make it bump up the divisor to next integer in case of 7/8 - it's
- * a better approximation.
- *
- * (25/Jul/2002) Bill Ryder inserted Dmitri's TIOCMIWAIT patch
- * Not tested by me but it doesn't break anything I use.
- *
- * (04/Jan/2002) Kuba Ober
- * Implemented 38400 baudrate kludge, where it can be substituted with other
- * values. That's the only way to set custom baudrates.
- * Implemented TIOCSSERIAL, TIOCGSERIAL ioctl's so that setserial is happy.
- * FIXME: both baudrate things should eventually go to usbserial.c as other
- * devices may need that functionality too. Actually, it can probably be
- * merged in serial.c somehow - too many drivers repeat this code over
- * and over.
- * Fixed baudrate forgetfulness - open() used to reset baudrate to 9600 every time.
- * Divisors for baudrates are calculated by a macro.
- * Small code cleanups. Ugly whitespace changes for Plato's sake only ;-].
- *
- * (04/Nov/2001) Bill Ryder
- * Fixed bug in read_bulk_callback where incorrect urb buffer was used.
- * Cleaned up write offset calculation
- * Added write_room since default values can be incorrect for sio
- * Changed write_bulk_callback to use same queue_task as other drivers
- * (the previous version caused panics)
- * Removed port iteration code since the device only has one I/O port and it
- * was wrong anyway.
- *
- * (31/May/2001) gkh
- * Switched from using spinlock to a semaphore, which fixes lots of problems.
- *
- * (23/May/2001) Bill Ryder
- * Added runtime debug patch (thanx Tyson D Sawyer).
- * Cleaned up comments for 8U232
- * Added parity, framing and overrun error handling
- * Added receive break handling.
- *
- * (04/08/2001) gb
- * Identify version on module load.
- *
- * (18/March/2001) Bill Ryder
- * (Not released)
- * Added send break handling. (requires kernel patch too)
- * Fixed 8U232AM hardware RTS/CTS etc status reporting.
- * Added flipbuf fix copied from generic device
- *
- * (12/3/2000) Bill Ryder
- * Added support for 8U232AM device.
- * Moved PID and VIDs into header file only.
- * Turned on low-latency for the tty (device will do high baudrates)
- * Added shutdown routine to close files when device removed.
- * More debug and error message cleanups.
- *
- * (11/13/2000) Bill Ryder
- * Added spinlock protected open code and close code.
- * Multiple opens work (sort of - see webpage mentioned above).
- * Cleaned up comments. Removed multiple PID/VID definitions.
- * Factorised cts/dtr code
- * Made use of __FUNCTION__ in dbg's
- *
- * (11/01/2000) Adam J. Richter
- * usb_device_id table support
- *
- * (10/05/2000) gkh
- * Fixed bug with urb->dev not being set properly, now that the usb
- * core needs it.
- *
- * (09/11/2000) gkh
- * Removed DEBUG #ifdefs with call to usb_serial_debug_data
- *
- * (07/19/2000) gkh
- * Added module_init and module_exit functions to handle the fact that this
- * driver is a loadable module now.
- *
- * (04/04/2000) Bill Ryder
- * Fixed bugs in TCGET/TCSET ioctls (by removing them - they are
- * handled elsewhere in the tty io driver chain).
- *
- * (03/30/2000) Bill Ryder
- * Implemented lots of ioctls
- * Fixed a race condition in write
- * Changed some dbg's to errs
- *
- * (03/26/2000) gkh
- * Split driver up into device specific pieces.
+ * Change entries from 2004 and earlier can be found in versions of this
+ * file in kernel versions prior to the 2.6.24 release.
*
*/
@@ -309,12 +91,12 @@ struct ftdi_sio_quirk {
void (*port_probe)(struct ftdi_private *); /* Special settings for probed ports. */
};
-static int ftdi_olimex_probe (struct usb_serial *serial);
+static int ftdi_jtag_probe (struct usb_serial *serial);
static void ftdi_USB_UIRT_setup (struct ftdi_private *priv);
static void ftdi_HE_TIRA1_setup (struct ftdi_private *priv);
-static struct ftdi_sio_quirk ftdi_olimex_quirk = {
- .probe = ftdi_olimex_probe,
+static struct ftdi_sio_quirk ftdi_jtag_quirk = {
+ .probe = ftdi_jtag_probe,
};
static struct ftdi_sio_quirk ftdi_USB_UIRT_quirk = {
@@ -471,30 +253,28 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_IBS_PEDO_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_IBS_PROD_PID) },
/*
- * These will probably use user-space drivers. Uncomment them if
- * you need them or use the user-specified vendor/product module
- * parameters (see ftdi_sio.h for the numbers). Make a fuss if
- * you think the driver should recognize any of them by default.
+ * Due to many user requests for multiple ELV devices we enable
+ * them by default.
*/
- /* { USB_DEVICE(FTDI_VID, FTDI_ELV_CLI7000_PID) }, */
- /* { USB_DEVICE(FTDI_VID, FTDI_ELV_PPS7330_PID) }, */
- /* { USB_DEVICE(FTDI_VID, FTDI_ELV_TFM100_PID) }, */
- /* { USB_DEVICE(FTDI_VID, FTDI_ELV_UDF77_PID) }, */
- /* { USB_DEVICE(FTDI_VID, FTDI_ELV_UIO88_PID) }, */
- /* { USB_DEVICE(FTDI_VID, FTDI_ELV_UAD8_PID) }, */
- /* { USB_DEVICE(FTDI_VID, FTDI_ELV_UDA7_PID) }, */
- /* { USB_DEVICE(FTDI_VID, FTDI_ELV_USI2_PID) }, */
- /* { USB_DEVICE(FTDI_VID, FTDI_ELV_T1100_PID) }, */
- /* { USB_DEVICE(FTDI_VID, FTDI_ELV_PCD200_PID) }, */
- /* { USB_DEVICE(FTDI_VID, FTDI_ELV_ULA200_PID) }, */
- /* { USB_DEVICE(FTDI_VID, FTDI_ELV_CSI8_PID) }, */
- /* { USB_DEVICE(FTDI_VID, FTDI_ELV_EM1000DL_PID) }, */
- /* { USB_DEVICE(FTDI_VID, FTDI_ELV_PCK100_PID) }, */
- /* { USB_DEVICE(FTDI_VID, FTDI_ELV_RFP500_PID) }, */
- /* { USB_DEVICE(FTDI_VID, FTDI_ELV_FS20SIG_PID) }, */
- /* { USB_DEVICE(FTDI_VID, FTDI_ELV_WS300PC_PID) }, */
- /* { USB_DEVICE(FTDI_VID, FTDI_ELV_FHZ1300PC_PID) }, */
- /* { USB_DEVICE(FTDI_VID, FTDI_ELV_WS500_PID) }, */
+ { USB_DEVICE(FTDI_VID, FTDI_ELV_CLI7000_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_ELV_PPS7330_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_ELV_TFM100_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_ELV_UDF77_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_ELV_UIO88_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_ELV_UAD8_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_ELV_UDA7_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_ELV_USI2_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_ELV_T1100_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_ELV_PCD200_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_ELV_ULA200_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_ELV_CSI8_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_ELV_EM1000DL_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_ELV_PCK100_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_ELV_RFP500_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_ELV_FS20SIG_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_ELV_WS300PC_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_ELV_FHZ1300PC_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_ELV_WS500_PID) },
{ USB_DEVICE(FTDI_VID, LINX_SDMUSBQSS_PID) },
{ USB_DEVICE(FTDI_VID, LINX_MASTERDEVEL2_PID) },
{ USB_DEVICE(FTDI_VID, LINX_FUTURE_0_PID) },
@@ -545,6 +325,7 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16C_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16HR_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16HRC_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16IC_PID) },
{ USB_DEVICE(KOBIL_VID, KOBIL_CONV_B1_PID) },
{ USB_DEVICE(KOBIL_VID, KOBIL_CONV_KAAN_PID) },
{ USB_DEVICE(POSIFLEX_VID, POSIFLEX_PP7000_PID) },
@@ -569,8 +350,13 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(TELLDUS_VID, TELLDUS_TELLSTICK_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_MAXSTREAM_PID) },
{ USB_DEVICE(TML_VID, TML_USB_SERIAL_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_ELSTER_UNICOM_PID) },
{ USB_DEVICE(OLIMEX_VID, OLIMEX_ARM_USB_OCD_PID),
- .driver_info = (kernel_ulong_t)&ftdi_olimex_quirk },
+ .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
+ { USB_DEVICE(FIC_VID, FIC_NEO1973_DEBUG_PID),
+ .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
+ { USB_DEVICE(FTDI_VID, FTDI_OOCDLINK_PID),
+ .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
{ }, /* Optional parameter entry */
{ } /* Terminating entry */
};
@@ -1283,10 +1069,11 @@ static void ftdi_HE_TIRA1_setup (struct ftdi_private *priv)
} /* ftdi_HE_TIRA1_setup */
/*
- * First port on Olimex arm-usb-ocd is reserved for JTAG interface
- * and can be accessed from userspace using openocd.
+ * First port on JTAG adaptors such as Olimex arm-usb-ocd or the FIC/OpenMoko
+ * Neo1973 Debug Board is reserved for JTAG interface and can be accessed from
+ * userspace using openocd.
*/
-static int ftdi_olimex_probe(struct usb_serial *serial)
+static int ftdi_jtag_probe(struct usb_serial *serial)
{
struct usb_device *udev = serial->dev;
struct usb_interface *interface = serial->interface;
@@ -1294,7 +1081,7 @@ static int ftdi_olimex_probe(struct usb_serial *serial)
dbg("%s",__FUNCTION__);
if (interface == udev->actconfig->interface[0]) {
- info("Ignoring reserved serial port on Olimex arm-usb-ocd\n");
+ info("Ignoring serial port reserved for JTAG");
return -ENODEV;
}
@@ -1411,7 +1198,8 @@ static void ftdi_close (struct usb_serial_port *port, struct file *filp)
dbg("%s", __FUNCTION__);
- if (c_cflag & HUPCL){
+ mutex_lock(&port->serial->disc_mutex);
+ if (c_cflag & HUPCL && !port->serial->disconnected){
/* Disable flow control */
if (usb_control_msg(port->serial->dev,
usb_sndctrlpipe(port->serial->dev, 0),
@@ -1425,6 +1213,7 @@ static void ftdi_close (struct usb_serial_port *port, struct file *filp)
/* drop RTS and DTR */
clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
} /* Note change no line if hupcl is off */
+ mutex_unlock(&port->serial->disc_mutex);
/* cancel any scheduled reading */
cancel_delayed_work(&priv->rx_work);
diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
index b51cbb0eaa0..6eee2ab914e 100644
--- a/drivers/usb/serial/ftdi_sio.h
+++ b/drivers/usb/serial/ftdi_sio.h
@@ -98,6 +98,10 @@
#define FTDI_MTXORB_5_PID 0xFA05 /* Matrix Orbital Product Id */
#define FTDI_MTXORB_6_PID 0xFA06 /* Matrix Orbital Product Id */
+/* OOCDlink by Joern Kaipf <joernk@web.de>
+ * (http://www.joernonline.de/dw/doku.php?id=start&idx=projects:oocdlink) */
+#define FTDI_OOCDLINK_PID 0xbaf8 /* Amontec JTAGkey */
+
/* Interbiometrics USB I/O Board */
/* Developed for Interbiometrics by Rudolf Gugler */
#define INTERBIOMETRICS_VID 0x1209
@@ -245,6 +249,7 @@
#define FTDI_ELV_WS300PC_PID 0xE0F6 /* PC-Wetterstation (WS 300 PC) */
#define FTDI_ELV_FHZ1300PC_PID 0xE0E8 /* FHZ 1300 PC */
#define FTDI_ELV_WS500_PID 0xE0E9 /* PC-Wetterstation (WS 500) */
+#define FTDI_ELV_EM1010PC_PID 0xE0EF /* Engery monitor EM 1010 PC */
/*
* Definitions for ID TECH (www.idt-net.com) devices
@@ -278,6 +283,7 @@
#define FTDI_ATIK_ATK16C_PID 0xDF32 /* ATIK ATK-16C Colour Camera */
#define FTDI_ATIK_ATK16HR_PID 0xDF31 /* ATIK ATK-16HR Grayscale Camera */
#define FTDI_ATIK_ATK16HRC_PID 0xDF33 /* ATIK ATK-16HRC Colour Camera */
+#define FTDI_ATIK_ATK16IC_PID 0xDF35 /* ATIK ATK-16IC Grayscale Camera */
/*
* Protego product ids
@@ -534,6 +540,8 @@
#define OLIMEX_VID 0x15BA
#define OLIMEX_ARM_USB_OCD_PID 0x0003
+/* www.elsterelectricity.com Elster Unicom III Optical Probe */
+#define FTDI_ELSTER_UNICOM_PID 0xE700 /* Product Id */
/*
* The Mobility Lab (TML)
@@ -556,6 +564,13 @@
/*
+ * FIC / OpenMoko, Inc. http://wiki.openmoko.org/wiki/Neo1973_Debug_Board_v3
+ * Submitted by Harald Welte <laforge@openmoko.org>
+ */
+#define FIC_VID 0x1457
+#define FIC_NEO1973_DEBUG_PID 0x5118
+
+/*
* BmRequestType: 1100 0000b
* bRequest: FTDI_E2_READ
* wValue: 0
diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c
index f1c90cfe725..d74e43d6923 100644
--- a/drivers/usb/serial/garmin_gps.c
+++ b/drivers/usb/serial/garmin_gps.c
@@ -1020,19 +1020,26 @@ static void garmin_close (struct usb_serial_port *port, struct file * filp)
if (!serial)
return;
- garmin_clear(garmin_data_p);
+ mutex_lock(&port->serial->disc_mutex);
+ if (!port->serial->disconnected)
+ garmin_clear(garmin_data_p);
/* shutdown our urbs */
usb_kill_urb (port->read_urb);
usb_kill_urb (port->write_urb);
- if (noResponseFromAppLayer(garmin_data_p) ||
- ((garmin_data_p->flags & CLEAR_HALT_REQUIRED) != 0)) {
- process_resetdev_request(port);
- garmin_data_p->state = STATE_RESET;
+ if (!port->serial->disconnected) {
+ if (noResponseFromAppLayer(garmin_data_p) ||
+ ((garmin_data_p->flags & CLEAR_HALT_REQUIRED) != 0)) {
+ process_resetdev_request(port);
+ garmin_data_p->state = STATE_RESET;
+ } else {
+ garmin_data_p->state = STATE_DISCONNECTED;
+ }
} else {
garmin_data_p->state = STATE_DISCONNECTED;
}
+ mutex_unlock(&port->serial->disc_mutex);
}
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c
index 9eb4a65ee4d..97fa3c42843 100644
--- a/drivers/usb/serial/generic.c
+++ b/drivers/usb/serial/generic.c
@@ -175,6 +175,14 @@ int usb_serial_generic_resume(struct usb_serial *serial)
struct usb_serial_port *port;
int i, c = 0, r;
+#ifdef CONFIG_PM
+ /*
+ * If this is an autoresume, don't submit URBs.
+ * They will be submitted in the open function instead.
+ */
+ if (serial->dev->auto_pm)
+ return 0;
+#endif
for (i = 0; i < serial->num_ports; i++) {
port = serial->port[i];
if (port->open_count && port->read_urb) {
@@ -327,6 +335,7 @@ void usb_serial_generic_read_bulk_callback (struct urb *urb)
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
unsigned char *data = urb->transfer_buffer;
int status = urb->status;
+ unsigned long flags;
dbg("%s - port %d", __FUNCTION__, port->number);
@@ -339,11 +348,11 @@ void usb_serial_generic_read_bulk_callback (struct urb *urb)
usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data);
/* Throttle the device if requested by tty */
- spin_lock(&port->lock);
+ spin_lock_irqsave(&port->lock, flags);
if (!(port->throttled = port->throttle_req))
/* Handle data and continue reading from device */
flush_and_resubmit_read_urb(port);
- spin_unlock(&port->lock);
+ spin_unlock_irqrestore(&port->lock, flags);
}
EXPORT_SYMBOL_GPL(usb_serial_generic_read_bulk_callback);
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index a5d2e115e16..3428ccc28da 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -959,7 +959,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
*
* This function will block the close until one of the following:
* 1. Response to our Chase comes from Edgeport
- * 2. A timout of 10 seconds without activity has expired
+ * 2. A timeout of 10 seconds without activity has expired
* (1K of Edgeport data @ 2400 baud ==> 4 sec to empty)
*
************************************************************************/
@@ -999,7 +999,7 @@ static void block_until_chase_response(struct edgeport_port *edge_port)
return;
}
} else {
- // Reset timout value back to 10 seconds
+ // Reset timeout value back to 10 seconds
dbg("%s - Last %d, Current %d", __FUNCTION__, lastCredits, edge_port->txCredits);
loop = 10;
}
@@ -1014,7 +1014,7 @@ static void block_until_chase_response(struct edgeport_port *edge_port)
* This function will block the close until one of the following:
* 1. TX count are 0
* 2. The edgeport has stopped
- * 3. A timout of 3 seconds without activity has expired
+ * 3. A timeout of 3 seconds without activity has expired
*
************************************************************************/
static void block_until_tx_empty (struct edgeport_port *edge_port)
@@ -1050,7 +1050,7 @@ static void block_until_tx_empty (struct edgeport_port *edge_port)
return;
}
} else {
- // Reset timout value back to seconds
+ // Reset timeout value back to seconds
loop = 30;
}
}
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
index b8670905bc3..cd3405953f7 100644
--- a/drivers/usb/serial/io_ti.c
+++ b/drivers/usb/serial/io_ti.c
@@ -34,6 +34,7 @@
#include <linux/tty_flip.h>
#include <linux/module.h>
#include <linux/spinlock.h>
+#include <linux/mutex.h>
#include <linux/serial.h>
#include <linux/ioctl.h>
#include <asm/uaccess.h>
@@ -133,7 +134,7 @@ struct edgeport_serial {
struct product_info product_info;
u8 TI_I2C_Type; // Type of I2C in UMP
u8 TiReadI2C; // Set to TRUE if we have read the I2c in Boot Mode
- struct semaphore es_sem;
+ struct mutex es_lock;
int num_ports_open;
struct usb_serial *serial;
};
@@ -1978,7 +1979,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
}
/* set up the port settings */
- edge_set_termios (port, NULL);
+ edge_set_termios (port, port->tty->termios);
/* open up the port */
@@ -2044,7 +2045,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
dbg ("ShadowMCR 0x%X", edge_port->shadow_mcr);
edge_serial = edge_port->edge_serial;
- if (down_interruptible(&edge_serial->es_sem))
+ if (mutex_lock_interruptible(&edge_serial->es_lock))
return -ERESTARTSYS;
if (edge_serial->num_ports_open == 0) {
/* we are the first port to be opened, let's post the interrupt urb */
@@ -2052,7 +2053,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
if (!urb) {
dev_err (&port->dev, "%s - no interrupt urb present, exiting\n", __FUNCTION__);
status = -EINVAL;
- goto up_es_sem;
+ goto release_es_lock;
}
urb->complete = edge_interrupt_callback;
urb->context = edge_serial;
@@ -2060,7 +2061,7 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
status = usb_submit_urb (urb, GFP_KERNEL);
if (status) {
dev_err (&port->dev, "%s - usb_submit_urb failed with value %d\n", __FUNCTION__, status);
- goto up_es_sem;
+ goto release_es_lock;
}
}
@@ -2092,13 +2093,13 @@ static int edge_open (struct usb_serial_port *port, struct file * filp)
dbg("%s - exited", __FUNCTION__);
- goto up_es_sem;
+ goto release_es_lock;
unlink_int_urb:
if (edge_port->edge_serial->num_ports_open == 0)
usb_kill_urb(port->serial->port[0]->interrupt_in_urb);
-up_es_sem:
- up(&edge_serial->es_sem);
+release_es_lock:
+ mutex_unlock(&edge_serial->es_lock);
return status;
}
@@ -2137,14 +2138,14 @@ static void edge_close (struct usb_serial_port *port, struct file *filp)
0,
NULL,
0);
- down(&edge_serial->es_sem);
+ mutex_lock(&edge_serial->es_lock);
--edge_port->edge_serial->num_ports_open;
if (edge_port->edge_serial->num_ports_open <= 0) {
/* last port is now closed, let's shut down our interrupt urb */
usb_kill_urb(port->serial->port[0]->interrupt_in_urb);
edge_port->edge_serial->num_ports_open = 0;
}
- up(&edge_serial->es_sem);
+ mutex_unlock(&edge_serial->es_lock);
edge_port->close_pending = 0;
dbg("%s - exited", __FUNCTION__);
@@ -2393,11 +2394,6 @@ static void change_port_settings (struct edgeport_port *edge_port, struct ktermi
dbg("%s - port %d", __FUNCTION__, edge_port->port->number);
tty = edge_port->port->tty;
- if ((!tty) ||
- (!tty->termios)) {
- dbg("%s - no tty structures", __FUNCTION__);
- return;
- }
config = kmalloc (sizeof (*config), GFP_KERNEL);
if (!config) {
@@ -2492,15 +2488,21 @@ static void change_port_settings (struct edgeport_port *edge_port, struct ktermi
}
}
+ tty->termios->c_cflag &= ~CMSPAR;
+
/* Round the baud rate */
baud = tty_get_baud_rate(tty);
if (!baud) {
/* pick a default, any default... */
baud = 9600;
- }
+ } else
+ tty_encode_baud_rate(tty, baud, baud);
+
edge_port->baud_rate = baud;
config->wBaudRate = (__u16)((461550L + baud/2) / baud);
+ /* FIXME: Recompute actual baud from divisor here */
+
dbg ("%s - baud rate = %d, wBaudRate = %d", __FUNCTION__, baud, config->wBaudRate);
dbg ("wBaudRate: %d", (int)(461550L / config->wBaudRate));
@@ -2538,19 +2540,12 @@ static void edge_set_termios (struct usb_serial_port *port, struct ktermios *old
struct tty_struct *tty = port->tty;
unsigned int cflag;
- if (!port->tty || !port->tty->termios) {
- dbg ("%s - no tty or termios", __FUNCTION__);
- return;
- }
-
cflag = tty->termios->c_cflag;
dbg("%s - clfag %08x iflag %08x", __FUNCTION__,
tty->termios->c_cflag, tty->termios->c_iflag);
- if (old_termios) {
- dbg("%s - old clfag %08x old iflag %08x", __FUNCTION__,
- old_termios->c_cflag, old_termios->c_iflag);
- }
+ dbg("%s - old clfag %08x old iflag %08x", __FUNCTION__,
+ old_termios->c_cflag, old_termios->c_iflag);
dbg("%s - port %d", __FUNCTION__, port->number);
@@ -2743,7 +2738,7 @@ static int edge_startup (struct usb_serial *serial)
dev_err(&serial->dev->dev, "%s - Out of memory\n", __FUNCTION__);
return -ENOMEM;
}
- sema_init(&edge_serial->es_sem, 1);
+ mutex_init(&edge_serial->es_lock);
edge_serial->serial = serial;
usb_set_serial_data(serial, edge_serial);
diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c
new file mode 100644
index 00000000000..fde188e23ce
--- /dev/null
+++ b/drivers/usb/serial/iuu_phoenix.c
@@ -0,0 +1,1217 @@
+/*
+ * Infinity Unlimited USB Phoenix driver
+ *
+ * Copyright (C) 2007 Alain Degreffe (eczema@ecze.com)
+ *
+ * Original code taken from iuutool (Copyright (C) 2006 Juan Carlos Borrás)
+ *
+ * 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.
+ *
+ * And tested with help of WB Electronics
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/spinlock.h>
+#include <linux/uaccess.h>
+#include <linux/usb.h>
+#include <linux/usb/serial.h>
+#include "iuu_phoenix.h"
+#include <linux/random.h>
+
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+static int debug = 1;
+#else
+static int debug;
+#endif
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v0.5"
+#define DRIVER_DESC "Infinity USB Unlimited Phoenix driver"
+
+static struct usb_device_id id_table[] = {
+ {USB_DEVICE(IUU_USB_VENDOR_ID, IUU_USB_PRODUCT_ID)},
+ {} /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+static struct usb_driver iuu_driver = {
+ .name = "iuu_phoenix",
+ .probe = usb_serial_probe,
+ .disconnect = usb_serial_disconnect,
+ .id_table = id_table,
+ .no_dynamic_id = 1,
+};
+
+/* turbo parameter */
+static int boost = 100;
+static int clockmode = 1;
+static int cdmode = 1;
+static int iuu_cardin;
+static int iuu_cardout;
+static int xmas;
+
+static void read_rxcmd_callback(struct urb *urb);
+
+struct iuu_private {
+ spinlock_t lock; /* store irq state */
+ wait_queue_head_t delta_msr_wait;
+ u8 line_control;
+ u8 line_status;
+ u8 termios_initialized;
+ int tiostatus; /* store IUART SIGNAL for tiocmget call */
+ u8 reset; /* if 1 reset is needed */
+ int poll; /* number of poll */
+ u8 *writebuf; /* buffer for writing to device */
+ int writelen; /* num of byte to write to device */
+ u8 *buf; /* used for initialize speed */
+ u8 *dbgbuf; /* debug buffer */
+ u8 len;
+};
+
+
+static void iuu_free_buf(struct iuu_private *priv)
+{
+ kfree(priv->buf);
+ kfree(priv->dbgbuf);
+ kfree(priv->writebuf);
+}
+
+static int iuu_alloc_buf(struct iuu_private *priv)
+{
+ priv->buf = kzalloc(256, GFP_KERNEL);
+ priv->dbgbuf = kzalloc(256, GFP_KERNEL);
+ priv->writebuf = kzalloc(256, GFP_KERNEL);
+ if (!priv->buf || !priv->dbgbuf || !priv->writebuf) {
+ iuu_free_buf(priv);
+ dbg("%s problem allocation buffer", __FUNCTION__);
+ return -ENOMEM;
+ }
+ dbg("%s - Privates buffers allocation success", __FUNCTION__);
+ return 0;
+}
+
+static int iuu_startup(struct usb_serial *serial)
+{
+ struct iuu_private *priv;
+ priv = kzalloc(sizeof(struct iuu_private), GFP_KERNEL);
+ dbg("%s- priv allocation success", __FUNCTION__);
+ if (!priv)
+ return -ENOMEM;
+ if (iuu_alloc_buf(priv)) {
+ kfree(priv);
+ return -ENOMEM;
+ }
+ spin_lock_init(&priv->lock);
+ init_waitqueue_head(&priv->delta_msr_wait);
+ usb_set_serial_port_data(serial->port[0], priv);
+ return 0;
+}
+
+/* Shutdown function */
+static void iuu_shutdown(struct usb_serial *serial)
+{
+ struct usb_serial_port *port = serial->port[0];
+ struct iuu_private *priv = usb_get_serial_port_data(port);
+ if (!port)
+ return;
+
+ dbg("%s", __FUNCTION__);
+
+ if (priv) {
+ iuu_free_buf(priv);
+ dbg("%s - I will free all", __FUNCTION__);
+ usb_set_serial_port_data(port, NULL);
+
+ dbg("%s - priv is not anymore in port structure", __FUNCTION__);
+ kfree(priv);
+
+ dbg("%s priv is now kfree", __FUNCTION__);
+ }
+}
+
+static int iuu_tiocmset(struct usb_serial_port *port, struct file *file,
+ unsigned int set, unsigned int clear)
+{
+ struct iuu_private *priv = usb_get_serial_port_data(port);
+ struct tty_struct *tty;
+ tty = port->tty;
+
+ dbg("%s (%d) msg : SET = 0x%04x, CLEAR = 0x%04x ", __FUNCTION__,
+ port->number, set, clear);
+ if (set & TIOCM_RTS)
+ priv->tiostatus = TIOCM_RTS;
+
+ if (!(set & TIOCM_RTS) && priv->tiostatus == TIOCM_RTS) {
+ dbg("%s TIOCMSET RESET called !!!", __FUNCTION__);
+ priv->reset = 1;
+ return 0;
+ }
+
+ return 0;
+}
+
+/* This is used to provide a carrier detect mechanism
+ * When a card is present, the response is 0x00
+ * When no card , the reader respond with TIOCM_CD
+ * This is known as CD autodetect mechanism
+ */
+static int iuu_tiocmget(struct usb_serial_port *port, struct file *file)
+{
+ struct iuu_private *priv = usb_get_serial_port_data(port);
+ return priv->tiostatus;
+}
+
+static void iuu_rxcmd(struct urb *urb)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ int result;
+ dbg("%s - enter", __FUNCTION__);
+
+ if (urb->status) {
+ dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
+ /* error stop all */
+ return;
+ }
+
+
+ memset(port->write_urb->transfer_buffer, IUU_UART_RX, 1);
+ usb_fill_bulk_urb(port->write_urb, port->serial->dev,
+ usb_sndbulkpipe(port->serial->dev,
+ port->bulk_out_endpointAddress),
+ port->write_urb->transfer_buffer, 1,
+ read_rxcmd_callback, port);
+ result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
+}
+
+static int iuu_reset(struct usb_serial_port *port, u8 wt)
+{
+ struct iuu_private *priv = usb_get_serial_port_data(port);
+ int result;
+ char *buf_ptr = port->write_urb->transfer_buffer;
+ dbg("%s - enter", __FUNCTION__);
+
+ /* Prepare the reset sequence */
+
+ *buf_ptr++ = IUU_RST_SET;
+ *buf_ptr++ = IUU_DELAY_MS;
+ *buf_ptr++ = wt;
+ *buf_ptr = IUU_RST_CLEAR;
+
+ /* send the sequence */
+
+ usb_fill_bulk_urb(port->write_urb,
+ port->serial->dev,
+ usb_sndbulkpipe(port->serial->dev,
+ port->bulk_out_endpointAddress),
+ port->write_urb->transfer_buffer, 4, iuu_rxcmd, port);
+ result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
+ priv->reset = 0;
+ return result;
+}
+
+/* Status Function
+ * Return value is
+ * 0x00 = no card
+ * 0x01 = smartcard
+ * 0x02 = sim card
+ */
+static void iuu_update_status_callback(struct urb *urb)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct iuu_private *priv = usb_get_serial_port_data(port);
+ u8 *st;
+ dbg("%s - enter", __FUNCTION__);
+
+ if (urb->status) {
+ dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
+ /* error stop all */
+ return;
+ }
+
+ st = urb->transfer_buffer;
+ dbg("%s - enter", __FUNCTION__);
+ if (urb->actual_length == 1) {
+ switch (st[0]) {
+ case 0x1:
+ priv->tiostatus = iuu_cardout;
+ break;
+ case 0x0:
+ priv->tiostatus = iuu_cardin;
+ break;
+ default:
+ priv->tiostatus = iuu_cardin;
+ }
+ }
+ iuu_rxcmd(urb);
+}
+
+static void iuu_status_callback(struct urb *urb)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ int result;
+ dbg("%s - enter", __FUNCTION__);
+
+ dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
+ usb_fill_bulk_urb(port->read_urb, port->serial->dev,
+ usb_rcvbulkpipe(port->serial->dev,
+ port->bulk_in_endpointAddress),
+ port->read_urb->transfer_buffer, 256,
+ iuu_update_status_callback, port);
+ result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
+}
+
+static int iuu_status(struct usb_serial_port *port)
+{
+ int result;
+
+ dbg("%s - enter", __FUNCTION__);
+
+ memset(port->write_urb->transfer_buffer, IUU_GET_STATE_REGISTER, 1);
+ usb_fill_bulk_urb(port->write_urb, port->serial->dev,
+ usb_sndbulkpipe(port->serial->dev,
+ port->bulk_out_endpointAddress),
+ port->write_urb->transfer_buffer, 1,
+ iuu_status_callback, port);
+ result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
+ return result;
+
+}
+
+static int bulk_immediate(struct usb_serial_port *port, u8 *buf, u8 count)
+{
+ int status;
+ struct usb_serial *serial = port->serial;
+ int actual = 0;
+
+ dbg("%s - enter", __FUNCTION__);
+
+ /* send the data out the bulk port */
+
+ status =
+ usb_bulk_msg(serial->dev,
+ usb_sndbulkpipe(serial->dev,
+ port->bulk_out_endpointAddress), buf,
+ count, &actual, HZ * 1);
+
+ if (status != IUU_OPERATION_OK) {
+ dbg("%s - error = %2x", __FUNCTION__, status);
+ } else {
+ dbg("%s - write OK !", __FUNCTION__);
+ }
+ return status;
+}
+
+static int read_immediate(struct usb_serial_port *port, u8 *buf, u8 count)
+{
+ int status;
+ struct usb_serial *serial = port->serial;
+ int actual = 0;
+
+ dbg("%s - enter", __FUNCTION__);
+
+ /* send the data out the bulk port */
+
+ status =
+ usb_bulk_msg(serial->dev,
+ usb_rcvbulkpipe(serial->dev,
+ port->bulk_in_endpointAddress), buf,
+ count, &actual, HZ * 1);
+
+ if (status != IUU_OPERATION_OK) {
+ dbg("%s - error = %2x", __FUNCTION__, status);
+ } else {
+ dbg("%s - read OK !", __FUNCTION__);
+ }
+
+ return status;
+}
+
+static int iuu_led(struct usb_serial_port *port, unsigned int R,
+ unsigned int G, unsigned int B, u8 f)
+{
+ int status;
+ u8 *buf;
+ buf = kmalloc(8, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ dbg("%s - enter", __FUNCTION__);
+
+ buf[0] = IUU_SET_LED;
+ buf[1] = R & 0xFF;
+ buf[2] = (R >> 8) & 0xFF;
+ buf[3] = G & 0xFF;
+ buf[4] = (G >> 8) & 0xFF;
+ buf[5] = B & 0xFF;
+ buf[6] = (B >> 8) & 0xFF;
+ buf[7] = f;
+ status = bulk_immediate(port, buf, 8);
+ kfree(buf);
+ if (status != IUU_OPERATION_OK)
+ dbg("%s - led error status = %2x", __FUNCTION__, status);
+ else
+ dbg("%s - led OK !", __FUNCTION__);
+ return IUU_OPERATION_OK;
+}
+
+static void iuu_rgbf_fill_buffer(u8 *buf, u8 r1, u8 r2, u8 g1, u8 g2, u8 b1,
+ u8 b2, u8 freq)
+{
+ *buf++ = IUU_SET_LED;
+ *buf++ = r1;
+ *buf++ = r2;
+ *buf++ = g1;
+ *buf++ = g2;
+ *buf++ = b1;
+ *buf++ = b2;
+ *buf = freq;
+}
+
+static void iuu_led_activity_on(struct urb *urb)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ int result;
+ char *buf_ptr = port->write_urb->transfer_buffer;
+ *buf_ptr++ = IUU_SET_LED;
+ if (xmas == 1) {
+ get_random_bytes(buf_ptr, 6);
+ *(buf_ptr+7) = 1;
+ } else {
+ iuu_rgbf_fill_buffer(buf_ptr, 255, 255, 0, 0, 0, 0, 255);
+ }
+
+ usb_fill_bulk_urb(port->write_urb, port->serial->dev,
+ usb_sndbulkpipe(port->serial->dev,
+ port->bulk_out_endpointAddress),
+ port->write_urb->transfer_buffer, 8 ,
+ iuu_rxcmd, port);
+ result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
+}
+
+static void iuu_led_activity_off(struct urb *urb)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ int result;
+ char *buf_ptr = port->write_urb->transfer_buffer;
+ if (xmas == 1) {
+ iuu_rxcmd(urb);
+ return;
+ } else {
+ *buf_ptr++ = IUU_SET_LED;
+ iuu_rgbf_fill_buffer(buf_ptr, 0, 0, 255, 255, 0, 0, 255);
+ }
+ usb_fill_bulk_urb(port->write_urb, port->serial->dev,
+ usb_sndbulkpipe(port->serial->dev,
+ port->bulk_out_endpointAddress),
+ port->write_urb->transfer_buffer, 8 ,
+ iuu_rxcmd, port);
+ result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
+}
+
+
+
+static int iuu_clk(struct usb_serial_port *port, int dwFrq)
+{
+ int status;
+ struct iuu_private *priv = usb_get_serial_port_data(port);
+ int Count = 0;
+ u8 FrqGenAdr = 0x69;
+ u8 DIV = 0; /* 8bit */
+ u8 XDRV = 0; /* 8bit */
+ u8 PUMP = 0; /* 3bit */
+ u8 PBmsb = 0; /* 2bit */
+ u8 PBlsb = 0; /* 8bit */
+ u8 PO = 0; /* 1bit */
+ u8 Q = 0; /* 7bit */
+ /* 24bit = 3bytes */
+ unsigned int P = 0;
+ unsigned int P2 = 0;
+ int frq = (int)dwFrq;
+
+ dbg("%s - enter", __FUNCTION__);
+
+ if (frq == 0) {
+ priv->buf[Count++] = IUU_UART_WRITE_I2C;
+ priv->buf[Count++] = FrqGenAdr << 1;
+ priv->buf[Count++] = 0x09;
+ priv->buf[Count++] = 0x00;
+
+ status = bulk_immediate(port, (u8 *) priv->buf, Count);
+ if (status != 0) {
+ dbg("%s - write error ", __FUNCTION__);
+ return status;
+ }
+ } else if (frq == 3579000) {
+ DIV = 100;
+ P = 1193;
+ Q = 40;
+ XDRV = 0;
+ } else if (frq == 3680000) {
+ DIV = 105;
+ P = 161;
+ Q = 5;
+ XDRV = 0;
+ } else if (frq == 6000000) {
+ DIV = 66;
+ P = 66;
+ Q = 2;
+ XDRV = 0x28;
+ } else {
+ unsigned int result = 0;
+ unsigned int tmp = 0;
+ unsigned int check;
+ unsigned int check2;
+ char found = 0x00;
+ unsigned int lQ = 2;
+ unsigned int lP = 2055;
+ unsigned int lDiv = 4;
+
+ for (lQ = 2; lQ <= 47 && !found; lQ++)
+ for (lP = 2055; lP >= 8 && !found; lP--)
+ for (lDiv = 4; lDiv <= 127 && !found; lDiv++) {
+ tmp = (12000000 / lDiv) * (lP / lQ);
+ if (abs((int)(tmp - frq)) <
+ abs((int)(frq - result))) {
+ check2 = (12000000 / lQ);
+ if (check2 < 250000)
+ continue;
+ check = (12000000 / lQ) * lP;
+ if (check > 400000000)
+ continue;
+ if (check < 100000000)
+ continue;
+ if (lDiv < 4 || lDiv > 127)
+ continue;
+ result = tmp;
+ P = lP;
+ DIV = lDiv;
+ Q = lQ;
+ if (result == frq)
+ found = 0x01;
+ }
+ }
+ }
+ P2 = ((P - PO) / 2) - 4;
+ DIV = DIV;
+ PUMP = 0x04;
+ PBmsb = (P2 >> 8 & 0x03);
+ PBlsb = P2 & 0xFF;
+ PO = (P >> 10) & 0x01;
+ Q = Q - 2;
+
+ priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */
+ priv->buf[Count++] = FrqGenAdr << 1;
+ priv->buf[Count++] = 0x09;
+ priv->buf[Count++] = 0x20; /* Adr = 0x09 */
+ priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */
+ priv->buf[Count++] = FrqGenAdr << 1;
+ priv->buf[Count++] = 0x0C;
+ priv->buf[Count++] = DIV; /* Adr = 0x0C */
+ priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */
+ priv->buf[Count++] = FrqGenAdr << 1;
+ priv->buf[Count++] = 0x12;
+ priv->buf[Count++] = XDRV; /* Adr = 0x12 */
+ priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */
+ priv->buf[Count++] = FrqGenAdr << 1;
+ priv->buf[Count++] = 0x13;
+ priv->buf[Count++] = 0x6B; /* Adr = 0x13 */
+ priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */
+ priv->buf[Count++] = FrqGenAdr << 1;
+ priv->buf[Count++] = 0x40;
+ priv->buf[Count++] = (0xC0 | ((PUMP & 0x07) << 2)) |
+ (PBmsb & 0x03); /* Adr = 0x40 */
+ priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */
+ priv->buf[Count++] = FrqGenAdr << 1;
+ priv->buf[Count++] = 0x41;
+ priv->buf[Count++] = PBlsb; /* Adr = 0x41 */
+ priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */
+ priv->buf[Count++] = FrqGenAdr << 1;
+ priv->buf[Count++] = 0x42;
+ priv->buf[Count++] = Q | (((PO & 0x01) << 7)); /* Adr = 0x42 */
+ priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */
+ priv->buf[Count++] = FrqGenAdr << 1;
+ priv->buf[Count++] = 0x44;
+ priv->buf[Count++] = (char)0xFF; /* Adr = 0x44 */
+ priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */
+ priv->buf[Count++] = FrqGenAdr << 1;
+ priv->buf[Count++] = 0x45;
+ priv->buf[Count++] = (char)0xFE; /* Adr = 0x45 */
+ priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */
+ priv->buf[Count++] = FrqGenAdr << 1;
+ priv->buf[Count++] = 0x46;
+ priv->buf[Count++] = 0x7F; /* Adr = 0x46 */
+ priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */
+ priv->buf[Count++] = FrqGenAdr << 1;
+ priv->buf[Count++] = 0x47;
+ priv->buf[Count++] = (char)0x84; /* Adr = 0x47 */
+
+ status = bulk_immediate(port, (u8 *) priv->buf, Count);
+ if (status != IUU_OPERATION_OK)
+ dbg("%s - write error ", __FUNCTION__);
+ return status;
+}
+
+static int iuu_uart_flush(struct usb_serial_port *port)
+{
+ int i;
+ int status;
+ u8 rxcmd = IUU_UART_RX;
+ struct iuu_private *priv = usb_get_serial_port_data(port);
+
+ dbg("%s - enter", __FUNCTION__);
+
+ if (iuu_led(port, 0xF000, 0, 0, 0xFF) < 0)
+ return -EIO;
+
+ for (i = 0; i < 2; i++) {
+ status = bulk_immediate(port, &rxcmd, 1);
+ if (status != IUU_OPERATION_OK) {
+ dbg("%s - uart_flush_write error", __FUNCTION__);
+ return status;
+ }
+
+ status = read_immediate(port, &priv->len, 1);
+ if (status != IUU_OPERATION_OK) {
+ dbg("%s - uart_flush_read error", __FUNCTION__);
+ return status;
+ }
+
+ if (priv->len > 0) {
+ dbg("%s - uart_flush datalen is : %i ", __FUNCTION__,
+ priv->len);
+ status = read_immediate(port, priv->buf, priv->len);
+ if (status != IUU_OPERATION_OK) {
+ dbg("%s - uart_flush_read error", __FUNCTION__);
+ return status;
+ }
+ }
+ }
+ dbg("%s - uart_flush_read OK!", __FUNCTION__);
+ iuu_led(port, 0, 0xF000, 0, 0xFF);
+ return status;
+}
+
+static void read_buf_callback(struct urb *urb)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ unsigned char *data = urb->transfer_buffer;
+ struct tty_struct *tty;
+ dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
+
+ if (urb->status) {
+ dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
+ if (urb->status == -EPROTO) {
+ /* reschedule needed */
+ }
+ return;
+ }
+
+ dbg("%s - %i chars to write", __FUNCTION__, urb->actual_length);
+ tty = port->tty;
+ if (data == NULL)
+ dbg("%s - data is NULL !!!", __FUNCTION__);
+ if (tty && urb->actual_length && data) {
+ tty_insert_flip_string(tty, data, urb->actual_length);
+ tty_flip_buffer_push(tty);
+ }
+ iuu_led_activity_on(urb);
+}
+
+static int iuu_bulk_write(struct usb_serial_port *port)
+{
+ struct iuu_private *priv = usb_get_serial_port_data(port);
+ unsigned int flags;
+ int result;
+ int i;
+ char *buf_ptr = port->write_urb->transfer_buffer;
+ dbg("%s - enter", __FUNCTION__);
+
+ *buf_ptr++ = IUU_UART_ESC;
+ *buf_ptr++ = IUU_UART_TX;
+ *buf_ptr++ = priv->writelen;
+
+ memcpy(buf_ptr, priv->writebuf,
+ priv->writelen);
+ if (debug == 1) {
+ for (i = 0; i < priv->writelen; i++)
+ sprintf(priv->dbgbuf + i*2 ,
+ "%02X", priv->writebuf[i]);
+ priv->dbgbuf[priv->writelen+i*2] = 0;
+ dbg("%s - writing %i chars : %s", __FUNCTION__,
+ priv->writelen, priv->dbgbuf);
+ }
+ usb_fill_bulk_urb(port->write_urb, port->serial->dev,
+ usb_sndbulkpipe(port->serial->dev,
+ port->bulk_out_endpointAddress),
+ port->write_urb->transfer_buffer, priv->writelen + 3,
+ iuu_rxcmd, port);
+ result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->writelen = 0;
+ spin_unlock_irqrestore(&priv->lock, flags);
+ usb_serial_port_softint(port);
+ return result;
+}
+
+static int iuu_read_buf(struct usb_serial_port *port, int len)
+{
+ int result;
+ dbg("%s - enter", __FUNCTION__);
+
+ usb_fill_bulk_urb(port->read_urb, port->serial->dev,
+ usb_rcvbulkpipe(port->serial->dev,
+ port->bulk_in_endpointAddress),
+ port->read_urb->transfer_buffer, len,
+ read_buf_callback, port);
+ result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
+ return result;
+}
+
+static void iuu_uart_read_callback(struct urb *urb)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct iuu_private *priv = usb_get_serial_port_data(port);
+ unsigned int flags;
+ int status;
+ int error = 0;
+ int len = 0;
+ unsigned char *data = urb->transfer_buffer;
+ priv->poll++;
+
+ dbg("%s - enter", __FUNCTION__);
+
+ if (urb->status) {
+ dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
+ /* error stop all */
+ return;
+ }
+ if (data == NULL)
+ dbg("%s - data is NULL !!!", __FUNCTION__);
+
+ if (urb->actual_length == 1 && data != NULL)
+ len = (int) data[0];
+
+ if (urb->actual_length > 1) {
+ dbg("%s - urb->actual_length = %i", __FUNCTION__,
+ urb->actual_length);
+ error = 1;
+ return;
+ }
+ /* if len > 0 call readbuf */
+
+ if (len > 0 && error == 0) {
+ dbg("%s - call read buf - len to read is %i ",
+ __FUNCTION__, len);
+ status = iuu_read_buf(port, len);
+ return;
+ }
+ /* need to update status ? */
+ if (priv->poll > 99) {
+ status = iuu_status(port);
+ priv->poll = 0;
+ return;
+ }
+
+ /* reset waiting ? */
+
+ if (priv->reset == 1) {
+ status = iuu_reset(port, 0xC);
+ return;
+ }
+ /* Writebuf is waiting */
+ spin_lock_irqsave(&priv->lock, flags);
+ if (priv->writelen > 0) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ status = iuu_bulk_write(port);
+ return;
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+ /* if nothing to write call again rxcmd */
+ dbg("%s - rxcmd recall", __FUNCTION__);
+ iuu_led_activity_off(urb);
+ return;
+}
+
+static int iuu_uart_write(struct usb_serial_port *port, const u8 *buf,
+ int count)
+{
+ struct iuu_private *priv = usb_get_serial_port_data(port);
+ unsigned int flags;
+ dbg("%s - enter", __FUNCTION__);
+
+ if (count > 256)
+ return -ENOMEM;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (priv->writelen > 0) {
+ /* buffer already filled but not commited */
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return (0);
+ }
+ /* fill the buffer */
+ memcpy(priv->writebuf, buf, count);
+ priv->writelen = count;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return (count);
+}
+
+static void read_rxcmd_callback(struct urb *urb)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ int result;
+ dbg("%s - enter", __FUNCTION__);
+
+ dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
+
+ if (urb->status) {
+ dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
+ /* error stop all */
+ return;
+ }
+
+ usb_fill_bulk_urb(port->read_urb, port->serial->dev,
+ usb_rcvbulkpipe(port->serial->dev,
+ port->bulk_in_endpointAddress),
+ port->read_urb->transfer_buffer, 256,
+ iuu_uart_read_callback, port);
+ result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
+ dbg("%s - submit result = %d", __FUNCTION__, result);
+ return;
+}
+
+static int iuu_uart_on(struct usb_serial_port *port)
+{
+ int status;
+ u8 *buf;
+
+ buf = kmalloc(sizeof(u8) * 4, GFP_KERNEL);
+
+ if (!buf)
+ return -ENOMEM;
+
+ buf[0] = IUU_UART_ENABLE;
+ buf[1] = (u8) ((IUU_BAUD_9600 >> 8) & 0x00FF);
+ buf[2] = (u8) (0x00FF & IUU_BAUD_9600);
+ buf[3] = (u8) (0x0F0 & IUU_TWO_STOP_BITS) | (0x07 & IUU_PARITY_EVEN);
+
+ status = bulk_immediate(port, buf, 4);
+ if (status != IUU_OPERATION_OK) {
+ dbg("%s - uart_on error", __FUNCTION__);
+ goto uart_enable_failed;
+ }
+ /* iuu_reset() the card after iuu_uart_on() */
+ status = iuu_uart_flush(port);
+ if (status != IUU_OPERATION_OK)
+ dbg("%s - uart_flush error", __FUNCTION__);
+uart_enable_failed:
+ kfree(buf);
+ return status;
+}
+
+/* Diables the IUU UART (a.k.a. the Phoenix voiderface) */
+static int iuu_uart_off(struct usb_serial_port *port)
+{
+ int status;
+ u8 *buf;
+ buf = kmalloc(1, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+ buf[0] = IUU_UART_DISABLE;
+
+ status = bulk_immediate(port, buf, 1);
+ if (status != IUU_OPERATION_OK)
+ dbg("%s - uart_off error", __FUNCTION__);
+
+ kfree(buf);
+ return status;
+}
+
+static int iuu_uart_baud(struct usb_serial_port *port, u32 baud,
+ u32 *actual, u8 parity)
+{
+ int status;
+ u8 *dataout;
+ u8 DataCount = 0;
+ u8 T1Frekvens = 0;
+ u8 T1reload = 0;
+ unsigned int T1FrekvensHZ = 0;
+
+ dataout = kmalloc(sizeof(u8) * 5, GFP_KERNEL);
+
+ if (!dataout)
+ return -ENOMEM;
+
+ if (baud < 1200 || baud > 230400) {
+ kfree(dataout);
+ return IUU_INVALID_PARAMETER;
+ }
+ if (baud > 977) {
+ T1Frekvens = 3;
+ T1FrekvensHZ = 500000;
+ }
+
+ if (baud > 3906) {
+ T1Frekvens = 2;
+ T1FrekvensHZ = 2000000;
+ }
+
+ if (baud > 11718) {
+ T1Frekvens = 1;
+ T1FrekvensHZ = 6000000;
+ }
+
+ if (baud > 46875) {
+ T1Frekvens = 0;
+ T1FrekvensHZ = 24000000;
+ }
+
+ T1reload = 256 - (u8) (T1FrekvensHZ / (baud * 2));
+
+ /* magic number here: ENTER_FIRMWARE_UPDATE; */
+ dataout[DataCount++] = IUU_UART_ESC;
+ /* magic number here: CHANGE_BAUD; */
+ dataout[DataCount++] = IUU_UART_CHANGE;
+ dataout[DataCount++] = T1Frekvens;
+ dataout[DataCount++] = T1reload;
+
+ *actual = (T1FrekvensHZ / (256 - T1reload)) / 2;
+
+ switch (parity & 0x0F) {
+ case IUU_PARITY_NONE:
+ dataout[DataCount++] = 0x00;
+ break;
+ case IUU_PARITY_EVEN:
+ dataout[DataCount++] = 0x01;
+ break;
+ case IUU_PARITY_ODD:
+ dataout[DataCount++] = 0x02;
+ break;
+ case IUU_PARITY_MARK:
+ dataout[DataCount++] = 0x03;
+ break;
+ case IUU_PARITY_SPACE:
+ dataout[DataCount++] = 0x04;
+ break;
+ default:
+ kfree(dataout);
+ return IUU_INVALID_PARAMETER;
+ break;
+ }
+
+ switch (parity & 0xF0) {
+ case IUU_ONE_STOP_BIT:
+ dataout[DataCount - 1] |= IUU_ONE_STOP_BIT;
+ break;
+
+ case IUU_TWO_STOP_BITS:
+ dataout[DataCount - 1] |= IUU_TWO_STOP_BITS;
+ break;
+ default:
+ kfree(dataout);
+ return IUU_INVALID_PARAMETER;
+ break;
+ }
+
+ status = bulk_immediate(port, dataout, DataCount);
+ if (status != IUU_OPERATION_OK)
+ dbg("%s - uart_off error", __FUNCTION__);
+ kfree(dataout);
+ return status;
+}
+
+static int set_control_lines(struct usb_device *dev, u8 value)
+{
+ return 0;
+}
+
+static void iuu_close(struct usb_serial_port *port, struct file *filp)
+{
+ /* iuu_led (port,255,0,0,0); */
+ struct usb_serial *serial;
+ struct iuu_private *priv = usb_get_serial_port_data(port);
+ unsigned long flags;
+ unsigned int c_cflag;
+
+ serial = port->serial;
+ if (!serial)
+ return;
+
+ dbg("%s - port %d", __FUNCTION__, port->number);
+
+ iuu_uart_off(port);
+ if (serial->dev) {
+ if (port->tty) {
+ c_cflag = port->tty->termios->c_cflag;
+ if (c_cflag & HUPCL) {
+ /* drop DTR and RTS */
+ priv = usb_get_serial_port_data(port);
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->line_control = 0;
+ spin_unlock_irqrestore(&priv->lock, flags);
+ set_control_lines(port->serial->dev, 0);
+ }
+ }
+ /* free writebuf */
+ /* shutdown our urbs */
+ dbg("%s - shutting down urbs", __FUNCTION__);
+ usb_kill_urb(port->write_urb);
+ usb_kill_urb(port->read_urb);
+ usb_kill_urb(port->interrupt_in_urb);
+ msleep(1000);
+ /* wait one second to free all buffers */
+ iuu_led(port, 0, 0, 0xF000, 0xFF);
+ msleep(1000);
+ usb_reset_device(port->serial->dev);
+ }
+}
+
+static int iuu_open(struct usb_serial_port *port, struct file *filp)
+{
+ struct usb_serial *serial = port->serial;
+ u8 *buf;
+ int result;
+ u32 actual;
+ unsigned long flags;
+ struct iuu_private *priv = usb_get_serial_port_data(port);
+
+ dbg("%s - port %d", __FUNCTION__, port->number);
+ usb_clear_halt(serial->dev, port->write_urb->pipe);
+ usb_clear_halt(serial->dev, port->read_urb->pipe);
+
+ buf = kmalloc(10, GFP_KERNEL);
+ if (buf == NULL)
+ return -ENOMEM;
+
+ /* fixup the endpoint buffer size */
+ kfree(port->bulk_out_buffer);
+ port->bulk_out_buffer = kmalloc(512, GFP_KERNEL);
+ port->bulk_out_size = 512;
+ kfree(port->bulk_in_buffer);
+ port->bulk_in_buffer = kmalloc(512, GFP_KERNEL);
+ port->bulk_in_size = 512;
+
+ if (!port->bulk_out_buffer || !port->bulk_in_buffer) {
+ kfree(port->bulk_out_buffer);
+ kfree(port->bulk_in_buffer);
+ kfree(buf);
+ return -ENOMEM;
+ }
+
+ usb_fill_bulk_urb(port->write_urb, port->serial->dev,
+ usb_sndbulkpipe(port->serial->dev,
+ port->bulk_out_endpointAddress),
+ port->bulk_out_buffer, 512,
+ NULL, NULL);
+
+
+ usb_fill_bulk_urb(port->read_urb, port->serial->dev,
+ usb_rcvbulkpipe(port->serial->dev,
+ port->bulk_in_endpointAddress),
+ port->bulk_in_buffer, 512,
+ NULL, NULL);
+
+ /* set the termios structure */
+ spin_lock_irqsave(&priv->lock, flags);
+ if (!priv->termios_initialized) {
+ *(port->tty->termios) = tty_std_termios;
+ port->tty->termios->c_cflag = CLOCAL | CREAD | CS8 | B9600
+ | TIOCM_CTS | CSTOPB | PARENB;
+ port->tty->termios->c_lflag = 0;
+ port->tty->termios->c_oflag = 0;
+ port->tty->termios->c_iflag = 0;
+ priv->termios_initialized = 1;
+ port->tty->low_latency = 1;
+ priv->poll = 0;
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ /* initialize writebuf */
+#define FISH(a, b, c, d) do { \
+ result = usb_control_msg(port->serial->dev, \
+ usb_rcvctrlpipe(port->serial->dev, 0), \
+ b, a, c, d, buf, 1, 1000); \
+ dbg("0x%x:0x%x:0x%x:0x%x %d - %x", a, b, c, d, result, \
+ buf[0]); } while (0);
+
+#define SOUP(a, b, c, d) do { \
+ result = usb_control_msg(port->serial->dev, \
+ usb_sndctrlpipe(port->serial->dev, 0), \
+ b, a, c, d, NULL, 0, 1000); \
+ dbg("0x%x:0x%x:0x%x:0x%x %d", a, b, c, d, result); } while (0)
+
+ /* This is not UART related but IUU USB driver related or something */
+ /* like that. Basically no IUU will accept any commands from the USB */
+ /* host unless it has received the following message */
+ /* sprintf(buf ,"%c%c%c%c",0x03,0x02,0x02,0x0); */
+
+ SOUP(0x03, 0x02, 0x02, 0x0);
+ kfree(buf);
+ iuu_led(port, 0xF000, 0xF000, 0, 0xFF);
+ iuu_uart_on(port);
+ if (boost < 100)
+ boost = 100;
+ switch (clockmode) {
+ case 2: /* 3.680 Mhz */
+ iuu_clk(port, IUU_CLK_3680000 * boost / 100);
+ result =
+ iuu_uart_baud(port, 9600 * boost / 100, &actual,
+ IUU_PARITY_EVEN);
+ break;
+ case 3: /* 6.00 Mhz */
+ iuu_clk(port, IUU_CLK_6000000 * boost / 100);
+ result =
+ iuu_uart_baud(port, 16457 * boost / 100, &actual,
+ IUU_PARITY_EVEN);
+ break;
+ default: /* 3.579 Mhz */
+ iuu_clk(port, IUU_CLK_3579000 * boost / 100);
+ result =
+ iuu_uart_baud(port, 9600 * boost / 100, &actual,
+ IUU_PARITY_EVEN);
+ }
+
+ /* set the cardin cardout signals */
+ switch (cdmode) {
+ case 0:
+ iuu_cardin = 0;
+ iuu_cardout = 0;
+ break;
+ case 1:
+ iuu_cardin = TIOCM_CD;
+ iuu_cardout = 0;
+ break;
+ case 2:
+ iuu_cardin = 0;
+ iuu_cardout = TIOCM_CD;
+ break;
+ case 3:
+ iuu_cardin = TIOCM_DSR;
+ iuu_cardout = 0;
+ break;
+ case 4:
+ iuu_cardin = 0;
+ iuu_cardout = TIOCM_DSR;
+ break;
+ case 5:
+ iuu_cardin = TIOCM_CTS;
+ iuu_cardout = 0;
+ break;
+ case 6:
+ iuu_cardin = 0;
+ iuu_cardout = TIOCM_CTS;
+ break;
+ case 7:
+ iuu_cardin = TIOCM_RNG;
+ iuu_cardout = 0;
+ break;
+ case 8:
+ iuu_cardin = 0;
+ iuu_cardout = TIOCM_RNG;
+ }
+
+ iuu_uart_flush(port);
+
+ dbg("%s - initialization done", __FUNCTION__);
+
+ memset(port->write_urb->transfer_buffer, IUU_UART_RX, 1);
+ usb_fill_bulk_urb(port->write_urb, port->serial->dev,
+ usb_sndbulkpipe(port->serial->dev,
+ port->bulk_out_endpointAddress),
+ port->write_urb->transfer_buffer, 1,
+ read_rxcmd_callback, port);
+ result = usb_submit_urb(port->write_urb, GFP_KERNEL);
+
+ if (result) {
+ dev_err(&port->dev, "%s - failed submitting read urb,"
+ " error %d\n", __FUNCTION__, result);
+ iuu_close(port, NULL);
+ return -EPROTO;
+ } else {
+ dbg("%s - rxcmd OK", __FUNCTION__);
+ }
+ return result;
+}
+
+static struct usb_serial_driver iuu_device = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "iuu_phoenix",
+ },
+ .id_table = id_table,
+ .num_interrupt_in = NUM_DONT_CARE,
+ .num_bulk_in = 1,
+ .num_bulk_out = 1,
+ .num_ports = 1,
+ .open = iuu_open,
+ .close = iuu_close,
+ .write = iuu_uart_write,
+ .read_bulk_callback = iuu_uart_read_callback,
+ .tiocmget = iuu_tiocmget,
+ .tiocmset = iuu_tiocmset,
+ .attach = iuu_startup,
+ .shutdown = iuu_shutdown,
+};
+
+static int __init iuu_init(void)
+{
+ int retval;
+ retval = usb_serial_register(&iuu_device);
+ if (retval)
+ goto failed_usb_serial_register;
+ retval = usb_register(&iuu_driver);
+ if (retval)
+ goto failed_usb_register;
+ info(DRIVER_DESC " " DRIVER_VERSION);
+ return 0;
+failed_usb_register:
+ usb_serial_deregister(&iuu_device);
+failed_usb_serial_register:
+ return retval;
+}
+
+static void __exit iuu_exit(void)
+{
+ usb_deregister(&iuu_driver);
+ usb_serial_deregister(&iuu_device);
+}
+
+module_init(iuu_init);
+module_exit(iuu_exit);
+
+MODULE_AUTHOR("Alain Degreffe eczema@ecze.com");
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+MODULE_VERSION(DRIVER_VERSION);
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+
+module_param(xmas, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(xmas, "xmas color enabled or not");
+
+module_param(boost, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(boost, "overclock boost percent 100 to 500");
+
+module_param(clockmode, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(clockmode, "1=3Mhz579,2=3Mhz680,3=6Mhz");
+
+module_param(cdmode, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(cdmode, "Card detect mode 0=none, 1=CD, 2=!CD, 3=DSR, "
+ "4=!DSR, 5=CTS, 6=!CTS, 7=RING, 8=!RING");
diff --git a/drivers/usb/serial/iuu_phoenix.h b/drivers/usb/serial/iuu_phoenix.h
new file mode 100644
index 00000000000..b82630a3b8f
--- /dev/null
+++ b/drivers/usb/serial/iuu_phoenix.h
@@ -0,0 +1,122 @@
+/*
+ * Infinity Unlimited USB Phoenix driver
+ *
+ * Copyright (C) 2007 Alain Degreffe (eczema@ecze.com)
+ *
+ *
+ * Original code taken from iuutool ( Copyright (C) 2006 Juan Carlos Borrás )
+ *
+ * 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.
+ *
+ * And tested with help of WB Electronics
+ *
+ */
+
+#define IUU_USB_VENDOR_ID 0x104f
+#define IUU_USB_PRODUCT_ID 0x0004
+#define IUU_USB_OP_TIMEOUT 0x0200
+
+/* Programmer commands */
+
+#define IUU_NO_OPERATION 0x00
+#define IUU_GET_FIRMWARE_VERSION 0x01
+#define IUU_GET_PRODUCT_NAME 0x02
+#define IUU_GET_STATE_REGISTER 0x03
+#define IUU_SET_LED 0x04
+#define IUU_WAIT_MUS 0x05
+#define IUU_WAIT_MS 0x06
+#define IUU_GET_LOADER_VERSION 0x50
+#define IUU_RST_SET 0x52
+#define IUU_RST_CLEAR 0x53
+#define IUU_SET_VCC 0x59
+#define IUU_UART_ENABLE 0x49
+#define IUU_UART_DISABLE 0x4A
+#define IUU_UART_WRITE_I2C 0x4C
+#define IUU_UART_ESC 0x5E
+#define IUU_UART_TRAP 0x54
+#define IUU_UART_TRAP_BREAK 0x5B
+#define IUU_UART_RX 0x56
+#define IUU_AVR_ON 0x21
+#define IUU_AVR_OFF 0x22
+#define IUU_AVR_1CLK 0x23
+#define IUU_AVR_RESET 0x24
+#define IUU_AVR_RESET_PC 0x25
+#define IUU_AVR_INC_PC 0x26
+#define IUU_AVR_INCN_PC 0x27
+#define IUU_AVR_PREAD 0x29
+#define IUU_AVR_PREADN 0x2A
+#define IUU_AVR_PWRITE 0x28
+#define IUU_AVR_DREAD 0x2C
+#define IUU_AVR_DREADN 0x2D
+#define IUU_AVR_DWRITE 0x2B
+#define IUU_AVR_PWRITEN 0x2E
+#define IUU_EEPROM_ON 0x37
+#define IUU_EEPROM_OFF 0x38
+#define IUU_EEPROM_WRITE 0x39
+#define IUU_EEPROM_WRITEX 0x3A
+#define IUU_EEPROM_WRITE8 0x3B
+#define IUU_EEPROM_WRITE16 0x3C
+#define IUU_EEPROM_WRITEX32 0x3D
+#define IUU_EEPROM_WRITEX64 0x3E
+#define IUU_EEPROM_READ 0x3F
+#define IUU_EEPROM_READX 0x40
+#define IUU_EEPROM_BREAD 0x41
+#define IUU_EEPROM_BREADX 0x42
+#define IUU_PIC_CMD 0x0A
+#define IUU_PIC_CMD_LOAD 0x0B
+#define IUU_PIC_CMD_READ 0x0C
+#define IUU_PIC_ON 0x0D
+#define IUU_PIC_OFF 0x0E
+#define IUU_PIC_RESET 0x16
+#define IUU_PIC_INC_PC 0x0F
+#define IUU_PIC_INCN_PC 0x10
+#define IUU_PIC_PWRITE 0x11
+#define IUU_PIC_PREAD 0x12
+#define IUU_PIC_PREADN 0x13
+#define IUU_PIC_DWRITE 0x14
+#define IUU_PIC_DREAD 0x15
+#define IUU_UART_NOP 0x00
+#define IUU_UART_CHANGE 0x02
+#define IUU_UART_TX 0x04
+#define IUU_DELAY_MS 0x06
+
+#define IUU_OPERATION_OK 0x00
+#define IUU_DEVICE_NOT_FOUND 0x01
+#define IUU_INVALID_HANDLE 0x02
+#define IUU_INVALID_PARAMETER 0x03
+#define IUU_INVALID_voidERFACE 0x04
+#define IUU_INVALID_REQUEST_LENGTH 0x05
+#define IUU_UART_NOT_ENABLED 0x06
+#define IUU_WRITE_ERROR 0x07
+#define IUU_READ_ERROR 0x08
+#define IUU_TX_ERROR 0x09
+#define IUU_RX_ERROR 0x0A
+
+#define IUU_PARITY_NONE 0x00
+#define IUU_PARITY_EVEN 0x01
+#define IUU_PARITY_ODD 0x02
+#define IUU_PARITY_MARK 0x03
+#define IUU_PARITY_SPACE 0x04
+#define IUU_SC_INSERTED 0x01
+#define IUU_VERIFY_ERROR 0x02
+#define IUU_SIM_INSERTED 0x04
+#define IUU_TWO_STOP_BITS 0x00
+#define IUU_ONE_STOP_BIT 0x20
+#define IUU_BAUD_2400 0x0398
+#define IUU_BAUD_9600 0x0298
+#define IUU_BAUD_19200 0x0164
+#define IUU_BAUD_28800 0x0198
+#define IUU_BAUD_38400 0x01B2
+#define IUU_BAUD_57600 0x0030
+#define IUU_BAUD_115200 0x0098
+#define IUU_CLK_3579000 3579000
+#define IUU_CLK_3680000 3680000
+#define IUU_CLK_6000000 6000000
+#define IUU_FULLCARD_IN 0x01
+#define IUU_DEV_ERROR 0x02
+#define IUU_MINICARD_IN 0x04
+#define IUU_VCC_5V 0x00
+#define IUU_VCC_3V 0x01
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
index 6bfdba6a213..ea7bba69f4d 100644
--- a/drivers/usb/serial/keyspan.c
+++ b/drivers/usb/serial/keyspan.c
@@ -447,7 +447,7 @@ static void usa26_indat_callback(struct urb *urb)
port = (struct usb_serial_port *) urb->context;
tty = port->tty;
- if (urb->actual_length) {
+ if (tty && urb->actual_length) {
/* 0x80 bit is error flag */
if ((data[0] & 0x80) == 0) {
/* no errors on individual bytes, only possible overrun err*/
@@ -838,7 +838,7 @@ static void usa49_indat_callback(struct urb *urb)
port = (struct usb_serial_port *) urb->context;
tty = port->tty;
- if (urb->actual_length) {
+ if (tty && urb->actual_length) {
/* 0x80 bit is error flag */
if ((data[0] & 0x80) == 0) {
/* no error on any byte */
@@ -1227,8 +1227,8 @@ static int keyspan_open (struct usb_serial_port *port, struct file *filp)
s_priv = usb_get_serial_data(serial);
p_priv = usb_get_serial_port_data(port);
d_details = p_priv->device_details;
-
- dbg("%s - port%d.", __FUNCTION__, port->number);
+
+ dbg("%s - port%d.", __FUNCTION__, port->number);
/* Set some sane defaults */
p_priv->rts_state = 1;
@@ -1249,7 +1249,7 @@ static int keyspan_open (struct usb_serial_port *port, struct file *filp)
urb->dev = serial->dev;
/* make sure endpoint data toggle is synchronized with the device */
-
+
usb_clear_halt(urb->dev, urb->pipe);
if ((err = usb_submit_urb(urb, GFP_KERNEL)) != 0) {
@@ -1265,7 +1265,7 @@ static int keyspan_open (struct usb_serial_port *port, struct file *filp)
/* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe), 0); */
}
- /* get the terminal config for the setup message now so we don't
+ /* get the terminal config for the setup message now so we don't
* need to send 2 of them */
cflag = port->tty->termios->c_cflag;
@@ -1274,7 +1274,7 @@ static int keyspan_open (struct usb_serial_port *port, struct file *filp)
/* Baud rate calculation takes baud rate as an integer
so other rates can be generated if desired. */
baud_rate = tty_get_baud_rate(port->tty);
- /* If no match or invalid, leave as default */
+ /* If no match or invalid, leave as default */
if (baud_rate >= 0
&& d_details->calculate_baud_rate(baud_rate, d_details->baudclk,
NULL, NULL, NULL, device_port) == KEYSPAN_BAUD_RATE_OK) {
diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
index be9ac20a8f1..b1fa5a376e9 100644
--- a/drivers/usb/serial/keyspan_pda.c
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -303,7 +303,7 @@ static void keyspan_pda_rx_unthrottle (struct usb_serial_port *port)
}
-static int keyspan_pda_setbaud (struct usb_serial *serial, int baud)
+static speed_t keyspan_pda_setbaud (struct usb_serial *serial, speed_t baud)
{
int rc;
int bindex;
@@ -319,7 +319,9 @@ static int keyspan_pda_setbaud (struct usb_serial *serial, int baud)
case 38400: bindex = 7; break;
case 57600: bindex = 8; break;
case 115200: bindex = 9; break;
- default: return -EINVAL;
+ default:
+ bindex = 5; /* Default to 9600 */
+ baud = 9600;
}
/* rather than figure out how to sleep while waiting for this
@@ -334,7 +336,9 @@ static int keyspan_pda_setbaud (struct usb_serial *serial, int baud)
NULL, /* &data */
0, /* size */
2000); /* timeout */
- return(rc);
+ if (rc < 0)
+ return 0;
+ return baud;
}
@@ -366,7 +370,7 @@ static void keyspan_pda_set_termios (struct usb_serial_port *port,
struct ktermios *old_termios)
{
struct usb_serial *serial = port->serial;
- unsigned int cflag = port->tty->termios->c_cflag;
+ speed_t speed;
/* cflag specifies lots of stuff: number of stop bits, parity, number
of data bits, baud. What can the device actually handle?:
@@ -388,22 +392,18 @@ static void keyspan_pda_set_termios (struct usb_serial_port *port,
For now, just do baud. */
- switch (cflag & CBAUD) {
- /* we could support more values here, just need to calculate
- the necessary divisors in the firmware. <asm/termbits.h>
- has the Bnnn constants. */
- case B110: keyspan_pda_setbaud(serial, 110); break;
- case B300: keyspan_pda_setbaud(serial, 300); break;
- case B1200: keyspan_pda_setbaud(serial, 1200); break;
- case B2400: keyspan_pda_setbaud(serial, 2400); break;
- case B4800: keyspan_pda_setbaud(serial, 4800); break;
- case B9600: keyspan_pda_setbaud(serial, 9600); break;
- case B19200: keyspan_pda_setbaud(serial, 19200); break;
- case B38400: keyspan_pda_setbaud(serial, 38400); break;
- case B57600: keyspan_pda_setbaud(serial, 57600); break;
- case B115200: keyspan_pda_setbaud(serial, 115200); break;
- default: dbg("can't handle requested baud rate"); break;
+ speed = tty_get_baud_rate(port->tty);
+ speed = keyspan_pda_setbaud(serial, speed);
+
+ if (speed == 0) {
+ dbg("can't handle requested baud rate");
+ /* It hasn't changed so.. */
+ speed = tty_termios_baud_rate(old_termios);
}
+ /* Only speed can change so copy the old h/w parameters
+ then encode the new speed */
+ tty_termios_copy_hw(port->tty->termios, old_termios);
+ tty_encode_baud_rate(port->tty, speed, speed);
}
diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c
index 90e3216abd1..55736df7d2f 100644
--- a/drivers/usb/serial/kl5kusb105.c
+++ b/drivers/usb/serial/kl5kusb105.c
@@ -461,17 +461,21 @@ static void klsi_105_close (struct usb_serial_port *port, struct file *filp)
dbg("%s port %d", __FUNCTION__, port->number);
- /* send READ_OFF */
- rc = usb_control_msg (port->serial->dev,
- usb_sndctrlpipe(port->serial->dev, 0),
- KL5KUSB105A_SIO_CONFIGURE,
- USB_TYPE_VENDOR | USB_DIR_OUT,
- KL5KUSB105A_SIO_CONFIGURE_READ_OFF,
- 0, /* index */
- NULL, 0,
- KLSI_TIMEOUT);
- if (rc < 0)
- err("Disabling read failed (error = %d)", rc);
+ mutex_lock(&port->serial->disc_mutex);
+ if (!port->serial->disconnected) {
+ /* send READ_OFF */
+ rc = usb_control_msg (port->serial->dev,
+ usb_sndctrlpipe(port->serial->dev, 0),
+ KL5KUSB105A_SIO_CONFIGURE,
+ USB_TYPE_VENDOR | USB_DIR_OUT,
+ KL5KUSB105A_SIO_CONFIGURE_READ_OFF,
+ 0, /* index */
+ NULL, 0,
+ KLSI_TIMEOUT);
+ if (rc < 0)
+ err("Disabling read failed (error = %d)", rc);
+ }
+ mutex_unlock(&port->serial->disc_mutex);
/* shutdown our bulk reads and writes */
usb_kill_urb(port->write_urb);
diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c
index aee450246bf..17b3baead4a 100644
--- a/drivers/usb/serial/kobil_sct.c
+++ b/drivers/usb/serial/kobil_sct.c
@@ -114,6 +114,7 @@ static struct usb_serial_driver kobil_device = {
.usb_driver = &kobil_driver,
.id_table = id_table,
.num_interrupt_in = NUM_DONT_CARE,
+ .num_interrupt_out = NUM_DONT_CARE,
.num_bulk_in = 0,
.num_bulk_out = 0,
.num_ports = 1,
diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
index 0dc99f75bb0..fc1cea4aba1 100644
--- a/drivers/usb/serial/mct_u232.c
+++ b/drivers/usb/serial/mct_u232.c
@@ -182,10 +182,11 @@ struct mct_u232_private {
/*
* Later day 2.6.0-test kernels have new baud rates like B230400 which
* we do not know how to support. We ignore them for the moment.
- * XXX Rate-limit the error message, it's user triggerable.
*/
-static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value)
+static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value, speed_t *result)
{
+ *result = value;
+
if (le16_to_cpu(serial->dev->descriptor.idProduct) == MCT_U232_SITECOM_PID
|| le16_to_cpu(serial->dev->descriptor.idProduct) == MCT_U232_BELKIN_F5U109_PID) {
switch (value) {
@@ -200,11 +201,13 @@ static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value
case 57600: return 0x0b;
case 115200: return 0x0c;
default:
- err("MCT USB-RS232: unsupported baudrate request 0x%x,"
- " using default of B9600", value);
+ *result = 9600;
return 0x08;
}
} else {
+ /* FIXME: Can we use any divider - should we do
+ divider = 115200/value;
+ real baud = 115200/divider */
switch (value) {
case 300: break;
case 600: break;
@@ -217,9 +220,8 @@ static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value
case 57600: break;
case 115200: break;
default:
- err("MCT USB-RS232: unsupported baudrate request 0x%x,"
- " using default of B9600", value);
value = 9600;
+ *result = 9600;
}
return 115200/value;
}
@@ -232,16 +234,19 @@ static int mct_u232_set_baud_rate(struct usb_serial *serial, struct usb_serial_p
int rc;
unsigned char zero_byte = 0;
unsigned char cts_enable_byte = 0;
+ speed_t speed;
- divisor = cpu_to_le32(mct_u232_calculate_baud_rate(serial, value));
+ divisor = cpu_to_le32(mct_u232_calculate_baud_rate(serial, value, &speed));
rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
MCT_U232_SET_BAUD_RATE_REQUEST,
MCT_U232_SET_REQUEST_TYPE,
0, 0, &divisor, MCT_U232_SET_BAUD_RATE_SIZE,
WDR_TIMEOUT);
- if (rc < 0)
+ if (rc < 0) /*FIXME: What value speed results */
err("Set BAUD RATE %d failed (error = %d)", value, rc);
+ else
+ tty_encode_baud_rate(port->tty, speed, speed);
dbg("set_baud_rate: value: 0x%x, divisor: 0x%x", value, divisor);
/* Mimic the MCT-supplied Windows driver (version 1.21P.0104), which
@@ -482,21 +487,22 @@ error:
static void mct_u232_close (struct usb_serial_port *port, struct file *filp)
{
unsigned int c_cflag;
- unsigned long flags;
unsigned int control_state;
struct mct_u232_private *priv = usb_get_serial_port_data(port);
dbg("%s port %d", __FUNCTION__, port->number);
if (port->tty) {
c_cflag = port->tty->termios->c_cflag;
- if (c_cflag & HUPCL) {
- /* drop DTR and RTS */
- spin_lock_irqsave(&priv->lock, flags);
- priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS);
- control_state = priv->control_state;
- spin_unlock_irqrestore(&priv->lock, flags);
- mct_u232_set_modem_ctrl(port->serial, control_state);
+ mutex_lock(&port->serial->disc_mutex);
+ if (c_cflag & HUPCL && !port->serial->disconnected) {
+ /* drop DTR and RTS */
+ spin_lock_irq(&priv->lock);
+ priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS);
+ control_state = priv->control_state;
+ spin_unlock_irq(&priv->lock);
+ mct_u232_set_modem_ctrl(port->serial, control_state);
}
+ mutex_unlock(&port->serial->disc_mutex);
}
@@ -608,7 +614,8 @@ static void mct_u232_set_termios (struct usb_serial_port *port,
{
struct usb_serial *serial = port->serial;
struct mct_u232_private *priv = usb_get_serial_port_data(port);
- unsigned int cflag = port->tty->termios->c_cflag;
+ struct ktermios *termios = port->tty->termios;
+ unsigned int cflag = termios->c_cflag;
unsigned int old_cflag = old_termios->c_cflag;
unsigned long flags;
unsigned int control_state;
@@ -670,6 +677,8 @@ static void mct_u232_set_termios (struct usb_serial_port *port,
break;
}
+ termios->c_cflag &= ~CMSPAR;
+
/* set the number of stop bits */
last_lcr |= (cflag & CSTOPB) ?
MCT_U232_STOP_BITS_2 : MCT_U232_STOP_BITS_1;
diff --git a/drivers/usb/serial/mct_u232.h b/drivers/usb/serial/mct_u232.h
index aae10c8174d..07b6bec31dc 100644
--- a/drivers/usb/serial/mct_u232.h
+++ b/drivers/usb/serial/mct_u232.h
@@ -79,7 +79,7 @@
* and "Intel solution". They are the regular MCT and "Sitecom" for us.
* This is pointless to document in the header, see the code for the bits.
*/
-static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value);
+static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value, speed_t *result);
/*
* Line Control Register (LCR)
diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c
index e02c198016b..40f3a018880 100644
--- a/drivers/usb/serial/mos7720.c
+++ b/drivers/usb/serial/mos7720.c
@@ -564,22 +564,25 @@ static void mos7720_close(struct usb_serial_port *port, struct file *filp)
}
/* While closing port, shutdown all bulk read, write *
- * and interrupt read if they exists */
- if (serial->dev) {
- dbg("Shutdown bulk write");
- usb_kill_urb(port->write_urb);
- dbg("Shutdown bulk read");
- usb_kill_urb(port->read_urb);
+ * and interrupt read if they exists, otherwise nop */
+ dbg("Shutdown bulk write");
+ usb_kill_urb(port->write_urb);
+ dbg("Shutdown bulk read");
+ usb_kill_urb(port->read_urb);
+
+ mutex_lock(&serial->disc_mutex);
+ /* these commands must not be issued if the device has
+ * been disconnected */
+ if (!serial->disconnected) {
+ data = 0x00;
+ send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor,
+ 0x04, &data);
+
+ data = 0x00;
+ send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor,
+ 0x01, &data);
}
-
- data = 0x00;
- send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor,
- 0x04, &data);
-
- data = 0x00;
- send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor,
- 0x01, &data);
-
+ mutex_unlock(&serial->disc_mutex);
mos7720_port->open = 0;
dbg("Leaving %s", __FUNCTION__);
@@ -1040,11 +1043,6 @@ static void change_port_settings(struct moschip_port *mos7720_port,
tty = mos7720_port->port->tty;
- if ((!tty) || (!tty->termios)) {
- dbg("%s - no tty structures", __FUNCTION__);
- return;
- }
-
dbg("%s: Entering ..........", __FUNCTION__);
lData = UART_LCR_WLEN8;
@@ -1175,7 +1173,10 @@ static void change_port_settings(struct moschip_port *mos7720_port,
dbg("%s - baud rate = %d", __FUNCTION__, baud);
status = send_cmd_write_baud_rate(mos7720_port, baud);
-
+ /* FIXME: needs to write actual resulting baud back not just
+ blindly do so */
+ if (cflag & CBAUD)
+ tty_encode_baud_rate(tty, baud, baud);
/* Enable Interrupts */
data = 0x0c;
send_mos_cmd(serial, MOS_WRITE, port_number, UART_IER, &data);
@@ -1214,10 +1215,6 @@ static void mos7720_set_termios(struct usb_serial_port *port,
tty = port->tty;
- if (!port->tty || !port->tty->termios) {
- dbg("%s - no tty or termios", __FUNCTION__);
- return;
- }
if (!mos7720_port->open) {
dbg("%s - port not opened", __FUNCTION__);
@@ -1228,19 +1225,13 @@ static void mos7720_set_termios(struct usb_serial_port *port,
cflag = tty->termios->c_cflag;
- if (!cflag) {
- printk("%s %s\n",__FUNCTION__,"cflag is NULL");
- return;
- }
-
- dbg("%s - clfag %08x iflag %08x", __FUNCTION__,
+ dbg("%s - cflag %08x iflag %08x", __FUNCTION__,
tty->termios->c_cflag,
RELEVANT_IFLAG(tty->termios->c_iflag));
- if (old_termios)
- dbg("%s - old clfag %08x old iflag %08x", __FUNCTION__,
- old_termios->c_cflag,
- RELEVANT_IFLAG(old_termios->c_iflag));
+ dbg("%s - old cflag %08x old iflag %08x", __FUNCTION__,
+ old_termios->c_cflag,
+ RELEVANT_IFLAG(old_termios->c_iflag));
dbg("%s - port %d", __FUNCTION__, port->number);
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index a5ced7e08cb..869ecd374cb 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -1133,7 +1133,7 @@ static int mos7840_chars_in_buffer(struct usb_serial_port *port)
* This function will block the close until one of the following:
* 1. TX count are 0
* 2. The mos7840 has stopped
- * 3. A timout of 3 seconds without activity has expired
+ * 3. A timeout of 3 seconds without activity has expired
*
************************************************************************/
static void mos7840_block_until_tx_empty(struct moschip_port *mos7840_port)
@@ -1161,7 +1161,7 @@ static void mos7840_block_until_tx_empty(struct moschip_port *mos7840_port)
dbg("%s - TIMEOUT", __FUNCTION__);
return;
} else {
- /* Reset timout value back to seconds */
+ /* Reset timeout value back to seconds */
wait = 30;
}
}
@@ -1275,7 +1275,7 @@ static void mos7840_close(struct usb_serial_port *port, struct file *filp)
*
* This function will block the close until one of the following:
* 1. Response to our Chase comes from mos7840
- * 2. A timout of 10 seconds without activity has expired
+ * 2. A timeout of 10 seconds without activity has expired
* (1K of mos7840 data @ 2400 baud ==> 4 sec to empty)
*
************************************************************************/
@@ -1304,7 +1304,7 @@ static void mos7840_block_until_chase_response(struct moschip_port
dbg("%s - TIMEOUT", __FUNCTION__);
return;
} else {
- /* Reset timout value back to seconds */
+ /* Reset timeout value back to seconds */
wait = 10;
}
}
@@ -2711,7 +2711,7 @@ static int mos7840_startup(struct usb_serial *serial)
status = mos7840_set_reg_sync(serial->port[0], ZLP_REG5, Data);
if (status < 0) {
dbg("Writing ZLP_REG5 failed status-0x%x\n", status);
- return -1;
+ goto error;
} else
dbg("ZLP_REG5 Writing success status%d\n", status);
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 4590124cf88..5e8bf1bc1e5 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -158,8 +158,8 @@ static struct usb_device_id option_ids[] = {
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_KOI_MODEM) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_KOI_NETWORK) },
{ USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) },
- { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220) },
- { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220BIS) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220BIS, 0xff, 0xff, 0xff) },
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x1100) }, /* Novatel Merlin XS620/S640 */
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x1110) }, /* Novatel Merlin S620 */
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x1120) }, /* Novatel Merlin EX720 */
@@ -180,6 +180,7 @@ static struct usb_device_id option_ids[] = {
{ USB_DEVICE(DELL_VENDOR_ID, 0x8117) }, /* Dell Wireless 5700 Mobile Broadband CDMA/EVDO ExpressCard == Novatel Merlin XV620 CDMA/EV-DO */
{ USB_DEVICE(DELL_VENDOR_ID, 0x8118) }, /* Dell Wireless 5510 Mobile Broadband HSDPA ExpressCard == Novatel Merlin XU870 HSDPA/3G */
{ USB_DEVICE(DELL_VENDOR_ID, 0x8128) }, /* Dell Wireless 5700 Mobile Broadband CDMA/EVDO Mini-Card == Novatel Expedite E720 CDMA/EV-DO */
+ { USB_DEVICE(DELL_VENDOR_ID, 0x8136) }, /* Dell Wireless HSDPA 5520 == Novatel Expedite EU860D */
{ USB_DEVICE(DELL_VENDOR_ID, 0x8137) }, /* Dell Wireless HSDPA 5520 */
{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_E100A) },
{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_500A) },
@@ -640,7 +641,10 @@ static void option_close(struct usb_serial_port *port, struct file *filp)
portdata->dtr_state = 0;
if (serial->dev) {
- option_send_setup(port);
+ mutex_lock(&serial->disc_mutex);
+ if (!serial->disconnected)
+ option_send_setup(port);
+ mutex_unlock(&serial->disc_mutex);
/* Stop reading/writing urbs */
for (i = 0; i < N_IN_URB; i++)
diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c
index eea226ae37b..a3847d6c946 100644
--- a/drivers/usb/serial/oti6858.c
+++ b/drivers/usb/serial/oti6858.c
@@ -79,7 +79,7 @@ static int debug;
#define PL2303_BUF_SIZE 1024
#define PL2303_TMP_BUF_SIZE 1024
-struct pl2303_buf {
+struct oti6858_buf {
unsigned int buf_size;
char *buf_buf;
char *buf_get;
@@ -161,14 +161,14 @@ static int oti6858_startup(struct usb_serial *serial);
static void oti6858_shutdown(struct usb_serial *serial);
/* functions operating on buffers */
-static struct pl2303_buf *pl2303_buf_alloc(unsigned int size);
-static void pl2303_buf_free(struct pl2303_buf *pb);
-static void pl2303_buf_clear(struct pl2303_buf *pb);
-static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb);
-static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb);
-static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf,
+static struct oti6858_buf *oti6858_buf_alloc(unsigned int size);
+static void oti6858_buf_free(struct oti6858_buf *pb);
+static void oti6858_buf_clear(struct oti6858_buf *pb);
+static unsigned int oti6858_buf_data_avail(struct oti6858_buf *pb);
+static unsigned int oti6858_buf_space_avail(struct oti6858_buf *pb);
+static unsigned int oti6858_buf_put(struct oti6858_buf *pb, const char *buf,
unsigned int count);
-static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf,
+static unsigned int oti6858_buf_get(struct oti6858_buf *pb, char *buf,
unsigned int count);
@@ -203,7 +203,7 @@ static struct usb_serial_driver oti6858_device = {
struct oti6858_private {
spinlock_t lock;
- struct pl2303_buf *buf;
+ struct oti6858_buf *buf;
struct oti6858_control_pkt status;
struct {
@@ -316,7 +316,7 @@ void send_data(struct work_struct *work)
}
priv->flags.write_urb_in_use = 1;
- count = pl2303_buf_data_avail(priv->buf);
+ count = oti6858_buf_data_avail(priv->buf);
spin_unlock_irqrestore(&priv->lock, flags);
if (count > port->bulk_out_size)
count = port->bulk_out_size;
@@ -345,7 +345,7 @@ void send_data(struct work_struct *work)
}
spin_lock_irqsave(&priv->lock, flags);
- pl2303_buf_get(priv->buf, port->write_urb->transfer_buffer, count);
+ oti6858_buf_get(priv->buf, port->write_urb->transfer_buffer, count);
spin_unlock_irqrestore(&priv->lock, flags);
port->write_urb->transfer_buffer_length = count;
@@ -370,7 +370,7 @@ static int oti6858_startup(struct usb_serial *serial)
priv = kzalloc(sizeof(struct oti6858_private), GFP_KERNEL);
if (!priv)
break;
- priv->buf = pl2303_buf_alloc(PL2303_BUF_SIZE);
+ priv->buf = oti6858_buf_alloc(PL2303_BUF_SIZE);
if (priv->buf == NULL) {
kfree(priv);
break;
@@ -391,7 +391,7 @@ static int oti6858_startup(struct usb_serial *serial)
for (--i; i >= 0; --i) {
priv = usb_get_serial_port_data(serial->port[i]);
- pl2303_buf_free(priv->buf);
+ oti6858_buf_free(priv->buf);
kfree(priv);
usb_set_serial_port_data(serial->port[i], NULL);
}
@@ -410,7 +410,7 @@ static int oti6858_write(struct usb_serial_port *port,
return count;
spin_lock_irqsave(&priv->lock, flags);
- count = pl2303_buf_put(priv->buf, buf, count);
+ count = oti6858_buf_put(priv->buf, buf, count);
spin_unlock_irqrestore(&priv->lock, flags);
return count;
@@ -425,7 +425,7 @@ static int oti6858_write_room(struct usb_serial_port *port)
dbg("%s(port = %d)", __FUNCTION__, port->number);
spin_lock_irqsave(&priv->lock, flags);
- room = pl2303_buf_space_avail(priv->buf);
+ room = oti6858_buf_space_avail(priv->buf);
spin_unlock_irqrestore(&priv->lock, flags);
return room;
@@ -440,7 +440,7 @@ static int oti6858_chars_in_buffer(struct usb_serial_port *port)
dbg("%s(port = %d)", __FUNCTION__, port->number);
spin_lock_irqsave(&priv->lock, flags);
- chars = pl2303_buf_data_avail(priv->buf);
+ chars = oti6858_buf_data_avail(priv->buf);
spin_unlock_irqrestore(&priv->lock, flags);
return chars;
@@ -458,7 +458,7 @@ static void oti6858_set_termios(struct usb_serial_port *port,
dbg("%s(port = %d)", __FUNCTION__, port->number);
- if ((!port->tty) || (!port->tty->termios)) {
+ if (!port->tty || !port->tty->termios) {
dbg("%s(): no tty structures", __FUNCTION__);
return;
}
@@ -468,6 +468,8 @@ static void oti6858_set_termios(struct usb_serial_port *port,
*(port->tty->termios) = tty_std_termios;
port->tty->termios->c_cflag = B38400 | CS8 | CREAD | HUPCL | CLOCAL;
priv->flags.termios_initialized = 1;
+ port->tty->termios->c_ispeed = 38400;
+ port->tty->termios->c_ospeed = 38400;
}
spin_unlock_irqrestore(&priv->lock, flags);
@@ -504,19 +506,14 @@ static void oti6858_set_termios(struct usb_serial_port *port,
br = tty_get_baud_rate(port->tty);
if (br == 0) {
divisor = 0;
- } else if (br <= OTI6858_MAX_BAUD_RATE) {
+ } else {
int real_br;
+ br = min(br, OTI6858_MAX_BAUD_RATE);
divisor = (96000000 + 8 * br) / (16 * br);
real_br = 96000000 / (16 * divisor);
- if ((((real_br - br) * 100 + br - 1) / br) > 2) {
- dbg("%s(): baud rate %d is invalid", __FUNCTION__, br);
- return;
- }
divisor = cpu_to_le16(divisor);
- } else {
- dbg("%s(): baud rate %d is too high", __FUNCTION__, br);
- return;
+ tty_encode_baud_rate(port->tty, real_br, real_br);
}
frame_fmt &= ~FMT_STOP_BITS_MASK;
@@ -650,9 +647,9 @@ static void oti6858_close(struct usb_serial_port *port, struct file *filp)
dbg("%s(): entering wait loop", __FUNCTION__);
for (;;) {
set_current_state(TASK_INTERRUPTIBLE);
- if (pl2303_buf_data_avail(priv->buf) == 0
+ if (oti6858_buf_data_avail(priv->buf) == 0
|| timeout == 0 || signal_pending(current)
- || !usb_get_intfdata(port->serial->interface)) /* disconnect */
+ || port->serial->disconnected)
break;
spin_unlock_irqrestore(&priv->lock, flags);
timeout = schedule_timeout(timeout);
@@ -663,7 +660,7 @@ static void oti6858_close(struct usb_serial_port *port, struct file *filp)
dbg("%s(): after wait loop", __FUNCTION__);
/* clear out any remaining data in the buffer */
- pl2303_buf_clear(priv->buf);
+ oti6858_buf_clear(priv->buf);
spin_unlock_irqrestore(&priv->lock, flags);
/* wait for characters to drain from the device */
@@ -831,21 +828,6 @@ static int oti6858_ioctl(struct usb_serial_port *port, struct file *file,
return -EFAULT;
return oti6858_tiocmset(port, NULL, 0, x);
- case TIOCGSERIAL:
- if (copy_to_user(user_arg, port->tty->termios,
- sizeof(struct ktermios))) {
- return -EFAULT;
- }
- return 0;
-
- case TIOCSSERIAL:
- if (copy_from_user(port->tty->termios, user_arg,
- sizeof(struct ktermios))) {
- return -EFAULT;
- }
- oti6858_set_termios(port, NULL);
- return 0;
-
case TIOCMIWAIT:
dbg("%s(): TIOCMIWAIT", __FUNCTION__);
return wait_modem_info(port, arg);
@@ -887,7 +869,7 @@ static void oti6858_shutdown(struct usb_serial *serial)
for (i = 0; i < serial->num_ports; ++i) {
priv = usb_get_serial_port_data(serial->port[i]);
if (priv) {
- pl2303_buf_free(priv->buf);
+ oti6858_buf_free(priv->buf);
kfree(priv);
usb_set_serial_port_data(serial->port[i], NULL);
}
@@ -987,7 +969,7 @@ static void oti6858_read_int_callback(struct urb *urb)
spin_lock_irqsave(&priv->lock, flags);
if (priv->flags.write_urb_in_use == 0
- && pl2303_buf_data_avail(priv->buf) != 0) {
+ && oti6858_buf_data_avail(priv->buf) != 0) {
schedule_delayed_work(&priv->delayed_write_work,0);
resubmit = 0;
}
@@ -1015,9 +997,8 @@ static void oti6858_read_bulk_callback(struct urb *urb)
struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
unsigned long flags;
- int i, result;
int status = urb->status;
- char tty_flag;
+ int result;
dbg("%s(port = %d, status = %d)",
__FUNCTION__, port->number, status);
@@ -1045,27 +1026,9 @@ static void oti6858_read_bulk_callback(struct urb *urb)
return;
}
- // get tty_flag from status
- tty_flag = TTY_NORMAL;
-
-/* FIXME: probably, errors will be signalled using interrupt pipe! */
-/*
- // break takes precedence over parity,
- // which takes precedence over framing errors
- if (status & UART_BREAK_ERROR )
- tty_flag = TTY_BREAK;
- else if (status & UART_PARITY_ERROR)
- tty_flag = TTY_PARITY;
- else if (status & UART_FRAME_ERROR)
- tty_flag = TTY_FRAME;
- dbg("%s - tty_flag = %d", __FUNCTION__, tty_flag);
-*/
-
tty = port->tty;
if (tty != NULL && urb->actual_length > 0) {
- tty_buffer_request_room(tty, urb->actual_length);
- for (i = 0; i < urb->actual_length; ++i)
- tty_insert_flip_char(tty, data[i], tty_flag);
+ tty_insert_flip_string(tty, data, urb->actual_length);
tty_flip_buffer_push(tty);
}
@@ -1133,18 +1096,18 @@ static void oti6858_write_bulk_callback(struct urb *urb)
/*
- * pl2303_buf_alloc
+ * oti6858_buf_alloc
*
* Allocate a circular buffer and all associated memory.
*/
-static struct pl2303_buf *pl2303_buf_alloc(unsigned int size)
+static struct oti6858_buf *oti6858_buf_alloc(unsigned int size)
{
- struct pl2303_buf *pb;
+ struct oti6858_buf *pb;
if (size == 0)
return NULL;
- pb = kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL);
+ pb = kmalloc(sizeof(struct oti6858_buf), GFP_KERNEL);
if (pb == NULL)
return NULL;
@@ -1161,11 +1124,11 @@ static struct pl2303_buf *pl2303_buf_alloc(unsigned int size)
}
/*
- * pl2303_buf_free
+ * oti6858_buf_free
*
* Free the buffer and all associated memory.
*/
-static void pl2303_buf_free(struct pl2303_buf *pb)
+static void oti6858_buf_free(struct oti6858_buf *pb)
{
if (pb) {
kfree(pb->buf_buf);
@@ -1174,11 +1137,11 @@ static void pl2303_buf_free(struct pl2303_buf *pb)
}
/*
- * pl2303_buf_clear
+ * oti6858_buf_clear
*
* Clear out all data in the circular buffer.
*/
-static void pl2303_buf_clear(struct pl2303_buf *pb)
+static void oti6858_buf_clear(struct oti6858_buf *pb)
{
if (pb != NULL) {
/* equivalent to a get of all data available */
@@ -1187,12 +1150,12 @@ static void pl2303_buf_clear(struct pl2303_buf *pb)
}
/*
- * pl2303_buf_data_avail
+ * oti6858_buf_data_avail
*
* Return the number of bytes of data available in the circular
* buffer.
*/
-static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb)
+static unsigned int oti6858_buf_data_avail(struct oti6858_buf *pb)
{
if (pb == NULL)
return 0;
@@ -1200,12 +1163,12 @@ static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb)
}
/*
- * pl2303_buf_space_avail
+ * oti6858_buf_space_avail
*
* Return the number of bytes of space available in the circular
* buffer.
*/
-static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb)
+static unsigned int oti6858_buf_space_avail(struct oti6858_buf *pb)
{
if (pb == NULL)
return 0;
@@ -1213,14 +1176,14 @@ static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb)
}
/*
- * pl2303_buf_put
+ * oti6858_buf_put
*
* Copy data data from a user buffer and put it into the circular buffer.
* Restrict to the amount of space available.
*
* Return the number of bytes copied.
*/
-static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf,
+static unsigned int oti6858_buf_put(struct oti6858_buf *pb, const char *buf,
unsigned int count)
{
unsigned int len;
@@ -1228,7 +1191,7 @@ static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf,
if (pb == NULL)
return 0;
- len = pl2303_buf_space_avail(pb);
+ len = oti6858_buf_space_avail(pb);
if (count > len)
count = len;
@@ -1252,14 +1215,14 @@ static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf,
}
/*
- * pl2303_buf_get
+ * oti6858_buf_get
*
* Get data from the circular buffer and copy to the given buffer.
* Restrict to the amount of data available.
*
* Return the number of bytes copied.
*/
-static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf,
+static unsigned int oti6858_buf_get(struct oti6858_buf *pb, char *buf,
unsigned int count)
{
unsigned int len;
@@ -1267,7 +1230,7 @@ static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf,
if (pb == NULL)
return 0;
- len = pl2303_buf_data_avail(pb);
+ len = oti6858_buf_data_avail(pb);
if (count > len)
count = len;
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index 2cd3f1d4b68..ae3ec1a6400 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -65,6 +65,7 @@ static struct usb_device_id id_table [] = {
{ USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID_2080) },
{ USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) },
{ USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) },
+ { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_USB60F) },
{ USB_DEVICE(TRIPP_VENDOR_ID, TRIPP_PRODUCT_ID) },
{ USB_DEVICE(RADIOSHACK_VENDOR_ID, RADIOSHACK_PRODUCT_ID) },
{ USB_DEVICE(DCU10_VENDOR_ID, DCU10_PRODUCT_ID) },
@@ -84,8 +85,10 @@ static struct usb_device_id id_table [] = {
{ 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(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_ID) },
{ USB_DEVICE(WS002IN_VENDOR_ID, WS002IN_PRODUCT_ID) },
+ { USB_DEVICE(COREGA_VENDOR_ID, COREGA_PRODUCT_ID) },
+ { USB_DEVICE(HL340_VENDOR_ID, HL340_PRODUCT_ID) },
+ { USB_DEVICE(YCCABLE_VENDOR_ID, YCCABLE_PRODUCT_ID) },
{ } /* Terminating entry */
};
@@ -96,7 +99,10 @@ static struct usb_driver pl2303_driver = {
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table,
+ .suspend = usb_serial_suspend,
+ .resume = usb_serial_resume,
.no_dynamic_id = 1,
+ .supports_autosuspend = 1,
};
#define SET_LINE_REQUEST_TYPE 0x21
@@ -309,12 +315,39 @@ static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf,
return count;
}
+static int pl2303_vendor_read(__u16 value, __u16 index,
+ struct usb_serial *serial, unsigned char *buf)
+{
+ int res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+ VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE,
+ value, index, buf, 1, 100);
+ dbg("0x%x:0x%x:0x%x:0x%x %d - %x", VENDOR_READ_REQUEST_TYPE,
+ VENDOR_READ_REQUEST, value, index, res, buf[0]);
+ return res;
+}
+
+static int pl2303_vendor_write(__u16 value, __u16 index,
+ struct usb_serial *serial)
+{
+ int res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE,
+ value, index, NULL, 0, 100);
+ dbg("0x%x:0x%x:0x%x:0x%x %d", VENDOR_WRITE_REQUEST_TYPE,
+ VENDOR_WRITE_REQUEST, value, index, res);
+ return res;
+}
+
static int pl2303_startup(struct usb_serial *serial)
{
struct pl2303_private *priv;
enum pl2303_type type = type_0;
+ unsigned char *buf;
int i;
+ buf = kmalloc(10, GFP_KERNEL);
+ if (buf == NULL)
+ return -ENOMEM;
+
if (serial->dev->descriptor.bDeviceClass == 0x02)
type = type_0;
else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40)
@@ -339,9 +372,27 @@ static int pl2303_startup(struct usb_serial *serial)
priv->type = type;
usb_set_serial_port_data(serial->port[i], priv);
}
+
+ pl2303_vendor_read(0x8484, 0, serial, buf);
+ pl2303_vendor_write(0x0404, 0, serial);
+ pl2303_vendor_read(0x8484, 0, serial, buf);
+ pl2303_vendor_read(0x8383, 0, serial, buf);
+ pl2303_vendor_read(0x8484, 0, serial, buf);
+ pl2303_vendor_write(0x0404, 1, serial);
+ pl2303_vendor_read(0x8484, 0, serial, buf);
+ pl2303_vendor_read(0x8383, 0, serial, buf);
+ pl2303_vendor_write(0, 1, serial);
+ pl2303_vendor_write(1, 0, serial);
+ if (type == HX)
+ pl2303_vendor_write(2, 0x44, serial);
+ else
+ pl2303_vendor_write(2, 0x24, serial);
+
+ kfree(buf);
return 0;
cleanup:
+ kfree(buf);
for (--i; i>=0; --i) {
priv = usb_get_serial_port_data(serial->port[i]);
pl2303_buf_free(priv->buf);
@@ -482,6 +533,13 @@ static void pl2303_set_termios(struct usb_serial_port *port,
}
spin_unlock_irqrestore(&priv->lock, flags);
+ /* The PL2303 is reported to lose bytes if you change
+ serial settings even to the same values as before. Thus
+ we actually need to filter in this specific case */
+
+ if (!tty_termios_hw_change(port->tty->termios, old_termios))
+ return;
+
cflag = port->tty->termios->c_cflag;
buf = kzalloc(7, GFP_KERNEL);
@@ -574,24 +632,12 @@ static void pl2303_set_termios(struct usb_serial_port *port,
buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
if (cflag & CRTSCTS) {
- __u16 index;
if (priv->type == HX)
- index = 0x61;
+ pl2303_vendor_write(0x0, 0x61, serial);
else
- index = 0x41;
- i = usb_control_msg(serial->dev,
- usb_sndctrlpipe(serial->dev, 0),
- VENDOR_WRITE_REQUEST,
- VENDOR_WRITE_REQUEST_TYPE,
- 0x0, index, NULL, 0, 100);
- dbg("0x40:0x1:0x0:0x%x %d", index, i);
+ pl2303_vendor_write(0x0, 0x41, serial);
} else {
- i = usb_control_msg(serial->dev,
- usb_sndctrlpipe(serial->dev, 0),
- VENDOR_WRITE_REQUEST,
- VENDOR_WRITE_REQUEST_TYPE,
- 0x0, 0x0, NULL, 0, 100);
- dbg ("0x40:0x1:0x0:0x0 %d", i);
+ pl2303_vendor_write(0x0, 0x0, serial);
}
/* FIXME: Need to read back resulting baud rate */
@@ -621,7 +667,7 @@ static void pl2303_close(struct usb_serial_port *port, struct file *filp)
set_current_state(TASK_INTERRUPTIBLE);
if (pl2303_buf_data_avail(priv->buf) == 0 ||
timeout == 0 || signal_pending(current) ||
- !usb_get_intfdata(port->serial->interface)) /* disconnect */
+ port->serial->disconnected)
break;
spin_unlock_irqrestore(&priv->lock, flags);
timeout = schedule_timeout(timeout);
@@ -670,7 +716,6 @@ static int pl2303_open(struct usb_serial_port *port, struct file *filp)
struct ktermios tmp_termios;
struct usb_serial *serial = port->serial;
struct pl2303_private *priv = usb_get_serial_port_data(port);
- unsigned char *buf;
int result;
dbg("%s - port %d", __FUNCTION__, port->number);
@@ -678,45 +723,12 @@ static int pl2303_open(struct usb_serial_port *port, struct file *filp)
if (priv->type != HX) {
usb_clear_halt(serial->dev, port->write_urb->pipe);
usb_clear_halt(serial->dev, port->read_urb->pipe);
- }
-
- buf = kmalloc(10, GFP_KERNEL);
- if (buf==NULL)
- return -ENOMEM;
-
-#define FISH(a,b,c,d) \
- result=usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev,0), \
- b, a, c, d, buf, 1, 100); \
- dbg("0x%x:0x%x:0x%x:0x%x %d - %x",a,b,c,d,result,buf[0]);
-
-#define SOUP(a,b,c,d) \
- result=usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev,0), \
- b, a, c, d, NULL, 0, 100); \
- dbg("0x%x:0x%x:0x%x:0x%x %d",a,b,c,d,result);
-
- FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
- SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0x0404, 0);
- FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
- FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8383, 0);
- FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
- SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0x0404, 1);
- FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0);
- FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8383, 0);
- SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0, 1);
- SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 1, 0);
-
- if (priv->type == HX) {
- /* HX chip */
- SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 2, 0x44);
- /* reset upstream data pipes */
- SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 8, 0);
- SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 9, 0);
} else {
- SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 2, 0x24);
+ /* reset upstream data pipes */
+ pl2303_vendor_write(8, 0, serial);
+ pl2303_vendor_write(9, 0, serial);
}
- kfree(buf);
-
/* Setup termios */
if (port->tty) {
pl2303_set_termios(port, &tmp_termios);
diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h
index ed603e3decd..237a41f6638 100644
--- a/drivers/usb/serial/pl2303.h
+++ b/drivers/usb/serial/pl2303.h
@@ -35,6 +35,7 @@
#define RATOC_VENDOR_ID 0x0584
#define RATOC_PRODUCT_ID 0xb000
+#define RATOC_PRODUCT_ID_USB60F 0xb020
#define TRIPP_VENDOR_ID 0x2478
#define TRIPP_PRODUCT_ID 0x2008
@@ -96,11 +97,18 @@
#define ALCOR_VENDOR_ID 0x058F
#define ALCOR_PRODUCT_ID 0x9720
-/* Huawei E620 UMTS/HSDPA card (ID: 12d1:1001) */
-#define HUAWEI_VENDOR_ID 0x12d1
-#define HUAWEI_PRODUCT_ID 0x1001
-
/* Willcom WS002IN Data Driver (by NetIndex Inc.) */
#define WS002IN_VENDOR_ID 0x11f6
#define WS002IN_PRODUCT_ID 0x2001
+/* Corega CG-USBRS232R Serial Adapter */
+#define COREGA_VENDOR_ID 0x07aa
+#define COREGA_PRODUCT_ID 0x002a
+
+/* HL HL-340 (ID: 4348:5523) */
+#define HL340_VENDOR_ID 0x4348
+#define HL340_PRODUCT_ID 0x5523
+
+/* Y.C. Cable U.S.A., Inc - USB to RS-232 */
+#define YCCABLE_VENDOR_ID 0x05ad
+#define YCCABLE_PRODUCT_ID 0x0fba
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c
index 833f6e1e372..4c925e3e8a6 100644
--- a/drivers/usb/serial/sierra.c
+++ b/drivers/usb/serial/sierra.c
@@ -1,7 +1,7 @@
/*
USB Driver for Sierra Wireless
- Copyright (C) 2006, 2007 Kevin Lloyd <linux@sierrawireless.com>
+ Copyright (C) 2006, 2007, 2008 Kevin Lloyd <linux@sierrawireless.com>
IMPORTANT DISCLAIMER: This driver is not commercially supported by
Sierra Wireless. Use at your own risk.
@@ -14,7 +14,7 @@
Whom based his on the Keyspan driver by Hugh Blemings <hugh@blemings.org>
*/
-#define DRIVER_VERSION "v.1.2.5b"
+#define DRIVER_VERSION "v.1.2.7"
#define DRIVER_AUTHOR "Kevin Lloyd <linux@sierrawireless.com>"
#define DRIVER_DESC "USB Driver for Sierra Wireless USB modems"
@@ -26,10 +26,12 @@
#include <linux/module.h>
#include <linux/usb.h>
#include <linux/usb/serial.h>
+#include <linux/usb/ch9.h>
+#define SWIMS_USB_REQUEST_SetPower 0x00
+#define SWIMS_USB_REQUEST_SetNmea 0x07
#define SWIMS_USB_REQUEST_SetMode 0x0B
-#define SWIMS_USB_REQUEST_TYPE_SetMode 0x40
-#define SWIMS_USB_INDEX_SetMode 0x0000
+#define SWIMS_USB_REQUEST_TYPE_VSC_SET 0x40
#define SWIMS_SET_MODE_Modem 0x0001
/* per port private data */
@@ -38,6 +40,8 @@
#define IN_BUFLEN 4096
static int debug;
+static int nmea;
+static int truinstall = 1;
enum devicetype {
DEVICE_3_PORT = 0,
@@ -50,48 +54,96 @@ static int sierra_set_power_state(struct usb_device *udev, __u16 swiState)
int result;
dev_dbg(&udev->dev, "%s", "SET POWER STATE\n");
result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
- 0x00, /* __u8 request */
- 0x40, /* __u8 request type */
- swiState, /* __u16 value */
- 0, /* __u16 index */
- NULL, /* void *data */
- 0, /* __u16 size */
- USB_CTRL_SET_TIMEOUT); /* int timeout */
+ SWIMS_USB_REQUEST_SetPower, /* __u8 request */
+ SWIMS_USB_REQUEST_TYPE_VSC_SET, /* __u8 request type */
+ swiState, /* __u16 value */
+ 0, /* __u16 index */
+ NULL, /* void *data */
+ 0, /* __u16 size */
+ USB_CTRL_SET_TIMEOUT); /* int timeout */
return result;
}
-static int sierra_set_ms_mode(struct usb_device *udev, __u16 eSocMode)
+static int sierra_set_ms_mode(struct usb_device *udev, __u16 eSWocMode)
{
int result;
dev_dbg(&udev->dev, "%s", "DEVICE MODE SWITCH\n");
result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
SWIMS_USB_REQUEST_SetMode, /* __u8 request */
- SWIMS_USB_REQUEST_TYPE_SetMode, /* __u8 request type */
- eSocMode, /* __u16 value */
- SWIMS_USB_INDEX_SetMode, /* __u16 index */
+ SWIMS_USB_REQUEST_TYPE_VSC_SET, /* __u8 request type */
+ eSWocMode, /* __u16 value */
+ 0x0000, /* __u16 index */
NULL, /* void *data */
0, /* __u16 size */
USB_CTRL_SET_TIMEOUT); /* int timeout */
return result;
}
-static int sierra_probe(struct usb_interface *iface,
- const struct usb_device_id *id)
+static int sierra_vsc_set_nmea(struct usb_device *udev, __u16 enable)
+{
+ int result;
+ dev_dbg(&udev->dev, "%s", "NMEA Enable sent\n");
+ result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ SWIMS_USB_REQUEST_SetNmea, /* __u8 request */
+ SWIMS_USB_REQUEST_TYPE_VSC_SET, /* __u8 request type */
+ enable, /* __u16 value */
+ 0x0000, /* __u16 index */
+ NULL, /* void *data */
+ 0, /* __u16 size */
+ USB_CTRL_SET_TIMEOUT); /* int timeout */
+ return result;
+}
+
+static int sierra_calc_num_ports(struct usb_serial *serial)
{
int result;
+ int *num_ports = usb_get_serial_data(serial);
+
+ result = *num_ports;
+
+ if (result) {
+ kfree(num_ports);
+ usb_set_serial_data(serial, NULL);
+ }
+
+ return result;
+}
+
+static int sierra_probe(struct usb_serial *serial,
+ const struct usb_device_id *id)
+{
+ int result = 0;
struct usb_device *udev;
+ int *num_ports;
+ u8 ifnum;
+
+ num_ports = kmalloc(sizeof(*num_ports), GFP_KERNEL);
+ if (!num_ports)
+ return -ENOMEM;
- udev = usb_get_dev(interface_to_usbdev(iface));
+ ifnum = serial->interface->cur_altsetting->desc.bInterfaceNumber;
+ udev = serial->dev;
/* Check if in installer mode */
- if (id->driver_info == DEVICE_INSTALLER) {
- dev_dbg(&udev->dev, "%s", "FOUND DEVICE(SW)\n");
+ if (truinstall && id->driver_info == DEVICE_INSTALLER) {
+ dev_dbg(&udev->dev, "%s", "FOUND TRU-INSTALL DEVICE(SW)\n");
result = sierra_set_ms_mode(udev, SWIMS_SET_MODE_Modem);
- /*We do not want to bind to the device when in installer mode*/
+ /* Don't bind to the device when in installer mode */
+ kfree(num_ports);
return -EIO;
- }
+ } else if (id->driver_info == DEVICE_1_PORT)
+ *num_ports = 1;
+ else if (ifnum == 0x99)
+ *num_ports = 0;
+ else
+ *num_ports = 3;
+ /*
+ * save off our num_ports info so that we can use it in the
+ * calc_num_ports callback
+ */
+ usb_set_serial_data(serial, (void *)num_ports);
- return usb_serial_probe(iface, id);
+ return result;
}
static struct usb_device_id id_table [] = {
@@ -100,14 +152,17 @@ static struct usb_device_id id_table [] = {
{ USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */
{ USB_DEVICE(0x0f30, 0x1b1d) }, /* Sierra Wireless MC5720 */
{ USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */
+ { USB_DEVICE(0x1199, 0x0220) }, /* Sierra Wireless MC5725 */
{ USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */
{ USB_DEVICE(0x1199, 0x0021) }, /* Sierra Wireless AirCard 597E */
{ USB_DEVICE(0x1199, 0x0120) }, /* Sierra Wireless USB Dongle 595U */
+ { USB_DEVICE(0x1199, 0x0023) }, /* Sierra Wireless AirCard */
{ USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */
{ USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 */
{ USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */
{ USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 & AC 875U */
+ { USB_DEVICE(0x1199, 0x6813) }, /* Sierra Wireless MC8775 (Thinkpad internal) */
{ USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */
{ USB_DEVICE(0x1199, 0x6832) }, /* Sierra Wireless MC8780*/
{ USB_DEVICE(0x1199, 0x6833) }, /* Sierra Wireless MC8781*/
@@ -115,54 +170,29 @@ static struct usb_device_id id_table [] = {
{ USB_DEVICE(0x1199, 0x6851) }, /* Sierra Wireless AirCard 881 */
{ USB_DEVICE(0x1199, 0x6852) }, /* Sierra Wireless AirCard 880 E */
{ USB_DEVICE(0x1199, 0x6853) }, /* Sierra Wireless AirCard 881 E */
+ { USB_DEVICE(0x1199, 0x6855) }, /* Sierra Wireless AirCard 880 U */
+ { USB_DEVICE(0x1199, 0x6856) }, /* Sierra Wireless AirCard 881 U */
+
+ { USB_DEVICE(0x1199, 0x6468) }, /* Sierra Wireless MP3G - EVDO */
+ { USB_DEVICE(0x1199, 0x6469) }, /* Sierra Wireless MP3G - UMTS/HSPA */
{ USB_DEVICE(0x1199, 0x0112), .driver_info = DEVICE_1_PORT }, /* Sierra Wireless AirCard 580 */
{ USB_DEVICE(0x0F3D, 0x0112), .driver_info = DEVICE_1_PORT }, /* Airprime/Sierra PC 5220 */
+ { USB_DEVICE(0x05C6, 0x6613), .driver_info = DEVICE_1_PORT }, /* Onda H600/ZTE MF330 */
{ USB_DEVICE(0x1199, 0x0FFF), .driver_info = DEVICE_INSTALLER},
{ }
};
MODULE_DEVICE_TABLE(usb, id_table);
-static struct usb_device_id id_table_1port [] = {
- { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless AirCard 580 */
- { USB_DEVICE(0x0F3D, 0x0112) }, /* AirPrime/Sierra PC 5220 */
- { }
-};
-
-static struct usb_device_id id_table_3port [] = {
- { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */
- { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */
- { USB_DEVICE(0x0f30, 0x1b1d) }, /* Sierra Wireless MC5720 */
- { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */
- { USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */
- { USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */
- { USB_DEVICE(0x1199, 0x0021) }, /* Sierra Wireless AirCard 597E */
- { USB_DEVICE(0x1199, 0x0120) }, /* Sierra Wireless USB Dongle 595U*/
-
- { USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */
- { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 */
- { USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */
- { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 & AC 875U */
- { USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */
- { USB_DEVICE(0x1199, 0x6832) }, /* Sierra Wireless MC8780*/
- { USB_DEVICE(0x1199, 0x6833) }, /* Sierra Wireless MC8781*/
- { USB_DEVICE(0x1199, 0x6850) }, /* Sierra Wireless AirCard 880 */
- { USB_DEVICE(0x1199, 0x6851) }, /* Sierra Wireless AirCard 881 */
- { USB_DEVICE(0x1199, 0x6852) }, /* Sierra Wireless AirCard 880E */
- { USB_DEVICE(0x1199, 0x6853) }, /* Sierra Wireless AirCard 881E */
- { }
-};
-
static struct usb_driver sierra_driver = {
.name = "sierra",
- .probe = sierra_probe,
+ .probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table,
.no_dynamic_id = 1,
};
-
struct sierra_port_private {
spinlock_t lock; /* lock the structure */
int outstanding_urbs; /* number of out urbs in flight */
@@ -184,6 +214,7 @@ static int sierra_send_setup(struct usb_serial_port *port)
{
struct usb_serial *serial = port->serial;
struct sierra_port_private *portdata;
+ __u16 interface = 0;
dbg("%s", __FUNCTION__);
@@ -196,9 +227,18 @@ static int sierra_send_setup(struct usb_serial_port *port)
if (portdata->rts_state)
val |= 0x02;
+ /* Determine which port is targeted */
+ if (port->bulk_out_endpointAddress == 2)
+ interface = 0;
+ else if (port->bulk_out_endpointAddress == 4)
+ interface = 1;
+ else if (port->bulk_out_endpointAddress == 5)
+ interface = 2;
+
return usb_control_msg(serial->dev,
usb_rcvctrlpipe(serial->dev, 0),
- 0x22,0x21,val,0,NULL,0,USB_CTRL_SET_TIMEOUT);
+ 0x22, 0x21, val, interface,
+ NULL, 0, USB_CTRL_SET_TIMEOUT);
}
return 0;
@@ -557,7 +597,10 @@ static void sierra_close(struct usb_serial_port *port, struct file *filp)
portdata->dtr_state = 0;
if (serial->dev) {
- sierra_send_setup(port);
+ mutex_lock(&serial->disc_mutex);
+ if (!serial->disconnected)
+ sierra_send_setup(port);
+ mutex_unlock(&serial->disc_mutex);
/* Stop reading/writing urbs */
for (i = 0; i < N_IN_URB; i++)
@@ -579,9 +622,13 @@ static int sierra_startup(struct usb_serial *serial)
dbg("%s", __FUNCTION__);
- /*Set Device mode to D0 */
+ /* Set Device mode to D0 */
sierra_set_power_state(serial->dev, 0x0000);
+ /* Check NMEA and set */
+ if (nmea)
+ sierra_vsc_set_nmea(serial->dev, 1);
+
/* Now setup per port private data */
for (i = 0; i < serial->num_ports; i++) {
port = serial->port[i];
@@ -642,47 +689,19 @@ static void sierra_shutdown(struct usb_serial *serial)
}
}
-static struct usb_serial_driver sierra_1port_device = {
+static struct usb_serial_driver sierra_device = {
.driver = {
.owner = THIS_MODULE,
.name = "sierra1",
},
- .description = "Sierra USB modem (1 port)",
- .id_table = id_table_1port,
+ .description = "Sierra USB modem",
+ .id_table = id_table,
.usb_driver = &sierra_driver,
.num_interrupt_in = NUM_DONT_CARE,
- .num_bulk_in = 1,
- .num_bulk_out = 1,
- .num_ports = 1,
- .open = sierra_open,
- .close = sierra_close,
- .write = sierra_write,
- .write_room = sierra_write_room,
- .chars_in_buffer = sierra_chars_in_buffer,
- .throttle = sierra_rx_throttle,
- .unthrottle = sierra_rx_unthrottle,
- .ioctl = sierra_ioctl,
- .set_termios = sierra_set_termios,
- .break_ctl = sierra_break_ctl,
- .tiocmget = sierra_tiocmget,
- .tiocmset = sierra_tiocmset,
- .attach = sierra_startup,
- .shutdown = sierra_shutdown,
- .read_int_callback = sierra_instat_callback,
-};
-
-static struct usb_serial_driver sierra_3port_device = {
- .driver = {
- .owner = THIS_MODULE,
- .name = "sierra3",
- },
- .description = "Sierra USB modem (3 port)",
- .id_table = id_table_3port,
- .usb_driver = &sierra_driver,
- .num_interrupt_in = NUM_DONT_CARE,
- .num_bulk_in = 3,
- .num_bulk_out = 3,
- .num_ports = 3,
+ .num_bulk_in = NUM_DONT_CARE,
+ .num_bulk_out = NUM_DONT_CARE,
+ .calc_num_ports = sierra_calc_num_ports,
+ .probe = sierra_probe,
.open = sierra_open,
.close = sierra_close,
.write = sierra_write,
@@ -704,12 +723,9 @@ static struct usb_serial_driver sierra_3port_device = {
static int __init sierra_init(void)
{
int retval;
- retval = usb_serial_register(&sierra_1port_device);
- if (retval)
- goto failed_1port_device_register;
- retval = usb_serial_register(&sierra_3port_device);
+ retval = usb_serial_register(&sierra_device);
if (retval)
- goto failed_3port_device_register;
+ goto failed_device_register;
retval = usb_register(&sierra_driver);
@@ -721,18 +737,15 @@ static int __init sierra_init(void)
return 0;
failed_driver_register:
- usb_serial_deregister(&sierra_3port_device);
-failed_3port_device_register:
- usb_serial_deregister(&sierra_1port_device);
-failed_1port_device_register:
+ usb_serial_deregister(&sierra_device);
+failed_device_register:
return retval;
}
static void __exit sierra_exit(void)
{
usb_deregister (&sierra_driver);
- usb_serial_deregister(&sierra_1port_device);
- usb_serial_deregister(&sierra_3port_device);
+ usb_serial_deregister(&sierra_device);
}
module_init(sierra_init);
@@ -743,6 +756,12 @@ MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_VERSION(DRIVER_VERSION);
MODULE_LICENSE("GPL");
+module_param(truinstall, bool, 0);
+MODULE_PARM_DESC(truinstall, "TRU-Install support");
+
+module_param(nmea, bool, 0);
+MODULE_PARM_DESC(nmea, "NMEA streaming");
+
#ifdef CONFIG_USB_DEBUG
module_param(debug, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Debug messages");
diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c
index 1f0149495fb..b517f93352e 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.c
+++ b/drivers/usb/serial/ti_usb_3410_5052.c
@@ -80,6 +80,7 @@
#include <linux/ioctl.h>
#include <linux/serial.h>
#include <linux/circ_buf.h>
+#include <linux/mutex.h>
#include <asm/uaccess.h>
#include <asm/semaphore.h>
#include <linux/usb.h>
@@ -139,7 +140,7 @@ struct ti_port {
};
struct ti_device {
- struct semaphore td_open_close_sem;
+ struct mutex td_open_close_lock;
int td_open_port_count;
struct usb_serial *td_serial;
int td_is_3410;
@@ -424,7 +425,7 @@ static int ti_startup(struct usb_serial *serial)
dev_err(&dev->dev, "%s - out of memory\n", __FUNCTION__);
return -ENOMEM;
}
- sema_init(&tdev->td_open_close_sem, 1);
+ mutex_init(&tdev->td_open_close_lock);
tdev->td_serial = serial;
usb_set_serial_data(serial, tdev);
@@ -547,7 +548,7 @@ static int ti_open(struct usb_serial_port *port, struct file *file)
tdev = tport->tp_tdev;
/* only one open on any port on a device at a time */
- if (down_interruptible(&tdev->td_open_close_sem))
+ if (mutex_lock_interruptible(&tdev->td_open_close_lock))
return -ERESTARTSYS;
if (port->tty)
@@ -568,7 +569,7 @@ static int ti_open(struct usb_serial_port *port, struct file *file)
if (!urb) {
dev_err(&port->dev, "%s - no interrupt urb\n", __FUNCTION__);
status = -EINVAL;
- goto up_sem;
+ goto release_lock;
}
urb->complete = ti_interrupt_callback;
urb->context = tdev;
@@ -576,11 +577,11 @@ static int ti_open(struct usb_serial_port *port, struct file *file)
status = usb_submit_urb(urb, GFP_KERNEL);
if (status) {
dev_err(&port->dev, "%s - submit interrupt urb failed, %d\n", __FUNCTION__, status);
- goto up_sem;
+ goto release_lock;
}
}
- ti_set_termios(port, NULL);
+ ti_set_termios(port, port->tty->termios);
dbg("%s - sending TI_OPEN_PORT", __FUNCTION__);
status = ti_command_out_sync(tdev, TI_OPEN_PORT,
@@ -617,7 +618,7 @@ static int ti_open(struct usb_serial_port *port, struct file *file)
usb_clear_halt(dev, port->write_urb->pipe);
usb_clear_halt(dev, port->read_urb->pipe);
- ti_set_termios(port, NULL);
+ ti_set_termios(port, port->tty->termios);
dbg("%s - sending TI_OPEN_PORT (2)", __FUNCTION__);
status = ti_command_out_sync(tdev, TI_OPEN_PORT,
@@ -656,13 +657,13 @@ static int ti_open(struct usb_serial_port *port, struct file *file)
tport->tp_is_open = 1;
++tdev->td_open_port_count;
- goto up_sem;
+ goto release_lock;
unlink_int_urb:
if (tdev->td_open_port_count == 0)
usb_kill_urb(port->serial->port[0]->interrupt_in_urb);
-up_sem:
- up(&tdev->td_open_close_sem);
+release_lock:
+ mutex_unlock(&tdev->td_open_close_lock);
dbg("%s - exit %d", __FUNCTION__, status);
return status;
}
@@ -674,7 +675,7 @@ static void ti_close(struct usb_serial_port *port, struct file *file)
struct ti_port *tport;
int port_number;
int status;
- int do_up;
+ int do_unlock;
dbg("%s - port %d", __FUNCTION__, port->number);
@@ -699,16 +700,16 @@ static void ti_close(struct usb_serial_port *port, struct file *file)
if (status)
dev_err(&port->dev, "%s - cannot send close port command, %d\n" , __FUNCTION__, status);
- /* if down is interrupted, continue anyway */
- do_up = !down_interruptible(&tdev->td_open_close_sem);
+ /* if mutex_lock is interrupted, continue anyway */
+ do_unlock = !mutex_lock_interruptible(&tdev->td_open_close_lock);
--tport->tp_tdev->td_open_port_count;
if (tport->tp_tdev->td_open_port_count <= 0) {
/* last port is closed, shut down interrupt urb */
usb_kill_urb(port->serial->port[0]->interrupt_in_urb);
tport->tp_tdev->td_open_port_count = 0;
}
- if (do_up)
- up(&tdev->td_open_close_sem);
+ if (do_unlock)
+ mutex_unlock(&tdev->td_open_close_lock);
dbg("%s - exit", __FUNCTION__);
}
@@ -896,24 +897,11 @@ static void ti_set_termios(struct usb_serial_port *port,
dbg("%s - port %d", __FUNCTION__, port->number);
- if (!tty || !tty->termios) {
- dbg("%s - no tty or termios", __FUNCTION__);
- return;
- }
-
cflag = tty->termios->c_cflag;
iflag = tty->termios->c_iflag;
- if (old_termios && cflag == old_termios->c_cflag
- && iflag == old_termios->c_iflag) {
- dbg("%s - nothing to change", __FUNCTION__);
- return;
- }
-
- dbg("%s - clfag %08x, iflag %08x", __FUNCTION__, cflag, iflag);
-
- if (old_termios)
- dbg("%s - old clfag %08x, old iflag %08x", __FUNCTION__, old_termios->c_cflag, old_termios->c_iflag);
+ dbg("%s - cflag %08x, iflag %08x", __FUNCTION__, cflag, iflag);
+ dbg("%s - old clfag %08x, old iflag %08x", __FUNCTION__, old_termios->c_cflag, old_termios->c_iflag);
if (tport == NULL)
return;
@@ -947,6 +935,9 @@ static void ti_set_termios(struct usb_serial_port *port,
break;
}
+ /* CMSPAR isn't supported by this driver */
+ tty->termios->c_cflag &= ~CMSPAR;
+
if (cflag & PARENB) {
if (cflag & PARODD) {
config->wFlags |= TI_UART_ENABLE_PARITY_CHECKING;
@@ -989,12 +980,17 @@ static void ti_set_termios(struct usb_serial_port *port,
}
baud = tty_get_baud_rate(tty);
- if (!baud) baud = 9600;
+ if (!baud)
+ baud = 9600;
if (tport->tp_tdev->td_is_3410)
config->wBaudRate = (__u16)((923077 + baud/2) / baud);
else
config->wBaudRate = (__u16)((461538 + baud/2) / baud);
+ /* FIXME: Should calculate resulting baud here and report it back */
+ if ((cflag & CBAUD) != B0)
+ tty_encode_baud_rate(tty, baud, baud);
+
dbg("%s - BaudRate=%d, wBaudRate=%d, wFlags=0x%04X, bDataBits=%d, bParity=%d, bStopBits=%d, cXon=%d, cXoff=%d, bUartMode=%d",
__FUNCTION__, baud, config->wBaudRate, config->wFlags, config->bDataBits, config->bParity, config->bStopBits, config->cXon, config->cXoff, config->bUartMode);
@@ -1497,11 +1493,10 @@ static void ti_drain(struct ti_port *tport, unsigned long timeout, int flush)
struct ti_device *tdev = tport->tp_tdev;
struct usb_serial_port *port = tport->tp_port;
wait_queue_t wait;
- unsigned long flags;
dbg("%s - port %d", __FUNCTION__, port->number);
- spin_lock_irqsave(&tport->tp_lock, flags);
+ spin_lock_irq(&tport->tp_lock);
/* wait for data to drain from the buffer */
tdev->td_urb_error = 0;
@@ -1512,11 +1507,11 @@ static void ti_drain(struct ti_port *tport, unsigned long timeout, int flush)
if (ti_buf_data_avail(tport->tp_write_buf) == 0
|| timeout == 0 || signal_pending(current)
|| tdev->td_urb_error
- || !usb_get_intfdata(port->serial->interface)) /* disconnect */
+ || port->serial->disconnected) /* disconnect */
break;
- spin_unlock_irqrestore(&tport->tp_lock, flags);
+ spin_unlock_irq(&tport->tp_lock);
timeout = schedule_timeout(timeout);
- spin_lock_irqsave(&tport->tp_lock, flags);
+ spin_lock_irq(&tport->tp_lock);
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&tport->tp_write_wait, &wait);
@@ -1525,19 +1520,23 @@ static void ti_drain(struct ti_port *tport, unsigned long timeout, int flush)
if (flush)
ti_buf_clear(tport->tp_write_buf);
- spin_unlock_irqrestore(&tport->tp_lock, flags);
+ spin_unlock_irq(&tport->tp_lock);
+ mutex_lock(&port->serial->disc_mutex);
/* wait for data to drain from the device */
/* wait for empty tx register, plus 20 ms */
timeout += jiffies;
tport->tp_lsr &= ~TI_LSR_TX_EMPTY;
while ((long)(jiffies - timeout) < 0 && !signal_pending(current)
&& !(tport->tp_lsr&TI_LSR_TX_EMPTY) && !tdev->td_urb_error
- && usb_get_intfdata(port->serial->interface)) { /* not disconnected */
+ && !port->serial->disconnected) {
if (ti_get_lsr(tport))
break;
+ mutex_unlock(&port->serial->disc_mutex);
msleep_interruptible(20);
+ mutex_lock(&port->serial->disc_mutex);
}
+ mutex_unlock(&port->serial->disc_mutex);
}
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 497e29a700c..3ce98e8d7bc 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -225,16 +225,21 @@ static int serial_open (struct tty_struct *tty, struct file * filp)
goto bailout_mutex_unlock;
}
+ retval = usb_autopm_get_interface(serial->interface);
+ if (retval)
+ goto bailout_module_put;
/* only call the device specific open if this
* is the first time the port is opened */
retval = serial->type->open(port, filp);
if (retval)
- goto bailout_module_put;
+ goto bailout_interface_put;
}
mutex_unlock(&port->mutex);
return 0;
+bailout_interface_put:
+ usb_autopm_put_interface(serial->interface);
bailout_module_put:
module_put(serial->type->driver.owner);
bailout_mutex_unlock:
@@ -264,17 +269,21 @@ static void serial_close(struct tty_struct *tty, struct file * filp)
}
--port->open_count;
- if (port->open_count == 0) {
+ if (port->open_count == 0)
/* only call the device specific close if this
* port is being closed by the last owner */
port->serial->type->close(port, filp);
+ if (port->open_count == (port->console? 1 : 0)) {
if (port->tty) {
if (port->tty->driver_data)
port->tty->driver_data = NULL;
port->tty = NULL;
}
+ }
+ if (port->open_count == 0) {
+ usb_autopm_put_interface(port->serial->interface);
module_put(port->serial->type->driver.owner);
}
@@ -625,6 +634,7 @@ static struct usb_serial * create_serial (struct usb_device *dev,
serial->type = driver;
serial->interface = interface;
kref_init(&serial->kref);
+ mutex_init(&serial->disc_mutex);
return serial;
}
@@ -1080,20 +1090,22 @@ void usb_serial_disconnect(struct usb_interface *interface)
usb_serial_console_disconnect(serial);
dbg ("%s", __FUNCTION__);
+ mutex_lock(&serial->disc_mutex);
usb_set_intfdata (interface, NULL);
- if (serial) {
- for (i = 0; i < serial->num_ports; ++i) {
- port = serial->port[i];
- if (port) {
- if (port->tty)
- tty_hangup(port->tty);
- kill_traffic(port);
- }
+ /* must set a flag, to signal subdrivers */
+ serial->disconnected = 1;
+ for (i = 0; i < serial->num_ports; ++i) {
+ port = serial->port[i];
+ if (port) {
+ if (port->tty)
+ tty_hangup(port->tty);
+ kill_traffic(port);
}
- /* let the last holder of this object
- * cause it to be cleaned up */
- usb_serial_put(serial);
}
+ /* let the last holder of this object
+ * cause it to be cleaned up */
+ mutex_unlock(&serial->disc_mutex);
+ usb_serial_put(serial);
dev_info(dev, "device disconnected\n");
}
@@ -1103,9 +1115,6 @@ int usb_serial_suspend(struct usb_interface *intf, pm_message_t message)
struct usb_serial_port *port;
int i, r = 0;
- if (!serial) /* device has been disconnected */
- return 0;
-
for (i = 0; i < serial->num_ports; ++i) {
port = serial->port[i];
if (port)
@@ -1253,6 +1262,7 @@ static void fixup_generic(struct usb_serial_driver *device)
set_to_generic_if_null(device, read_bulk_callback);
set_to_generic_if_null(device, write_bulk_callback);
set_to_generic_if_null(device, shutdown);
+ set_to_generic_if_null(device, resume);
}
int usb_serial_register(struct usb_serial_driver *driver) /* must be called with BKL held */
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
index 7ee087fed91..22b3f78a388 100644
--- a/drivers/usb/serial/visor.c
+++ b/drivers/usb/serial/visor.c
@@ -349,16 +349,20 @@ static void visor_close (struct usb_serial_port *port, struct file * filp)
usb_kill_urb(port->read_urb);
usb_kill_urb(port->interrupt_in_urb);
- /* Try to send shutdown message, if the device is gone, this will just fail. */
- transfer_buffer = kmalloc (0x12, GFP_KERNEL);
- if (transfer_buffer) {
- usb_control_msg (port->serial->dev,
- usb_rcvctrlpipe(port->serial->dev, 0),
- VISOR_CLOSE_NOTIFICATION, 0xc2,
- 0x0000, 0x0000,
- transfer_buffer, 0x12, 300);
- kfree (transfer_buffer);
+ mutex_lock(&port->serial->disc_mutex);
+ if (!port->serial->disconnected) {
+ /* Try to send shutdown message, unless the device is gone */
+ transfer_buffer = kmalloc (0x12, GFP_KERNEL);
+ if (transfer_buffer) {
+ usb_control_msg (port->serial->dev,
+ usb_rcvctrlpipe(port->serial->dev, 0),
+ VISOR_CLOSE_NOTIFICATION, 0xc2,
+ 0x0000, 0x0000,
+ transfer_buffer, 0x12, 300);
+ kfree (transfer_buffer);
+ }
}
+ mutex_unlock(&port->serial->disc_mutex);
if (stats)
dev_info(&port->dev, "Bytes In = %d Bytes Out = %d\n",
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
index ee5dd8b5a71..38726ef3132 100644
--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -610,8 +610,7 @@ static int whiteheat_open (struct usb_serial_port *port, struct file *filp)
if (retval)
goto exit;
- if (port->tty)
- port->tty->low_latency = 1;
+ port->tty->low_latency = 1;
/* send an open port command */
retval = firm_open(port);
@@ -659,11 +658,14 @@ static void whiteheat_close(struct usb_serial_port *port, struct file * filp)
struct list_head *tmp2;
dbg("%s - port %d", __FUNCTION__, port->number);
-
+
+ mutex_lock(&port->serial->disc_mutex);
/* filp is NULL when called from usb_serial_disconnect */
- if (filp && (tty_hung_up_p(filp))) {
+ if ((filp && (tty_hung_up_p(filp))) || port->serial->disconnected) {
+ mutex_unlock(&port->serial->disc_mutex);
return;
}
+ mutex_unlock(&port->serial->disc_mutex);
port->tty->closing = 1;