summaryrefslogtreecommitdiffstats
path: root/drivers/usb/serial
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/serial')
-rw-r--r--drivers/usb/serial/Kconfig17
-rw-r--r--drivers/usb/serial/Makefile1
-rw-r--r--drivers/usb/serial/airprime.c7
-rw-r--r--drivers/usb/serial/cp2101.c4
-rw-r--r--drivers/usb/serial/ftdi_sio.c256
-rw-r--r--drivers/usb/serial/ftdi_sio.h11
-rw-r--r--drivers/usb/serial/ipaq.c1
-rw-r--r--drivers/usb/serial/mos7720.c1683
-rw-r--r--drivers/usb/serial/mos7840.c3
-rw-r--r--drivers/usb/serial/sierra.c700
10 files changed, 2514 insertions, 169 deletions
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index 5076b9d9705..2a8dd4cc943 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -54,10 +54,10 @@ config USB_SERIAL_GENERIC
properly.
config USB_SERIAL_AIRCABLE
- tristate "AIRcable USB Bluetooth Dongle Driver (EXPERIMENTAL)"
+ tristate "USB AIRcable Bluetooth Dongle Driver (EXPERIMENTAL)"
depends on USB_SERIAL && EXPERIMENTAL
help
- Say Y here if you want to use AIRcable USB Bluetoot Dongle.
+ Say Y here if you want to use USB AIRcable Bluetooth Dongle.
To compile this driver as a module, choose M here: the module
will be called aircable.
@@ -422,6 +422,16 @@ config USB_SERIAL_MCT_U232
To compile this driver as a module, choose M here: the
module will be called mct_u232.
+config USB_SERIAL_MOS7720
+ tristate "USB Moschip 7720 Single Port Serial Driver"
+ depends on USB_SERIAL
+ ---help---
+ Say Y here if you want to use a USB Serial single port adapter from
+ Moschip Semiconductor Tech.
+
+ To compile this driver as a module, choose M here: the
+ module will be called mos7720.
+
config USB_SERIAL_MOS7840
tristate "USB Moschip 7840/7820 USB Serial Driver"
depends on USB_SERIAL
@@ -527,8 +537,7 @@ config USB_SERIAL_OPTION
The USB bus on these cards is not accessible externally.
Supported devices include (some of?) those made by:
- Option, Huawei, Audiovox, Sierra Wireless, Novatel Wireless, or
- Anydata.
+ Option, Huawei, Audiovox, Novatel Wireless, or Anydata.
To compile this driver as a module, choose M here: the
module will be called option.
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
index 8dce83340e3..a5047dc599b 100644
--- a/drivers/usb/serial/Makefile
+++ b/drivers/usb/serial/Makefile
@@ -34,6 +34,7 @@ obj-$(CONFIG_USB_SERIAL_KEYSPAN_PDA) += keyspan_pda.o
obj-$(CONFIG_USB_SERIAL_KLSI) += kl5kusb105.o
obj-$(CONFIG_USB_SERIAL_KOBIL_SCT) += kobil_sct.o
obj-$(CONFIG_USB_SERIAL_MCT_U232) += mct_u232.o
+obj-$(CONFIG_USB_SERIAL_MOS7720) += mos7720.o
obj-$(CONFIG_USB_SERIAL_MOS7840) += mos7840.o
obj-$(CONFIG_USB_SERIAL_NAVMAN) += navman.o
obj-$(CONFIG_USB_SERIAL_OMNINET) += omninet.o
diff --git a/drivers/usb/serial/airprime.c b/drivers/usb/serial/airprime.c
index 2c19f19b255..7f5d546da39 100644
--- a/drivers/usb/serial/airprime.c
+++ b/drivers/usb/serial/airprime.c
@@ -18,12 +18,8 @@
static struct usb_device_id id_table [] = {
{ USB_DEVICE(0x0c88, 0x17da) }, /* Kyocera Wireless KPC650/Passport */
- { USB_DEVICE(0x0f3d, 0x0112) }, /* AirPrime CDMA Wireless PC Card */
- { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */
- { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */
- { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless Aircard 580 */
- { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */
{ USB_DEVICE(0x1410, 0x1110) }, /* Novatel Wireless Merlin CDMA */
+ { USB_DEVICE(0x1410, 0x1100) }, /* ExpressCard34 Qualcomm 3G CDMA */
{ },
};
MODULE_DEVICE_TABLE(usb, id_table);
@@ -133,6 +129,7 @@ static int airprime_open(struct usb_serial_port *port, struct file *filp)
}
urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb) {
+ kfree(buffer);
dev_err(&port->dev, "%s - no more urbs?\n",
__FUNCTION__);
result = -ENOMEM;
diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c
index 486c7411b9a..f95d42c0d16 100644
--- a/drivers/usb/serial/cp2101.c
+++ b/drivers/usb/serial/cp2101.c
@@ -64,7 +64,11 @@ static struct usb_device_id id_table [] = {
{ USB_DEVICE(0x10C4, 0x80F6) }, /* Suunto sports instrument */
{ USB_DEVICE(0x10C4, 0x813D) }, /* Burnside Telecom Deskmobile */
{ 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, 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(0x16D6, 0x0001) }, /* Jablotron serial interface */
{ } /* Terminating Entry */
};
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index d3dc1a15ec6..c186b4e73c7 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -1,16 +1,16 @@
/*
* USB FTDI SIO driver
*
- * Copyright (C) 1999 - 2001
- * Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 1999 - 2001
+ * Greg Kroah-Hartman (greg@kroah.com)
* Bill Ryder (bryder@sgi.com)
* Copyright (C) 2002
* Kuba Ober (kuba@mareimbrium.org)
*
- * 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.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
@@ -32,7 +32,7 @@
* 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
@@ -69,7 +69,7 @@
* 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.
@@ -77,7 +77,7 @@
*
* (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
+ * 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.
*
@@ -137,17 +137,17 @@
* (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
+ * 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.
@@ -158,7 +158,7 @@
*
* (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.
@@ -179,7 +179,7 @@
* (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.
*
@@ -188,16 +188,16 @@
* 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.
@@ -211,14 +211,14 @@
* 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
*
@@ -226,11 +226,11 @@
* Added module_init and module_exit functions to handle the fact that this
* driver is a loadable module now.
*
- * (04/04/2000) Bill Ryder
+ * (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
+ * (03/30/2000) Bill Ryder
* Implemented lots of ioctls
* Fixed a race condition in write
* Changed some dbg's to errs
@@ -311,6 +311,7 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_ACTZWAVE_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_IRTRANS_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_IPLUS_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_DMX4ALL) },
{ USB_DEVICE(FTDI_VID, FTDI_SIO_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_8U232AM_ALT_PID) },
@@ -444,13 +445,13 @@ static struct usb_device_id id_table_combined [] = {
/* { 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) },
- { USB_DEVICE(FTDI_VID, LINX_FUTURE_1_PID) },
- { USB_DEVICE(FTDI_VID, LINX_FUTURE_2_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_CCSICDU20_0_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_CCSICDU40_1_PID) },
+ { USB_DEVICE(FTDI_VID, LINX_SDMUSBQSS_PID) },
+ { USB_DEVICE(FTDI_VID, LINX_MASTERDEVEL2_PID) },
+ { USB_DEVICE(FTDI_VID, LINX_FUTURE_0_PID) },
+ { USB_DEVICE(FTDI_VID, LINX_FUTURE_1_PID) },
+ { USB_DEVICE(FTDI_VID, LINX_FUTURE_2_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_CCSICDU20_0_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_CCSICDU40_1_PID) },
{ USB_DEVICE(FTDI_VID, INSIDE_ACCESSO) },
{ USB_DEVICE(INTREPID_VID, INTREPID_VALUECAN_PID) },
{ USB_DEVICE(INTREPID_VID, INTREPID_NEOVI_PID) },
@@ -511,6 +512,7 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13M_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13S_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13U_PID) },
+ { USB_DEVICE(ELEKTOR_VID, ELEKTOR_FT323R_PID) },
{ }, /* Optional parameter entry */
{ } /* Terminating entry */
};
@@ -522,7 +524,7 @@ static struct usb_driver ftdi_driver = {
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table_combined,
- .no_dynamic_id = 1,
+ .no_dynamic_id = 1,
};
static const char *ftdi_chip_name[] = {
@@ -548,13 +550,13 @@ struct ftdi_private {
int custom_divisor; /* custom_divisor kludge, this is for baud_base (different from what goes to the chip!) */
__u16 last_set_data_urb_value ;
/* the last data state set - needed for doing a break */
- int write_offset; /* This is the offset in the usb data block to write the serial data -
+ int write_offset; /* This is the offset in the usb data block to write the serial data -
* it is different between devices
*/
int flags; /* some ASYNC_xxxx flags are supported */
unsigned long last_dtr_rts; /* saved modem control outputs */
wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */
- char prev_status, diff_status; /* Used for TIOCMIWAIT */
+ char prev_status, diff_status; /* Used for TIOCMIWAIT */
__u8 rx_flags; /* receive state flags (throttling) */
spinlock_t rx_lock; /* spinlock for receive state */
struct work_struct rx_work;
@@ -721,7 +723,7 @@ static int update_mctrl(struct usb_serial_port *port, unsigned int set, unsigned
urb_value |= FTDI_SIO_SET_RTS_HIGH;
rv = usb_control_msg(port->serial->dev,
usb_sndctrlpipe(port->serial->dev, 0),
- FTDI_SIO_SET_MODEM_CTRL_REQUEST,
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST,
FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
urb_value, priv->interface,
buf, 0, WDR_TIMEOUT);
@@ -768,7 +770,7 @@ static int change_speed(struct usb_serial_port *port)
if (priv->interface) { /* FT2232C */
urb_index = (__u16)((urb_index << 8) | priv->interface);
}
-
+
rv = usb_control_msg(port->serial->dev,
usb_sndctrlpipe(port->serial->dev, 0),
FTDI_SIO_SET_BAUDRATE_REQUEST,
@@ -827,7 +829,7 @@ static __u32 get_ftdi_divisor(struct usb_serial_port * port)
/* 3. Convert baudrate to device-specific divisor */
- if (!baud) baud = 9600;
+ if (!baud) baud = 9600;
switch(priv->chip_type) {
case SIO: /* SIO chip */
switch(baud) {
@@ -843,7 +845,7 @@ static __u32 get_ftdi_divisor(struct usb_serial_port * port)
case 115200: div_value = ftdi_sio_b115200; break;
} /* baud */
if (div_value == 0) {
- dbg("%s - Baudrate (%d) requested is not supported", __FUNCTION__, baud);
+ dbg("%s - Baudrate (%d) requested is not supported", __FUNCTION__, baud);
div_value = ftdi_sio_b9600;
div_okay = 0;
}
@@ -925,7 +927,7 @@ static int set_serial_info(struct usb_serial_port * port, struct serial_struct _
/* Make the changes - these are privileged changes! */
priv->flags = ((priv->flags & ~ASYNC_FLAGS) |
- (new_serial.flags & ASYNC_FLAGS));
+ (new_serial.flags & ASYNC_FLAGS));
priv->custom_divisor = new_serial.custom_divisor;
port->tty->low_latency = (priv->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
@@ -950,7 +952,7 @@ check_and_exit:
(old_priv.custom_divisor != priv->custom_divisor))) {
change_speed(port);
}
-
+
return (0);
} /* set_serial_info */
@@ -1022,18 +1024,18 @@ static ssize_t show_latency_timer(struct device *dev, struct device_attribute *a
struct usb_device *udev;
unsigned short latency = 0;
int rv = 0;
-
+
udev = to_usb_device(dev);
-
+
dbg("%s",__FUNCTION__);
-
+
rv = usb_control_msg(udev,
usb_rcvctrlpipe(udev, 0),
FTDI_SIO_GET_LATENCY_TIMER_REQUEST,
FTDI_SIO_GET_LATENCY_TIMER_REQUEST_TYPE,
- 0, priv->interface,
+ 0, priv->interface,
(char*) &latency, 1, WDR_TIMEOUT);
-
+
if (rv < 0) {
dev_err(dev, "Unable to read latency timer: %i", rv);
return -EIO;
@@ -1051,23 +1053,23 @@ static ssize_t store_latency_timer(struct device *dev, struct device_attribute *
char buf[1];
int v = simple_strtoul(valbuf, NULL, 10);
int rv = 0;
-
+
udev = to_usb_device(dev);
-
+
dbg("%s: setting latency timer = %i", __FUNCTION__, v);
-
+
rv = usb_control_msg(udev,
usb_sndctrlpipe(udev, 0),
FTDI_SIO_SET_LATENCY_TIMER_REQUEST,
FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE,
- v, priv->interface,
+ v, priv->interface,
buf, 0, WDR_TIMEOUT);
-
+
if (rv < 0) {
dev_err(dev, "Unable to write latency timer: %i", rv);
return -EIO;
}
-
+
return count;
}
@@ -1082,23 +1084,23 @@ static ssize_t store_event_char(struct device *dev, struct device_attribute *att
char buf[1];
int v = simple_strtoul(valbuf, NULL, 10);
int rv = 0;
-
+
udev = to_usb_device(dev);
-
+
dbg("%s: setting event char = %i", __FUNCTION__, v);
-
+
rv = usb_control_msg(udev,
usb_sndctrlpipe(udev, 0),
FTDI_SIO_SET_EVENT_CHAR_REQUEST,
FTDI_SIO_SET_EVENT_CHAR_REQUEST_TYPE,
- v, priv->interface,
+ v, priv->interface,
buf, 0, WDR_TIMEOUT);
-
+
if (rv < 0) {
dbg("Unable to write event character: %i", rv);
return -EIO;
}
-
+
return count;
}
@@ -1135,11 +1137,11 @@ static void remove_sysfs_attrs(struct usb_serial *serial)
struct ftdi_private *priv;
struct usb_device *udev;
- dbg("%s",__FUNCTION__);
+ dbg("%s",__FUNCTION__);
priv = usb_get_serial_port_data(serial->port[0]);
udev = serial->dev;
-
+
/* XXX see create_sysfs_attrs */
if (priv->chip_type != SIO) {
device_remove_file(&udev->dev, &dev_attr_event_char);
@@ -1147,7 +1149,7 @@ static void remove_sysfs_attrs(struct usb_serial *serial)
device_remove_file(&udev->dev, &dev_attr_latency_timer);
}
}
-
+
}
/*
@@ -1258,7 +1260,7 @@ static void ftdi_HE_TIRA1_setup (struct usb_serial *serial)
} /* ftdi_HE_TIRA1_setup */
-/* ftdi_shutdown is called from usbserial:usb_serial_disconnect
+/* ftdi_shutdown is called from usbserial:usb_serial_disconnect
* it is called when the usb device is disconnected
*
* usbserial:usb_serial_disconnect
@@ -1269,16 +1271,16 @@ static void ftdi_HE_TIRA1_setup (struct usb_serial *serial)
static void ftdi_shutdown (struct usb_serial *serial)
{ /* ftdi_shutdown */
-
+
struct usb_serial_port *port = serial->port[0];
struct ftdi_private *priv = usb_get_serial_port_data(port);
dbg("%s", __FUNCTION__);
remove_sysfs_attrs(serial);
-
- /* all open ports are closed at this point
- * (by usbserial.c:__serial_close, which calls ftdi_close)
+
+ /* all open ports are closed at this point
+ * (by usbserial.c:__serial_close, which calls ftdi_close)
*/
if (priv) {
@@ -1293,7 +1295,7 @@ static int ftdi_open (struct usb_serial_port *port, struct file *filp)
struct usb_device *dev = port->serial->dev;
struct ftdi_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
-
+
int result = 0;
char buf[1]; /* Needed for the usb_control_msg I think */
@@ -1312,8 +1314,8 @@ static int ftdi_open (struct usb_serial_port *port, struct file *filp)
/* No error checking for this (will get errors later anyway) */
/* See ftdi_sio.h for description of what is reset */
usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE,
- FTDI_SIO_RESET_SIO,
+ FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE,
+ FTDI_SIO_RESET_SIO,
priv->interface, buf, 0, WDR_TIMEOUT);
/* Termios defaults are set by usb_serial_init. We don't change
@@ -1350,12 +1352,12 @@ static int ftdi_open (struct usb_serial_port *port, struct file *filp)
-/*
+/*
* usbserial:__serial_close only calls ftdi_close if the point is open
*
* This only gets called when it is the last close
- *
- *
+ *
+ *
*/
static void ftdi_close (struct usb_serial_port *port, struct file *filp)
@@ -1368,14 +1370,14 @@ static void ftdi_close (struct usb_serial_port *port, struct file *filp)
if (c_cflag & HUPCL){
/* Disable flow control */
- if (usb_control_msg(port->serial->dev,
+ if (usb_control_msg(port->serial->dev,
usb_sndctrlpipe(port->serial->dev, 0),
FTDI_SIO_SET_FLOW_CTRL_REQUEST,
FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
0, priv->interface, buf, 0,
WDR_TIMEOUT) < 0) {
err("error from flowcontrol urb");
- }
+ }
/* drop RTS and DTR */
clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
@@ -1384,14 +1386,14 @@ static void ftdi_close (struct usb_serial_port *port, struct file *filp)
/* cancel any scheduled reading */
cancel_delayed_work(&priv->rx_work);
flush_scheduled_work();
-
+
/* shutdown our bulk read */
if (port->read_urb)
usb_kill_urb(port->read_urb);
} /* ftdi_close */
-
+
/* The SIO requires the first byte to have:
* B0 1
* B1 0
@@ -1423,7 +1425,7 @@ static int ftdi_write (struct usb_serial_port *port,
return 0;
}
spin_unlock_irqrestore(&priv->tx_lock, flags);
-
+
data_offset = priv->write_offset;
dbg("data_offset set to %d",data_offset);
@@ -1462,7 +1464,7 @@ static int ftdi_write (struct usb_serial_port *port,
user_pktsz = todo;
}
/* Write the control byte at the front of the packet*/
- *first_byte = 1 | ((user_pktsz) << 2);
+ *first_byte = 1 | ((user_pktsz) << 2);
/* Copy data for packet */
memcpy (first_byte + data_offset,
current_position, user_pktsz);
@@ -1479,7 +1481,7 @@ static int ftdi_write (struct usb_serial_port *port,
usb_serial_debug_data(debug, &port->dev, __FUNCTION__, transfer_size, buffer);
/* fill the buffer and send it */
- usb_fill_bulk_urb(urb, port->serial->dev,
+ usb_fill_bulk_urb(urb, port->serial->dev,
usb_sndbulkpipe(port->serial->dev, port->bulk_out_endpointAddress),
buffer, transfer_size,
ftdi_write_bulk_callback, port);
@@ -1520,7 +1522,7 @@ static void ftdi_write_bulk_callback (struct urb *urb)
kfree (urb->transfer_buffer);
dbg("%s - port %d", __FUNCTION__, port->number);
-
+
if (urb->status) {
dbg("nonzero write bulk status received: %d", urb->status);
return;
@@ -1651,7 +1653,7 @@ static void ftdi_process_read (void *param)
struct tty_struct *tty;
struct ftdi_private *priv;
char error_flag;
- unsigned char *data;
+ unsigned char *data;
int i;
int result;
@@ -1759,7 +1761,7 @@ static void ftdi_process_read (void *param)
}
if (length > 0) {
for (i = 2; i < length+2; i++) {
- /* Note that the error flag is duplicated for
+ /* Note that the error flag is duplicated for
every character received since we don't know
which character it applied to */
tty_insert_flip_char(tty, data[packet_offset+i], error_flag);
@@ -1773,7 +1775,7 @@ static void ftdi_process_read (void *param)
This doesn't work well since the application receives a never
ending stream of bad data - even though new data hasn't been sent.
Therefore I (bill) have taken this out.
- However - this might make sense for framing errors and so on
+ However - this might make sense for framing errors and so on
so I am leaving the code in for now.
*/
else {
@@ -1827,7 +1829,7 @@ static void ftdi_process_read (void *param)
/* if the port is closed stop trying to read */
if (port->open_count > 0){
/* Continue trying to always read */
- usb_fill_bulk_urb(port->read_urb, port->serial->dev,
+ usb_fill_bulk_urb(port->read_urb, port->serial->dev,
usb_rcvbulkpipe(port->serial->dev, port->bulk_in_endpointAddress),
port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
ftdi_read_bulk_callback, port);
@@ -1844,9 +1846,9 @@ static void ftdi_process_read (void *param)
static void ftdi_break_ctl( struct usb_serial_port *port, int break_state )
{
struct ftdi_private *priv = usb_get_serial_port_data(port);
- __u16 urb_value = 0;
+ __u16 urb_value = 0;
char buf[1];
-
+
/* break_state = -1 to turn on break, and 0 to turn off break */
/* see drivers/char/tty_io.c to see it used */
/* last_set_data_urb_value NEVER has the break bit set in it */
@@ -1854,20 +1856,20 @@ static void ftdi_break_ctl( struct usb_serial_port *port, int break_state )
if (break_state) {
urb_value = priv->last_set_data_urb_value | FTDI_SIO_SET_BREAK;
} else {
- urb_value = priv->last_set_data_urb_value;
+ urb_value = priv->last_set_data_urb_value;
}
-
+
if (usb_control_msg(port->serial->dev, usb_sndctrlpipe(port->serial->dev, 0),
- FTDI_SIO_SET_DATA_REQUEST,
+ FTDI_SIO_SET_DATA_REQUEST,
FTDI_SIO_SET_DATA_REQUEST_TYPE,
urb_value , priv->interface,
buf, 0, WDR_TIMEOUT) < 0) {
err("%s FAILED to enable/disable break state (state was %d)", __FUNCTION__,break_state);
- }
+ }
dbg("%s break state is %d - urb is %d", __FUNCTION__,break_state, urb_value);
-
+
}
@@ -1883,12 +1885,12 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_
struct ftdi_private *priv = usb_get_serial_port_data(port);
__u16 urb_value; /* will hold the new flags */
char buf[1]; /* Perhaps I should dynamically alloc this? */
-
+
// Added for xon/xoff support
unsigned int iflag = port->tty->termios->c_iflag;
unsigned char vstop;
unsigned char vstart;
-
+
dbg("%s", __FUNCTION__);
/* Force baud rate if this device requires it, unless it is set to B0. */
@@ -1906,20 +1908,20 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_
cflag = port->tty->termios->c_cflag;
- /* FIXME -For this cut I don't care if the line is really changing or
- not - so just do the change regardless - should be able to
+ /* FIXME -For this cut I don't care if the line is really changing or
+ not - so just do the change regardless - should be able to
compare old_termios and tty->termios */
- /* NOTE These routines can get interrupted by
- ftdi_sio_read_bulk_callback - need to examine what this
+ /* NOTE These routines can get interrupted by
+ ftdi_sio_read_bulk_callback - need to examine what this
means - don't see any problems yet */
-
+
/* Set number of data bits, parity, stop bits */
-
+
urb_value = 0;
urb_value |= (cflag & CSTOPB ? FTDI_SIO_SET_DATA_STOP_BITS_2 :
FTDI_SIO_SET_DATA_STOP_BITS_1);
- urb_value |= (cflag & PARENB ?
- (cflag & PARODD ? FTDI_SIO_SET_DATA_PARITY_ODD :
+ urb_value |= (cflag & PARENB ?
+ (cflag & PARODD ? FTDI_SIO_SET_DATA_PARITY_ODD :
FTDI_SIO_SET_DATA_PARITY_EVEN) :
FTDI_SIO_SET_DATA_PARITY_NONE);
if (cflag & CSIZE) {
@@ -1936,25 +1938,25 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_
/* This is needed by the break command since it uses the same command - but is
* or'ed with this value */
priv->last_set_data_urb_value = urb_value;
-
+
if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- FTDI_SIO_SET_DATA_REQUEST,
+ FTDI_SIO_SET_DATA_REQUEST,
FTDI_SIO_SET_DATA_REQUEST_TYPE,
urb_value , priv->interface,
buf, 0, WDR_SHORT_TIMEOUT) < 0) {
err("%s FAILED to set databits/stopbits/parity", __FUNCTION__);
- }
+ }
/* Now do the baudrate */
if ((cflag & CBAUD) == B0 ) {
/* Disable flow control */
if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- FTDI_SIO_SET_FLOW_CTRL_REQUEST,
+ FTDI_SIO_SET_FLOW_CTRL_REQUEST,
FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
- 0, priv->interface,
+ 0, priv->interface,
buf, 0, WDR_TIMEOUT) < 0) {
err("%s error from disable flowcontrol urb", __FUNCTION__);
- }
+ }
/* Drop RTS and DTR */
clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
} else {
@@ -1972,16 +1974,16 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_
/* Note device also supports DTR/CD (ugh) and Xon/Xoff in hardware */
if (cflag & CRTSCTS) {
dbg("%s Setting to CRTSCTS flow control", __FUNCTION__);
- if (usb_control_msg(dev,
+ if (usb_control_msg(dev,
usb_sndctrlpipe(dev, 0),
- FTDI_SIO_SET_FLOW_CTRL_REQUEST,
+ FTDI_SIO_SET_FLOW_CTRL_REQUEST,
FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
0 , (FTDI_SIO_RTS_CTS_HS | priv->interface),
buf, 0, WDR_TIMEOUT) < 0) {
err("urb failed to set to rts/cts flow control");
- }
-
- } else {
+ }
+
+ } else {
/*
* Xon/Xoff code
*
@@ -2011,16 +2013,16 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_
/* else clause to only run if cfag ! CRTSCTS and iflag ! XOFF */
/* CHECKME Assuming XON/XOFF handled by tty stack - not by device */
dbg("%s Turning off hardware flow control", __FUNCTION__);
- if (usb_control_msg(dev,
+ if (usb_control_msg(dev,
usb_sndctrlpipe(dev, 0),
- FTDI_SIO_SET_FLOW_CTRL_REQUEST,
+ FTDI_SIO_SET_FLOW_CTRL_REQUEST,
FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
- 0, priv->interface,
+ 0, priv->interface,
buf, 0, WDR_TIMEOUT) < 0) {
err("urb failed to clear flow control");
- }
+ }
}
-
+
}
return;
} /* ftdi_termios */
@@ -2036,11 +2038,11 @@ static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file)
switch (priv->chip_type) {
case SIO:
/* Request the status from the device */
- if ((ret = usb_control_msg(port->serial->dev,
+ if ((ret = usb_control_msg(port->serial->dev,
usb_rcvctrlpipe(port->serial->dev, 0),
- FTDI_SIO_GET_MODEM_STATUS_REQUEST,
+ FTDI_SIO_GET_MODEM_STATUS_REQUEST,
FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE,
- 0, 0,
+ 0, 0,
buf, 1, WDR_TIMEOUT)) < 0 ) {
err("%s Could not get modem status of device - err: %d", __FUNCTION__,
ret);
@@ -2052,11 +2054,11 @@ static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file)
case FT2232C:
/* the 8U232AM returns a two byte value (the sio is a 1 byte value) - in the same
format as the data returned from the in point */
- if ((ret = usb_control_msg(port->serial->dev,
+ if ((ret = usb_control_msg(port->serial->dev,
usb_rcvctrlpipe(port->serial->dev, 0),
- FTDI_SIO_GET_MODEM_STATUS_REQUEST,
+ FTDI_SIO_GET_MODEM_STATUS_REQUEST,
FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE,
- 0, priv->interface,
+ 0, priv->interface,
buf, 2, WDR_TIMEOUT)) < 0 ) {
err("%s Could not get modem status of device - err: %d", __FUNCTION__,
ret);
@@ -2067,12 +2069,12 @@ static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file)
return -EFAULT;
break;
}
-
+
return (buf[0] & FTDI_SIO_DSR_MASK ? TIOCM_DSR : 0) |
(buf[0] & FTDI_SIO_CTS_MASK ? TIOCM_CTS : 0) |
(buf[0] & FTDI_SIO_RI_MASK ? TIOCM_RI : 0) |
(buf[0] & FTDI_SIO_RLSD_MASK ? TIOCM_CD : 0) |
- priv->last_dtr_rts;
+ priv->last_dtr_rts;
}
static int ftdi_tiocmset(struct usb_serial_port *port, struct file * file, unsigned int set, unsigned int clear)
@@ -2138,11 +2140,11 @@ static int ftdi_ioctl (struct usb_serial_port *port, struct file * file, unsigne
break;
default:
break;
-
+
}
- /* This is not necessarily an error - turns out the higher layers will do
+ /* This is not necessarily an error - turns out the higher layers will do
* some ioctls itself (see comment above)
*/
dbg("%s arg not supported - it was 0x%04x - check /usr/include/asm/ioctls.h", __FUNCTION__, cmd);
@@ -2199,7 +2201,7 @@ static int __init ftdi_init (void)
if (retval)
goto failed_sio_register;
retval = usb_register(&ftdi_driver);
- if (retval)
+ if (retval)
goto failed_usb_register;
info(DRIVER_VERSION ":" DRIVER_DESC);
diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
index f0edb87d2dd..bae117d359a 100644
--- a/drivers/usb/serial/ftdi_sio.h
+++ b/drivers/usb/serial/ftdi_sio.h
@@ -55,6 +55,9 @@
/* iPlus device */
#define FTDI_IPLUS_PID 0xD070 /* Product Id */
+/* DMX4ALL DMX Interfaces */
+#define FTDI_DMX4ALL 0xC850
+
/* www.crystalfontz.com devices - thanx for providing free devices for evaluation ! */
/* they use the ftdi chipset for the USB interface and the vendor id is the same */
#define FTDI_XF_632_PID 0xFC08 /* 632: 16x2 Character Display */
@@ -175,9 +178,15 @@
#define FTDI_ASK_RDR400_PID 0xC991 /* ASK RDR 400 series card reader */
/*
+ * FTDI USB UART chips used in construction projects from the
+ * Elektor Electronics magazine (http://elektor-electronics.co.uk)
+ */
+#define ELEKTOR_VID 0x0C7D
+#define ELEKTOR_FT323R_PID 0x0005 /* RFID-Reader, issue 09-2006 */
+
+/*
* DSS-20 Sync Station for Sony Ericsson P800
*/
-
#define FTDI_DSS20_PID 0xFC82
/*
diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c
index 6238aff1e77..d72cf8bc7f7 100644
--- a/drivers/usb/serial/ipaq.c
+++ b/drivers/usb/serial/ipaq.c
@@ -320,6 +320,7 @@ static struct usb_device_id ipaq_id_table [] = {
{ USB_DEVICE(0x0B05, 0x9200) }, /* ASUS USB Sync */
{ USB_DEVICE(0x0B05, 0x9202) }, /* ASUS USB Sync */
{ USB_DEVICE(0x0BB4, 0x00CE) }, /* HTC USB Sync */
+ { USB_DEVICE(0x0BB4, 0x00CF) }, /* HTC USB Modem */
{ USB_DEVICE(0x0BB4, 0x0A01) }, /* PocketPC USB Sync */
{ USB_DEVICE(0x0BB4, 0x0A02) }, /* PocketPC USB Sync */
{ USB_DEVICE(0x0BB4, 0x0A03) }, /* PocketPC USB Sync */
diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c
new file mode 100644
index 00000000000..82cd15b894b
--- /dev/null
+++ b/drivers/usb/serial/mos7720.c
@@ -0,0 +1,1683 @@
+/*
+ * mos7720.c
+ * Controls the Moschip 7720 usb to dual port serial convertor
+ *
+ * Copyright 2006 Moschip Semiconductor Tech. Ltd.
+ *
+ * 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, version 2 of the License.
+ *
+ * Developed by:
+ * VijayaKumar.G.N. <vijaykumar@aspirecom.net>
+ * AjayKumar <ajay@aspirecom.net>
+ * Gurudeva.N. <gurudev@aspirecom.net>
+ *
+ * Cleaned up from the original by:
+ * Greg Kroah-Hartman <gregkh@suse.de>
+ *
+ * Originally based on drivers/usb/serial/io_edgeport.c which is:
+ * Copyright (C) 2000 Inside Out Networks, All rights reserved.
+ * Copyright (C) 2001-2002 Greg Kroah-Hartman <greg@kroah.com>
+ */
+#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/module.h>
+#include <linux/spinlock.h>
+#include <linux/serial.h>
+#include <linux/serial_reg.h>
+#include <linux/usb.h>
+#include <linux/usb/serial.h>
+#include <asm/uaccess.h>
+
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "1.0.0.4F"
+#define DRIVER_AUTHOR "Aspire Communications pvt Ltd."
+#define DRIVER_DESC "Moschip USB Serial Driver"
+
+/* default urb timeout */
+#define MOS_WDR_TIMEOUT (HZ * 5)
+
+#define MOS_PORT1 0x0200
+#define MOS_PORT2 0x0300
+#define MOS_VENREG 0x0000
+#define MOS_MAX_PORT 0x02
+#define MOS_WRITE 0x0E
+#define MOS_READ 0x0D
+
+/* Interrupt Rotinue Defines */
+#define SERIAL_IIR_RLS 0x06
+#define SERIAL_IIR_RDA 0x04
+#define SERIAL_IIR_CTI 0x0c
+#define SERIAL_IIR_THR 0x02
+#define SERIAL_IIR_MS 0x00
+
+#define NUM_URBS 16 /* URB Count */
+#define URB_TRANSFER_BUFFER_SIZE 32 /* URB Size */
+
+/* This structure holds all of the local port information */
+struct moschip_port
+{
+ __u8 shadowLCR; /* last LCR value received */
+ __u8 shadowMCR; /* last MCR value received */
+ __u8 shadowMSR; /* last MSR value received */
+ char open;
+ struct async_icount icount;
+ struct usb_serial_port *port; /* loop back to the owner */
+ struct urb *write_urb_pool[NUM_URBS];
+};
+
+/* This structure holds all of the individual serial device information */
+struct moschip_serial
+{
+ int interrupt_started;
+};
+
+static int debug;
+
+#define USB_VENDOR_ID_MOSCHIP 0x9710
+#define MOSCHIP_DEVICE_ID_7720 0x7720
+#define MOSCHIP_DEVICE_ID_7715 0x7715
+
+static struct usb_device_id moschip_port_id_table [] = {
+ { USB_DEVICE(USB_VENDOR_ID_MOSCHIP,MOSCHIP_DEVICE_ID_7720) },
+ { } /* terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, moschip_port_id_table);
+
+
+/*
+ * mos7720_interrupt_callback
+ * this is the callback function for when we have received data on the
+ * interrupt endpoint.
+ */
+static void mos7720_interrupt_callback(struct urb *urb)
+{
+ int result;
+ int length;
+ __u32 *data;
+ unsigned int status;
+ __u8 sp1;
+ __u8 sp2;
+ __u8 st;
+
+ dbg("%s"," : Entering\n");
+
+ if (!urb) {
+ dbg("%s","Invalid Pointer !!!!:\n");
+ return;
+ }
+
+ switch (urb->status) {
+ case 0:
+ /* success */
+ break;
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ /* this urb is terminated, clean up */
+ dbg("%s - urb shutting down with status: %d", __FUNCTION__,
+ urb->status);
+ return;
+ default:
+ dbg("%s - nonzero urb status received: %d", __FUNCTION__,
+ urb->status);
+ goto exit;
+ }
+
+ length = urb->actual_length;
+ data = urb->transfer_buffer;
+
+ /* Moschip get 4 bytes
+ * Byte 1 IIR Port 1 (port.number is 0)
+ * Byte 2 IIR Port 2 (port.number is 1)
+ * Byte 3 --------------
+ * Byte 4 FIFO status for both */
+ if (length && length > 4) {
+ dbg("Wrong data !!!");
+ return;
+ }
+
+ status = *data;
+
+ sp1 = (status & 0xff000000)>>24;
+ sp2 = (status & 0x00ff0000)>>16;
+ st = status & 0x000000ff;
+
+ if ((sp1 & 0x01) || (sp2 & 0x01)) {
+ /* No Interrupt Pending in both the ports */
+ dbg("No Interrupt !!!");
+ } else {
+ switch (sp1 & 0x0f) {
+ case SERIAL_IIR_RLS:
+ dbg("Serial Port 1: Receiver status error or address "
+ "bit detected in 9-bit mode\n");
+ break;
+ case SERIAL_IIR_CTI:
+ dbg("Serial Port 1: Receiver time out");
+ break;
+ case SERIAL_IIR_MS:
+ dbg("Serial Port 1: Modem status change");
+ break;
+ }
+
+ switch (sp2 & 0x0f) {
+ case SERIAL_IIR_RLS:
+ dbg("Serial Port 2: Receiver status error or address "
+ "bit detected in 9-bit mode");
+ break;
+ case SERIAL_IIR_CTI:
+ dbg("Serial Port 2: Receiver time out");
+ break;
+ case SERIAL_IIR_MS:
+ dbg("Serial Port 2: Modem status change");
+ break;
+ }
+ }
+
+exit:
+ result = usb_submit_urb(urb, GFP_ATOMIC);
+ if (result)
+ dev_err(&urb->dev->dev,
+ "%s - Error %d submitting control urb\n",
+ __FUNCTION__, result);
+ return;
+}
+
+/*
+ * mos7720_bulk_in_callback
+ * this is the callback function for when we have received data on the
+ * bulk in endpoint.
+ */
+static void mos7720_bulk_in_callback(struct urb *urb)
+{
+ int status;
+ unsigned char *data ;
+ struct usb_serial_port *port;
+ struct moschip_port *mos7720_port;
+ struct tty_struct *tty;
+
+ if (urb->status) {
+ dbg("nonzero read bulk status received: %d",urb->status);
+ return;
+ }
+
+ mos7720_port = urb->context;
+ if (!mos7720_port) {
+ dbg("%s","NULL mos7720_port pointer \n");
+ return ;
+ }
+
+ port = mos7720_port->port;
+
+ dbg("Entering...%s", __FUNCTION__);
+
+ data = urb->transfer_buffer;
+
+ tty = port->tty;
+ if (tty && urb->actual_length) {
+ tty_buffer_request_room(tty, urb->actual_length);
+ tty_insert_flip_string(tty, data, urb->actual_length);
+ tty_flip_buffer_push(tty);
+ }
+
+ if (!port->read_urb) {
+ dbg("URB KILLED !!!");
+ return;
+ }
+
+ if (port->read_urb->status != -EINPROGRESS) {
+ port->read_urb->dev = port->serial->dev;
+
+ status = usb_submit_urb(port->read_urb, GFP_ATOMIC);
+ if (status)
+ dbg("usb_submit_urb(read bulk) failed, status = %d",
+ status);
+ }
+}
+
+/*
+ * mos7720_bulk_out_data_callback
+ * this is the callback function for when we have finished sending serial
+ * data on the bulk out endpoint.
+ */
+static void mos7720_bulk_out_data_callback(struct urb *urb)
+{
+ struct moschip_port *mos7720_port;
+ struct tty_struct *tty;
+
+ if (urb->status) {
+ dbg("nonzero write bulk status received:%d", urb->status);
+ return;
+ }
+
+ mos7720_port = urb->context;
+ if (!mos7720_port) {
+ dbg("NULL mos7720_port pointer");
+ return ;
+ }
+
+ dbg("Entering .........");
+
+ tty = mos7720_port->port->tty;
+
+ if (tty && mos7720_port->open) {
+ /* let the tty driver wakeup if it has a special *
+ * write_wakeup function */
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+ tty->ldisc.write_wakeup)
+ (tty->ldisc.write_wakeup)(tty);
+
+ /* tell the tty driver that something has changed */
+ wake_up_interruptible(&tty->write_wait);
+ }
+
+ /* schedule_work(&mos7720_port->port->work); */
+}
+
+/*
+ * send_mos_cmd
+ * this function will be used for sending command to device
+ */
+static int send_mos_cmd(struct usb_serial *serial, __u8 request, __u16 value,
+ __u16 index, void *data)
+{
+ int status;
+ unsigned int pipe;
+ u16 product = le16_to_cpu(serial->dev->descriptor.idProduct);
+ __u8 requesttype;
+ __u16 size = 0x0000;
+
+ if (value < MOS_MAX_PORT) {
+ if (product == MOSCHIP_DEVICE_ID_7715) {
+ value = value*0x100+0x100;
+ } else {
+ value = value*0x100+0x200;
+ }
+ } else {
+ value = 0x0000;
+ if ((product == MOSCHIP_DEVICE_ID_7715) &&
+ (index != 0x08)) {
+ dbg("serial->product== MOSCHIP_DEVICE_ID_7715");
+ //index = 0x01 ;
+ }
+ }
+
+ if (request == MOS_WRITE) {
+ request = (__u8)MOS_WRITE;
+ requesttype = (__u8)0x40;
+ value = value + (__u16)*((unsigned char *)data);
+ data = NULL;
+ pipe = usb_sndctrlpipe(serial->dev, 0);
+ } else {
+ request = (__u8)MOS_READ;
+ requesttype = (__u8)0xC0;
+ size = 0x01;
+ pipe = usb_rcvctrlpipe(serial->dev,0);
+ }
+
+ status = usb_control_msg(serial->dev, pipe, request, requesttype,
+ value, index, data, size, MOS_WDR_TIMEOUT);
+
+ if (status < 0)
+ dbg("Command Write failed Value %x index %x\n",value,index);
+
+ return status;
+}
+
+static int mos7720_open(struct usb_serial_port *port, struct file * filp)
+{
+ struct usb_serial *serial;
+ struct usb_serial_port *port0;
+ struct urb *urb;
+ struct moschip_serial *mos7720_serial;
+ struct moschip_port *mos7720_port;
+ int response;
+ int port_number;
+ char data;
+ int j;
+
+ serial = port->serial;
+
+ mos7720_port = usb_get_serial_port_data(port);
+ if (mos7720_port == NULL)
+ return -ENODEV;
+
+ port0 = serial->port[0];
+
+ mos7720_serial = usb_get_serial_data(serial);
+
+ if (mos7720_serial == NULL || port0 == NULL)
+ return -ENODEV;
+
+ usb_clear_halt(serial->dev, port->write_urb->pipe);
+ usb_clear_halt(serial->dev, port->read_urb->pipe);
+
+ /* Initialising the write urb pool */
+ for (j = 0; j < NUM_URBS; ++j) {
+ urb = usb_alloc_urb(0,SLAB_ATOMIC);
+ mos7720_port->write_urb_pool[j] = urb;
+
+ if (urb == NULL) {
+ err("No more urbs???");
+ continue;
+ }
+
+ urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE,
+ GFP_KERNEL);
+ if (!urb->transfer_buffer) {
+ err("%s-out of memory for urb buffers.", __FUNCTION__);
+ continue;
+ }
+ }
+
+ /* Initialize MCS7720 -- Write Init values to corresponding Registers
+ *
+ * Register Index
+ * 1 : IER
+ * 2 : FCR
+ * 3 : LCR
+ * 4 : MCR
+ *
+ * 0x08 : SP1/2 Control Reg
+ */
+ port_number = port->number - port->serial->minor;
+ send_mos_cmd(port->serial, MOS_READ, port_number, UART_LSR, &data);
+ dbg("SS::%p LSR:%x\n",mos7720_port, data);
+
+ dbg("Check:Sending Command ..........");
+
+ data = 0x02;
+ send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x01, &data);
+ data = 0x02;
+ send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x02, &data);
+
+ data = 0x00;
+ send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data);
+ data = 0x00;
+ send_mos_cmd(serial, MOS_WRITE, port_number, 0x02, &data);
+
+ data = 0xCF;
+ send_mos_cmd(serial, MOS_WRITE, port_number, 0x02, &data);
+ data = 0x03;
+ mos7720_port->shadowLCR = data;
+ send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data);
+ data = 0x0b;
+ mos7720_port->shadowMCR = data;
+ send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data);
+ data = 0x0b;
+ send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data);
+
+ data = 0x00;
+ send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, 0x08, &data);
+ data = 0x00;
+ send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x08, &data);
+
+/* data = 0x00;
+ send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, port_number + 1, &data);
+ data = 0x03;
+ send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, port_number + 1, &data);
+ data = 0x00;
+ send_mos_cmd(port->serial, MOS_WRITE, MOS_MAX_PORT, port_number + 1, &data);
+*/
+ data = 0x00;
+ send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, 0x08, &data);
+
+ data = data | (port->number - port->serial->minor + 1);
+ send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x08, &data);
+
+ data = 0x83;
+ mos7720_port->shadowLCR = data;
+ send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data);
+ data = 0x0c;
+ send_mos_cmd(serial, MOS_WRITE, port_number, 0x00, &data);
+ data = 0x00;
+ send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data);
+ data = 0x03;
+ mos7720_port->shadowLCR = data;
+ send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data);
+ data = 0x0c;
+ send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data);
+ data = 0x0c;
+ send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data);
+
+//Matrix
+
+ /* force low_latency on so that our tty_push actually forces *
+ * the data through,otherwise it is scheduled, and with *
+ * high data rates (like with OHCI) data can get lost. */
+
+ if (port->tty)
+ port->tty->low_latency = 1;
+
+ /* see if we've set up our endpoint info yet *
+ * (can't set it up in mos7720_startup as the *
+ * structures were not set up at that time.) */
+ if (!mos7720_serial->interrupt_started) {
+ dbg("Interrupt buffer NULL !!!");
+
+ /* not set up yet, so do it now */
+ mos7720_serial->interrupt_started = 1;
+
+ dbg("To Submit URB !!!");
+
+ /* set up our interrupt urb */
+ usb_fill_int_urb(port0->interrupt_in_urb, serial->dev,
+ usb_rcvintpipe(serial->dev,
+ port->interrupt_in_endpointAddress),
+ port0->interrupt_in_buffer,
+ port0->interrupt_in_urb->transfer_buffer_length,
+ mos7720_interrupt_callback, mos7720_port,
+ port0->interrupt_in_urb->interval);
+
+ /* start interrupt read for this mos7720 this interrupt *
+ * will continue as long as the mos7720 is connected */
+ dbg("Submit URB over !!!");
+ response = usb_submit_urb(port0->interrupt_in_urb, GFP_KERNEL);
+ if (response)
+ dev_err(&port->dev,
+ "%s - Error %d submitting control urb",
+ __FUNCTION__, response);
+ }
+
+ /* set up our bulk in urb */
+ usb_fill_bulk_urb(port->read_urb, serial->dev,
+ usb_rcvbulkpipe(serial->dev,
+ port->bulk_in_endpointAddress),
+ port->bulk_in_buffer,
+ port->read_urb->transfer_buffer_length,
+ mos7720_bulk_in_callback, mos7720_port);
+ response = usb_submit_urb(port->read_urb, GFP_KERNEL);
+ if (response)
+ dev_err(&port->dev,
+ "%s - Error %d submitting read urb", __FUNCTION__, response);
+
+ /* initialize our icount structure */
+ memset(&(mos7720_port->icount), 0x00, sizeof(mos7720_port->icount));
+
+ /* initialize our port settings */
+ mos7720_port->shadowMCR = UART_MCR_OUT2; /* Must set to enable ints! */
+
+ /* send a open port command */
+ mos7720_port->open = 1;
+
+ return 0;
+}
+
+/*
+ * mos7720_chars_in_buffer
+ * this function is called by the tty driver when it wants to know how many
+ * bytes of data we currently have outstanding in the port (data that has
+ * been written, but hasn't made it out the port yet)
+ * If successful, we return the number of bytes left to be written in the
+ * system,
+ * Otherwise we return a negative error number.
+ */
+static int mos7720_chars_in_buffer(struct usb_serial_port *port)
+{
+ int i;
+ int chars = 0;
+ struct moschip_port *mos7720_port;
+
+ dbg("%s:entering ...........", __FUNCTION__);
+
+ mos7720_port = usb_get_serial_port_data(port);
+ if (mos7720_port == NULL) {
+ dbg("%s:leaving ...........", __FUNCTION__);
+ return -ENODEV;
+ }
+
+ for (i = 0; i < NUM_URBS; ++i) {
+ if (mos7720_port->write_urb_pool[i]->status == -EINPROGRESS)
+ chars += URB_TRANSFER_BUFFER_SIZE;
+ }
+ dbg("%s - returns %d", __FUNCTION__, chars);
+ return chars;
+}
+
+static void mos7720_close(struct usb_serial_port *port, struct file *filp)
+{
+ struct usb_serial *serial;
+ struct moschip_port *mos7720_port;
+ char data;
+ int j;
+
+ dbg("mos7720_close:entering...");
+
+ serial = port->serial;
+
+ mos7720_port = usb_get_serial_port_data(port);
+ if (mos7720_port == NULL)
+ return;
+
+ for (j = 0; j < NUM_URBS; ++j)
+ usb_kill_urb(mos7720_port->write_urb_pool[j]);
+
+ /* Freeing Write URBs */
+ for (j = 0; j < NUM_URBS; ++j) {
+ if (mos7720_port->write_urb_pool[j]) {
+ kfree(mos7720_port->write_urb_pool[j]->transfer_buffer);
+ usb_free_urb(mos7720_port->write_urb_pool[j]);
+ }
+ }
+
+ /* 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);
+ }
+
+ 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);
+
+ mos7720_port->open = 0;
+
+ dbg("Leaving %s", __FUNCTION__);
+}
+
+static void mos7720_break(struct usb_serial_port *port, int break_state)
+{
+ unsigned char data;
+ struct usb_serial *serial;
+ struct moschip_port *mos7720_port;
+
+ dbg("Entering %s", __FUNCTION__);
+
+ serial = port->serial;
+
+ mos7720_port = usb_get_serial_port_data(port);
+ if (mos7720_port == NULL)
+ return;
+
+ if (break_state == -1)
+ data = mos7720_port->shadowLCR | UART_LCR_SBC;
+ else
+ data = mos7720_port->shadowLCR & ~UART_LCR_SBC;
+
+ mos7720_port->shadowLCR = data;
+ send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor,
+ 0x03, &data);
+
+ return;
+}
+
+/*
+ * mos7720_write_room
+ * this function is called by the tty driver when it wants to know how many
+ * bytes of data we can accept for a specific port.
+ * If successful, we return the amount of room that we have for this port
+ * Otherwise we return a negative error number.
+ */
+static int mos7720_write_room(struct usb_serial_port *port)
+{
+ struct moschip_port *mos7720_port;
+ int room = 0;
+ int i;
+
+ dbg("%s:entering ...........", __FUNCTION__);
+
+ mos7720_port = usb_get_serial_port_data(port);
+ if (mos7720_port == NULL) {
+ dbg("%s:leaving ...........", __FUNCTION__);
+ return -ENODEV;
+ }
+
+ for (i = 0; i < NUM_URBS; ++i) {
+ if (mos7720_port->write_urb_pool[i]->status != -EINPROGRESS)
+ room += URB_TRANSFER_BUFFER_SIZE;
+ }
+
+ dbg("%s - returns %d", __FUNCTION__, room);
+ return room;
+}
+
+static int mos7720_write(struct usb_serial_port *port,
+ const unsigned char *data, int count)
+{
+ int status;
+ int i;
+ int bytes_sent = 0;
+ int transfer_size;
+
+ struct moschip_port *mos7720_port;
+ struct usb_serial *serial;
+ struct urb *urb;
+ const unsigned char *current_position = data;
+
+ dbg("%s:entering ...........", __FUNCTION__);
+
+ serial = port->serial;
+
+ mos7720_port = usb_get_serial_port_data(port);
+ if (mos7720_port == NULL) {
+ dbg("mos7720_port is NULL");
+ return -ENODEV;
+ }
+
+ /* try to find a free urb in the list */
+ urb = NULL;
+
+ for (i = 0; i < NUM_URBS; ++i) {
+ if (mos7720_port->write_urb_pool[i]->status != -EINPROGRESS) {
+ urb = mos7720_port->write_urb_pool[i];
+ dbg("URB:%d",i);
+ break;
+ }
+ }
+
+ if (urb == NULL) {
+ dbg("%s - no more free urbs", __FUNCTION__);
+ goto exit;
+ }
+
+ if (urb->transfer_buffer == NULL) {
+ urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE,
+ GFP_KERNEL);
+ if (urb->transfer_buffer == NULL) {
+ err("%s no more kernel memory...", __FUNCTION__);
+ goto exit;
+ }
+ }
+ transfer_size = min (count, URB_TRANSFER_BUFFER_SIZE);
+
+ memcpy(urb->transfer_buffer, current_position, transfer_size);
+ usb_serial_debug_data(debug, &port->dev, __FUNCTION__, transfer_size,
+ urb->transfer_buffer);
+
+ /* fill urb with data and submit */
+ usb_fill_bulk_urb(urb, serial->dev,
+ usb_sndbulkpipe(serial->dev,
+ port->bulk_out_endpointAddress),
+ urb->transfer_buffer, transfer_size,
+ mos7720_bulk_out_data_callback, mos7720_port);
+
+ /* send it down the pipe */
+ status = usb_submit_urb(urb,GFP_ATOMIC);
+ if (status) {
+ err("%s - usb_submit_urb(write bulk) failed with status = %d",
+ __FUNCTION__, status);
+ bytes_sent = status;
+ goto exit;
+ }
+ bytes_sent = transfer_size;
+
+exit:
+ return bytes_sent;
+}
+
+static void mos7720_throttle(struct usb_serial_port *port)
+{
+ struct moschip_port *mos7720_port;
+ struct tty_struct *tty;
+ int status;
+
+ dbg("%s- port %d\n", __FUNCTION__, port->number);
+
+ mos7720_port = usb_get_serial_port_data(port);
+
+ if (mos7720_port == NULL)
+ return;
+
+ if (!mos7720_port->open) {
+ dbg("port not opened");
+ return;
+ }
+
+ dbg("%s: Entering ..........", __FUNCTION__);
+
+ tty = port->tty;
+ if (!tty) {
+ dbg("%s - no tty available", __FUNCTION__);
+ return;
+ }
+
+ /* if we are implementing XON/XOFF, send the stop character */
+ if (I_IXOFF(tty)) {
+ unsigned char stop_char = STOP_CHAR(tty);
+ status = mos7720_write(port, &stop_char, 1);
+ if (status <= 0)
+ return;
+ }
+
+ /* if we are implementing RTS/CTS, toggle that line */
+ if (tty->termios->c_cflag & CRTSCTS) {
+ mos7720_port->shadowMCR &= ~UART_MCR_RTS;
+ status = send_mos_cmd(port->serial, MOS_WRITE,
+ port->number - port->serial->minor,
+ UART_MCR, &mos7720_port->shadowMCR);
+ if (status != 0)
+ return;
+ }
+}
+
+static void mos7720_unthrottle(struct usb_serial_port *port)
+{
+ struct tty_struct *tty;
+ int status;
+ struct moschip_port *mos7720_port = usb_get_serial_port_data(port);
+
+ if (mos7720_port == NULL)
+ return;
+
+ if (!mos7720_port->open) {
+ dbg("%s - port not opened", __FUNCTION__);
+ return;
+ }
+
+ dbg("%s: Entering ..........", __FUNCTION__);
+
+ tty = port->tty;
+ if (!tty) {
+ dbg("%s - no tty available", __FUNCTION__);
+ return;
+ }
+
+ /* if we are implementing XON/XOFF, send the start character */
+ if (I_IXOFF(tty)) {
+ unsigned char start_char = START_CHAR(tty);
+ status = mos7720_write(port, &start_char, 1);
+ if (status <= 0)
+ return;
+ }
+
+ /* if we are implementing RTS/CTS, toggle that line */
+ if (tty->termios->c_cflag & CRTSCTS) {
+ mos7720_port->shadowMCR |= UART_MCR_RTS;
+ status = send_mos_cmd(port->serial, MOS_WRITE,
+ port->number - port->serial->minor,
+ UART_MCR, &mos7720_port->shadowMCR);
+ if (status != 0)
+ return;
+ }
+}
+
+static int set_higher_rates(struct moschip_port *mos7720_port,
+ unsigned int baud)
+{
+ unsigned char data;
+ struct usb_serial_port *port;
+ struct usb_serial *serial;
+ int port_number;
+
+ if (mos7720_port == NULL)
+ return -EINVAL;
+
+ port = mos7720_port->port;
+ serial = port->serial;
+
+ /***********************************************
+ * Init Sequence for higher rates
+ ***********************************************/
+ dbg("Sending Setting Commands ..........");
+ port_number = port->number - port->serial->minor;
+
+ data = 0x000;
+ send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data);
+ data = 0x000;
+ send_mos_cmd(serial, MOS_WRITE, port_number, 0x02, &data);
+ data = 0x0CF;
+ send_mos_cmd(serial, MOS_WRITE, port->number, 0x02, &data);
+ data = 0x00b;
+ mos7720_port->shadowMCR = data;
+ send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data);
+ data = 0x00b;
+ send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data);
+
+ data = 0x000;
+ send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, 0x08, &data);
+ data = 0x000;
+ send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x08, &data);
+
+
+ /***********************************************
+ * Set for higher rates *
+ ***********************************************/
+
+ data = baud * 0x10;
+ send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, port_number + 1,&data);
+
+ data = 0x003;
+ send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, 0x08, &data);
+ data = 0x003;
+ send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x08, &data);
+
+ data = 0x02b;
+ mos7720_port->shadowMCR = data;
+ send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data);
+ data = 0x02b;
+ send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data);
+
+ /***********************************************
+ * Set DLL/DLM
+ ***********************************************/
+
+ data = mos7720_port->shadowLCR | UART_LCR_DLAB;
+ mos7720_port->shadowLCR = data;
+ send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data);
+
+ data = 0x001; /* DLL */
+ send_mos_cmd(serial, MOS_WRITE, port_number, 0x00, &data);
+ data = 0x000; /* DLM */
+ send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data);
+
+ data = mos7720_port->shadowLCR & ~UART_LCR_DLAB;
+ mos7720_port->shadowLCR = data;
+ send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data);
+
+ return 0;
+}
+
+/* baud rate information */
+struct divisor_table_entry
+{
+ __u32 baudrate;
+ __u16 divisor;
+};
+
+/* Define table of divisors for moschip 7720 hardware *
+ * These assume a 3.6864MHz crystal, the standard /16, and *
+ * MCR.7 = 0. */
+static struct divisor_table_entry divisor_table[] = {
+ { 50, 2304},
+ { 110, 1047}, /* 2094.545455 => 230450 => .0217 % over */
+ { 134, 857}, /* 1713.011152 => 230398.5 => .00065% under */
+ { 150, 768},
+ { 300, 384},
+ { 600, 192},
+ { 1200, 96},
+ { 1800, 64},
+ { 2400, 48},
+ { 4800, 24},
+ { 7200, 16},
+ { 9600, 12},
+ { 19200, 6},
+ { 38400, 3},
+ { 57600, 2},
+ { 115200, 1},
+};
+
+/*****************************************************************************
+ * calc_baud_rate_divisor
+ * this function calculates the proper baud rate divisor for the specified
+ * baud rate.
+ *****************************************************************************/
+static int calc_baud_rate_divisor(int baudrate, int *divisor)
+{
+ int i;
+ __u16 custom;
+ __u16 round1;
+ __u16 round;
+
+
+ dbg("%s - %d", __FUNCTION__, baudrate);
+
+ for (i = 0; i < ARRAY_SIZE(divisor_table); i++) {
+ if (divisor_table[i].baudrate == baudrate) {
+ *divisor = divisor_table[i].divisor;
+ return 0;
+ }
+ }
+
+ /* After trying for all the standard baud rates *
+ * Try calculating the divisor for this baud rate */
+ if (baudrate > 75 && baudrate < 230400) {
+ /* get the divisor */
+ custom = (__u16)(230400L / baudrate);
+
+ /* Check for round off */
+ round1 = (__u16)(2304000L / baudrate);
+ round = (__u16)(round1 - (custom * 10));
+ if (round > 4)
+ custom++;
+ *divisor = custom;
+
+ dbg("Baud %d = %d",baudrate, custom);
+ return 0;
+ }
+
+ dbg("Baud calculation Failed...");
+ return -EINVAL;
+}
+
+/*
+ * send_cmd_write_baud_rate
+ * this function sends the proper command to change the baud rate of the
+ * specified port.
+ */
+static int send_cmd_write_baud_rate(struct moschip_port *mos7720_port,
+ int baudrate)
+{
+ struct usb_serial_port *port;
+ struct usb_serial *serial;
+ int divisor;
+ int status;
+ unsigned char data;
+ unsigned char number;
+
+ if (mos7720_port == NULL)
+ return -1;
+
+ port = mos7720_port->port;
+ serial = port->serial;
+
+ dbg("%s: Entering ..........", __FUNCTION__);
+
+ number = port->number - port->serial->minor;
+ dbg("%s - port = %d, baud = %d", __FUNCTION__, port->number, baudrate);
+
+ /* Calculate the Divisor */
+ status = calc_baud_rate_divisor(baudrate, &divisor);
+ if (status) {
+ err("%s - bad baud rate", __FUNCTION__);
+ return status;
+ }
+
+ /* Enable access to divisor latch */
+ data = mos7720_port->shadowLCR | UART_LCR_DLAB;
+ mos7720_port->shadowLCR = data;
+ send_mos_cmd(serial, MOS_WRITE, number, UART_LCR, &data);
+
+ /* Write the divisor */
+ data = ((unsigned char)(divisor & 0xff));
+ send_mos_cmd(serial, MOS_WRITE, number, 0x00, &data);
+
+ data = ((unsigned char)((divisor & 0xff00) >> 8));
+ send_mos_cmd(serial, MOS_WRITE, number, 0x01, &data);
+
+ /* Disable access to divisor latch */
+ data = mos7720_port->shadowLCR & ~UART_LCR_DLAB;
+ mos7720_port->shadowLCR = data;
+ send_mos_cmd(serial, MOS_WRITE, number, 0x03, &data);
+
+ return status;
+}
+
+/*
+ * change_port_settings
+ * This routine is called to set the UART on the device to match
+ * the specified new settings.
+ */
+static void change_port_settings(struct moschip_port *mos7720_port,
+ struct termios *old_termios)
+{
+ struct usb_serial_port *port;
+ struct usb_serial *serial;
+ struct tty_struct *tty;
+ int baud;
+ unsigned cflag;
+ unsigned iflag;
+ __u8 mask = 0xff;
+ __u8 lData;
+ __u8 lParity;
+ __u8 lStop;
+ int status;
+ int port_number;
+ char data;
+
+ if (mos7720_port == NULL)
+ return ;
+
+ port = mos7720_port->port;
+ serial = port->serial;
+ port_number = port->number - port->serial->minor;
+
+ dbg("%s - port %d", __FUNCTION__, port->number);
+
+ if (!mos7720_port->open) {
+ dbg("%s - port not opened", __FUNCTION__);
+ return;
+ }
+
+ tty = mos7720_port->port->tty;
+
+ if ((!tty) || (!tty->termios)) {
+ dbg("%s - no tty structures", __FUNCTION__);
+ return;
+ }
+
+ dbg("%s: Entering ..........", __FUNCTION__);
+
+ lData = UART_LCR_WLEN8;
+ lStop = 0x00; /* 1 stop bit */
+ lParity = 0x00; /* No parity */
+
+ cflag = tty->termios->c_cflag;
+ iflag = tty->termios->c_iflag;
+
+ /* Change the number of bits */
+ switch (cflag & CSIZE) {
+ case CS5:
+ lData = UART_LCR_WLEN5;
+ mask = 0x1f;
+ break;
+
+ case CS6:
+ lData = UART_LCR_WLEN6;
+ mask = 0x3f;
+ break;
+
+ case CS7:
+ lData = UART_LCR_WLEN7;
+ mask = 0x7f;
+ break;
+ default:
+ case CS8:
+ lData = UART_LCR_WLEN8;
+ break;
+ }
+
+ /* Change the Parity bit */
+ if (cflag & PARENB) {
+ if (cflag & PARODD) {
+ lParity = UART_LCR_PARITY;
+ dbg("%s - parity = odd", __FUNCTION__);
+ } else {
+ lParity = (UART_LCR_EPAR | UART_LCR_PARITY);
+ dbg("%s - parity = even", __FUNCTION__);
+ }
+
+ } else {
+ dbg("%s - parity = none", __FUNCTION__);
+ }
+
+ if (cflag & CMSPAR)
+ lParity = lParity | 0x20;
+
+ /* Change the Stop bit */
+ if (cflag & CSTOPB) {
+ lStop = UART_LCR_STOP;
+ dbg("%s - stop bits = 2", __FUNCTION__);
+ } else {
+ lStop = 0x00;
+ dbg("%s - stop bits = 1", __FUNCTION__);
+ }
+
+#define LCR_BITS_MASK 0x03 /* Mask for bits/char field */
+#define LCR_STOP_MASK 0x04 /* Mask for stop bits field */
+#define LCR_PAR_MASK 0x38 /* Mask for parity field */
+
+ /* Update the LCR with the correct value */
+ mos7720_port->shadowLCR &= ~(LCR_BITS_MASK | LCR_STOP_MASK | LCR_PAR_MASK);
+ mos7720_port->shadowLCR |= (lData | lParity | lStop);
+
+
+ /* Disable Interrupts */
+ data = 0x00;
+ send_mos_cmd(serial,MOS_WRITE,port->number - port->serial->minor, UART_IER, &data);
+
+ data = 0x00;
+ send_mos_cmd(serial, MOS_WRITE, port_number, UART_FCR, &data);
+
+ data = 0xcf;
+ send_mos_cmd(serial, MOS_WRITE, port_number, UART_FCR, &data);
+
+ /* Send the updated LCR value to the mos7720 */
+ data = mos7720_port->shadowLCR;
+ send_mos_cmd(serial, MOS_WRITE, port_number, UART_LCR, &data);
+
+ data = 0x00b;
+ mos7720_port->shadowMCR = data;
+ send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data);
+ data = 0x00b;
+ send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data);
+
+ /* set up the MCR register and send it to the mos7720 */
+ mos7720_port->shadowMCR = UART_MCR_OUT2;
+ if (cflag & CBAUD)
+ mos7720_port->shadowMCR |= (UART_MCR_DTR | UART_MCR_RTS);
+
+ if (cflag & CRTSCTS) {
+ mos7720_port->shadowMCR |= (UART_MCR_XONANY);
+
+ /* To set hardware flow control to the specified *
+ * serial port, in SP1/2_CONTROL_REG */
+ if (port->number) {
+ data = 0x001;
+ send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT,
+ 0x08, &data);
+ } else {
+ data = 0x002;
+ send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT,
+ 0x08, &data);
+ }
+ } else {
+ mos7720_port->shadowMCR &= ~(UART_MCR_XONANY);
+ }
+
+ data = mos7720_port->shadowMCR;
+ send_mos_cmd(serial, MOS_WRITE, port_number, UART_MCR, &data);
+
+ /* Determine divisor based on baud rate */
+ baud = tty_get_baud_rate(tty);
+ if (!baud) {
+ /* pick a default, any default... */
+ dbg("Picked default baud...");
+ baud = 9600;
+ }
+
+ if (baud >= 230400) {
+ set_higher_rates(mos7720_port, baud);
+ /* Enable Interrupts */
+ data = 0x0c;
+ send_mos_cmd(serial, MOS_WRITE, port_number, UART_IER, &data);
+ return;
+ }
+
+ dbg("%s - baud rate = %d", __FUNCTION__, baud);
+ status = send_cmd_write_baud_rate(mos7720_port, baud);
+
+ /* Enable Interrupts */
+ data = 0x0c;
+ send_mos_cmd(serial, MOS_WRITE, port_number, UART_IER, &data);
+
+ if (port->read_urb->status != -EINPROGRESS) {
+ port->read_urb->dev = serial->dev;
+
+ status = usb_submit_urb(port->read_urb, GFP_ATOMIC);
+ if (status)
+ dbg("usb_submit_urb(read bulk) failed, status = %d",
+ status);
+ }
+ return;
+}
+
+/*
+ * mos7720_set_termios
+ * this function is called by the tty driver when it wants to change the
+ * termios structure.
+ */
+static void mos7720_set_termios(struct usb_serial_port *port,
+ struct termios *old_termios)
+{
+ int status;
+ unsigned int cflag;
+ struct usb_serial *serial;
+ struct moschip_port *mos7720_port;
+ struct tty_struct *tty;
+
+ serial = port->serial;
+
+ mos7720_port = usb_get_serial_port_data(port);
+
+ if (mos7720_port == NULL)
+ return;
+
+ 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__);
+ return;
+ }
+
+ dbg("%s\n","setting termios - ASPIRE");
+
+ cflag = tty->termios->c_cflag;
+
+ if (!cflag) {
+ printk("%s %s\n",__FUNCTION__,"cflag is NULL");
+ return;
+ }
+
+ /* check that they really want us to change something */
+ if (old_termios) {
+ if ((cflag == old_termios->c_cflag) &&
+ (RELEVANT_IFLAG(tty->termios->c_iflag) ==
+ RELEVANT_IFLAG(old_termios->c_iflag))) {
+ dbg("Nothing to change");
+ return;
+ }
+ }
+
+ dbg("%s - clfag %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 - port %d", __FUNCTION__, port->number);
+
+ /* change the port settings to the new ones specified */
+ change_port_settings(mos7720_port, old_termios);
+
+ if(!port->read_urb) {
+ dbg("%s","URB KILLED !!!!!\n");
+ return;
+ }
+
+ if(port->read_urb->status != -EINPROGRESS) {
+ port->read_urb->dev = serial->dev;
+ status = usb_submit_urb(port->read_urb, GFP_ATOMIC);
+ if (status)
+ dbg("usb_submit_urb(read bulk) failed, status = %d",
+ status);
+ }
+ return;
+}
+
+/*
+ * get_lsr_info - get line status register info
+ *
+ * Purpose: Let user call ioctl() to get info when the UART physically
+ * is emptied. On bus types like RS485, the transmitter must
+ * release the bus after transmitting. This must be done when
+ * the transmit shift register is empty, not be done when the
+ * transmit holding register is empty. This functionality
+ * allows an RS485 driver to be written in user space.
+ */
+static int get_lsr_info(struct moschip_port *mos7720_port,
+ unsigned int __user *value)
+{
+ int count;
+ unsigned int result = 0;
+
+ count = mos7720_chars_in_buffer(mos7720_port->port);
+ if (count == 0) {
+ dbg("%s -- Empty", __FUNCTION__);
+ result = TIOCSER_TEMT;
+ }
+
+ if (copy_to_user(value, &result, sizeof(int)))
+ return -EFAULT;
+ return 0;
+}
+
+/*
+ * get_number_bytes_avail - get number of bytes available
+ *
+ * Purpose: Let user call ioctl to get the count of number of bytes available.
+ */
+static int get_number_bytes_avail(struct moschip_port *mos7720_port,
+ unsigned int __user *value)
+{
+ unsigned int result = 0;
+ struct tty_struct *tty = mos7720_port->port->tty;
+
+ if (!tty)
+ return -ENOIOCTLCMD;
+
+ result = tty->read_cnt;
+
+ dbg("%s(%d) = %d", __FUNCTION__, mos7720_port->port->number, result);
+ if (copy_to_user(value, &result, sizeof(int)))
+ return -EFAULT;
+
+ return -ENOIOCTLCMD;
+}
+
+static int set_modem_info(struct moschip_port *mos7720_port, unsigned int cmd,
+ unsigned int __user *value)
+{
+ unsigned int mcr ;
+ unsigned int arg;
+ unsigned char data;
+
+ struct usb_serial_port *port;
+
+ if (mos7720_port == NULL)
+ return -1;
+
+ port = (struct usb_serial_port*)mos7720_port->port;
+ mcr = mos7720_port->shadowMCR;
+
+ if (copy_from_user(&arg, value, sizeof(int)))
+ return -EFAULT;
+
+ switch (cmd) {
+ case TIOCMBIS:
+ if (arg & TIOCM_RTS)
+ mcr |= UART_MCR_RTS;
+ if (arg & TIOCM_DTR)
+ mcr |= UART_MCR_RTS;
+ if (arg & TIOCM_LOOP)
+ mcr |= UART_MCR_LOOP;
+ break;
+
+ case TIOCMBIC:
+ if (arg & TIOCM_RTS)
+ mcr &= ~UART_MCR_RTS;
+ if (arg & TIOCM_DTR)
+ mcr &= ~UART_MCR_RTS;
+ if (arg & TIOCM_LOOP)
+ mcr &= ~UART_MCR_LOOP;
+ break;
+
+ case TIOCMSET:
+ /* turn off the RTS and DTR and LOOPBACK
+ * and then only turn on what was asked to */
+ mcr &= ~(UART_MCR_RTS | UART_MCR_DTR | UART_MCR_LOOP);
+ mcr |= ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0);
+ mcr |= ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0);
+ mcr |= ((arg & TIOCM_LOOP) ? UART_MCR_LOOP : 0);
+ break;
+ }
+
+ mos7720_port->shadowMCR = mcr;
+
+ data = mos7720_port->shadowMCR;
+ send_mos_cmd(port->serial, MOS_WRITE,
+ port->number - port->serial->minor, UART_MCR, &data);
+
+ return 0;
+}
+
+static int get_modem_info(struct moschip_port *mos7720_port,
+ unsigned int __user *value)
+{
+ unsigned int result = 0;
+ unsigned int msr = mos7720_port->shadowMSR;
+ unsigned int mcr = mos7720_port->shadowMCR;
+
+ result = ((mcr & UART_MCR_DTR) ? TIOCM_DTR: 0) /* 0x002 */
+ | ((mcr & UART_MCR_RTS) ? TIOCM_RTS: 0) /* 0x004 */
+ | ((msr & UART_MSR_CTS) ? TIOCM_CTS: 0) /* 0x020 */
+ | ((msr & UART_MSR_DCD) ? TIOCM_CAR: 0) /* 0x040 */
+ | ((msr & UART_MSR_RI) ? TIOCM_RI: 0) /* 0x080 */
+ | ((msr & UART_MSR_DSR) ? TIOCM_DSR: 0); /* 0x100 */
+
+
+ dbg("%s -- %x", __FUNCTION__, result);
+
+ if (copy_to_user(value, &result, sizeof(int)))
+ return -EFAULT;
+ return 0;
+}
+
+static int get_serial_info(struct moschip_port *mos7720_port,
+ struct serial_struct __user *retinfo)
+{
+ struct serial_struct tmp;
+
+ if (!retinfo)
+ return -EFAULT;
+
+ memset(&tmp, 0, sizeof(tmp));
+
+ tmp.type = PORT_16550A;
+ tmp.line = mos7720_port->port->serial->minor;
+ tmp.port = mos7720_port->port->number;
+ tmp.irq = 0;
+ tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
+ tmp.xmit_fifo_size = NUM_URBS * URB_TRANSFER_BUFFER_SIZE;
+ tmp.baud_base = 9600;
+ tmp.close_delay = 5*HZ;
+ tmp.closing_wait = 30*HZ;
+
+ if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
+ return -EFAULT;
+ return 0;
+}
+
+static int mos7720_ioctl(struct usb_serial_port *port, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct moschip_port *mos7720_port;
+ struct async_icount cnow;
+ struct async_icount cprev;
+ struct serial_icounter_struct icount;
+
+ mos7720_port = usb_get_serial_port_data(port);
+ if (mos7720_port == NULL)
+ return -ENODEV;
+
+ dbg("%s - port %d, cmd = 0x%x", __FUNCTION__, port->number, cmd);
+
+ switch (cmd) {
+ case TIOCINQ:
+ /* return number of bytes available */
+ dbg("%s (%d) TIOCINQ", __FUNCTION__, port->number);
+ return get_number_bytes_avail(mos7720_port,
+ (unsigned int __user *)arg);
+ break;
+
+ case TIOCSERGETLSR:
+ dbg("%s (%d) TIOCSERGETLSR", __FUNCTION__, port->number);
+ return get_lsr_info(mos7720_port, (unsigned int __user *)arg);
+ return 0;
+
+ case TIOCMBIS:
+ case TIOCMBIC:
+ case TIOCMSET:
+ dbg("%s (%d) TIOCMSET/TIOCMBIC/TIOCMSET", __FUNCTION__,
+ port->number);
+ return set_modem_info(mos7720_port, cmd,
+ (unsigned int __user *)arg);
+
+ case TIOCMGET:
+ dbg("%s (%d) TIOCMGET", __FUNCTION__, port->number);
+ return get_modem_info(mos7720_port,
+ (unsigned int __user *)arg);
+
+ case TIOCGSERIAL:
+ dbg("%s (%d) TIOCGSERIAL", __FUNCTION__, port->number);
+ return get_serial_info(mos7720_port,
+ (struct serial_struct __user *)arg);
+
+ case TIOCSSERIAL:
+ dbg("%s (%d) TIOCSSERIAL", __FUNCTION__, port->number);
+ break;
+
+ case TIOCMIWAIT:
+ dbg("%s (%d) TIOCMIWAIT", __FUNCTION__, port->number);
+ cprev = mos7720_port->icount;
+ while (1) {
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+ cnow = mos7720_port->icount;
+ if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
+ cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
+ return -EIO; /* no change => error */
+ if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
+ ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
+ ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
+ ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) {
+ return 0;
+ }
+ cprev = cnow;
+ }
+ /* NOTREACHED */
+ break;
+
+ case TIOCGICOUNT:
+ cnow = mos7720_port->icount;
+ icount.cts = cnow.cts;
+ icount.dsr = cnow.dsr;
+ icount.rng = cnow.rng;
+ icount.dcd = cnow.dcd;
+ icount.rx = cnow.rx;
+ icount.tx = cnow.tx;
+ icount.frame = cnow.frame;
+ icount.overrun = cnow.overrun;
+ icount.parity = cnow.parity;
+ icount.brk = cnow.brk;
+ icount.buf_overrun = cnow.buf_overrun;
+
+ dbg("%s (%d) TIOCGICOUNT RX=%d, TX=%d", __FUNCTION__,
+ port->number, icount.rx, icount.tx );
+ if (copy_to_user((void __user *)arg, &icount, sizeof(icount)))
+ return -EFAULT;
+ return 0;
+ }
+
+ return -ENOIOCTLCMD;
+}
+
+static int mos7720_startup(struct usb_serial *serial)
+{
+ struct moschip_serial *mos7720_serial;
+ struct moschip_port *mos7720_port;
+ struct usb_device *dev;
+ int i;
+ char data;
+
+ dbg("%s: Entering ..........", __FUNCTION__);
+
+ if (!serial) {
+ dbg("Invalid Handler");
+ return -ENODEV;
+ }
+
+ dev = serial->dev;
+
+ /* create our private serial structure */
+ mos7720_serial = kzalloc(sizeof(struct moschip_serial), GFP_KERNEL);
+ if (mos7720_serial == NULL) {
+ err("%s - Out of memory", __FUNCTION__);
+ return -ENOMEM;
+ }
+
+ usb_set_serial_data(serial, mos7720_serial);
+
+ /* we set up the pointers to the endpoints in the mos7720_open *
+ * function, as the structures aren't created yet. */
+
+ /* set up port private structures */
+ for (i = 0; i < serial->num_ports; ++i) {
+ mos7720_port = kzalloc(sizeof(struct moschip_port), GFP_KERNEL);
+ if (mos7720_port == NULL) {
+ err("%s - Out of memory", __FUNCTION__);
+ usb_set_serial_data(serial, NULL);
+ kfree(mos7720_serial);
+ return -ENOMEM;
+ }
+
+ /* Initialize all port interrupt end point to port 0 int
+ * endpoint. Our device has only one interrupt endpoint
+ * comman to all ports */
+ serial->port[i]->interrupt_in_endpointAddress = serial->port[0]->interrupt_in_endpointAddress;
+
+ mos7720_port->port = serial->port[i];
+ usb_set_serial_port_data(serial->port[i], mos7720_port);
+
+ dbg("port number is %d", serial->port[i]->number);
+ dbg("serial number is %d", serial->minor);
+ }
+
+
+ /* setting configuration feature to one */
+ usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ (__u8)0x03, 0x00,0x01,0x00, NULL, 0x00, 5*HZ);
+
+ send_mos_cmd(serial,MOS_READ,0x00, UART_LSR, &data); // LSR For Port 1
+ dbg("LSR:%x",data);
+
+ send_mos_cmd(serial,MOS_READ,0x01, UART_LSR, &data); // LSR For Port 2
+ dbg("LSR:%x",data);
+
+ return 0;
+}
+
+static void mos7720_shutdown(struct usb_serial *serial)
+{
+ int i;
+
+ /* free private structure allocated for serial port */
+ for (i=0; i < serial->num_ports; ++i) {
+ kfree(usb_get_serial_port_data(serial->port[i]));
+ usb_set_serial_port_data(serial->port[i], NULL);
+ }
+
+ /* free private structure allocated for serial device */
+ kfree(usb_get_serial_data(serial));
+ usb_set_serial_data(serial, NULL);
+}
+
+static struct usb_serial_driver moschip7720_2port_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "moschip7720",
+ },
+ .description = "Moschip 2 port adapter",
+ .id_table = moschip_port_id_table,
+ .num_interrupt_in = 1,
+ .num_bulk_in = 2,
+ .num_bulk_out = 2,
+ .num_ports = 2,
+ .open = mos7720_open,
+ .close = mos7720_close,
+ .throttle = mos7720_throttle,
+ .unthrottle = mos7720_unthrottle,
+ .attach = mos7720_startup,
+ .shutdown = mos7720_shutdown,
+ .ioctl = mos7720_ioctl,
+ .set_termios = mos7720_set_termios,
+ .write = mos7720_write,
+ .write_room = mos7720_write_room,
+ .chars_in_buffer = mos7720_chars_in_buffer,
+ .break_ctl = mos7720_break,
+ .read_bulk_callback = mos7720_bulk_in_callback,
+};
+
+static struct usb_driver usb_driver = {
+ .name = "moschip7720",
+ .probe = usb_serial_probe,
+ .disconnect = usb_serial_disconnect,
+ .id_table = moschip_port_id_table,
+};
+
+static int __init moschip7720_init(void)
+{
+ int retval;
+
+ dbg("%s: Entering ..........", __FUNCTION__);
+
+ /* Register with the usb serial */
+ retval = usb_serial_register(&moschip7720_2port_driver);
+ if (retval)
+ goto failed_port_device_register;
+
+ info(DRIVER_DESC " " DRIVER_VERSION);
+
+ /* Register with the usb */
+ retval = usb_register(&usb_driver);
+ if (retval)
+ goto failed_usb_register;
+
+ return 0;
+
+failed_usb_register:
+ usb_serial_deregister(&moschip7720_2port_driver);
+
+failed_port_device_register:
+ return retval;
+}
+
+static void __exit moschip7720_exit(void)
+{
+ usb_deregister(&usb_driver);
+ usb_serial_deregister(&moschip7720_2port_driver);
+}
+
+module_init(moschip7720_init);
+module_exit(moschip7720_exit);
+
+/* Module information */
+MODULE_AUTHOR( DRIVER_AUTHOR );
+MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_LICENSE("GPL");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index 021be39fe16..5b71962d035 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -2413,11 +2413,12 @@ static int mos7840_ioctl(struct usb_serial_port *port, struct file *file,
}
mos7840_port = mos7840_get_port_private(port);
- tty = mos7840_port->port->tty;
if (mos7840_port == NULL)
return -1;
+ tty = mos7840_port->port->tty;
+
dbg("%s - port %d, cmd = 0x%x", __FUNCTION__, port->number, cmd);
switch (cmd) {
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c
index d29638daa98..4b5097fa48d 100644
--- a/drivers/usb/serial/sierra.c
+++ b/drivers/usb/serial/sierra.c
@@ -1,75 +1,713 @@
/*
- * Sierra Wireless CDMA Wireless Serial USB driver
- *
- * Current Copy modified by: Kevin Lloyd <linux@sierrawireless.com>
- * Original Copyright (C) 2005-2006 Greg Kroah-Hartman <gregkh@suse.de>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- */
+ USB Driver for Sierra Wireless
+
+ Copyright (C) 2006 Kevin Lloyd <linux@sierrawireless.com>
+
+ IMPORTANT DISCLAIMER: This driver is not commercially supported by
+ Sierra Wireless. Use at your own risk.
+
+ This driver is free software; you can redistribute it and/or modify
+ it under the terms of Version 2 of the GNU General Public License as
+ published by the Free Software Foundation.
+
+ Portions based on the option driver by Matthias Urlichs <smurf@smurf.noris.de>
+ Whom based his on the Keyspan driver by Hugh Blemings <hugh@blemings.org>
+
+ History:
+*/
+
+#define DRIVER_VERSION "v.1.0.5"
+#define DRIVER_AUTHOR "Kevin Lloyd <linux@sierrawireless.com>"
+#define DRIVER_DESC "USB Driver for Sierra Wireless USB modems"
#include <linux/kernel.h>
-#include <linux/init.h>
+#include <linux/jiffies.h>
+#include <linux/errno.h>
#include <linux/tty.h>
+#include <linux/tty_flip.h>
#include <linux/module.h>
#include <linux/usb.h>
#include <linux/usb/serial.h>
+
static struct usb_device_id id_table [] = {
{ USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */
{ USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */
{ USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */
{ USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */
+ { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */
{ USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */
{ USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */
+ { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 for Europe */
{ USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 */
{ USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */
- /* Following devices are supported in the airprime.c driver */
- /* { USB_DEVICE(0x1199, 0x0112) }, */ /* Sierra Wireless AirCard 580 */
- /* { USB_DEVICE(0x0F3D, 0x0112) }, */ /* AirPrime/Sierra PC 5220 */
+
+ { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless AirCard 580 */
+ { USB_DEVICE(0x0F3D, 0x0112) }, /* AirPrime/Sierra PC 5220 */
{ }
};
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, 0x0018) }, /* Sierra Wireless MC5720 */
+ { USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */
+ { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */
+ { USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */
+ { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */
+ { USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */
+ { USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */
+ { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 for Europe */
+ { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 */
+ { USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */
+ { }
+};
+
static struct usb_driver sierra_driver = {
- .name = "sierra_wireless",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
+ .name = "sierra",
+ .probe = usb_serial_probe,
+ .disconnect = usb_serial_disconnect,
+ .id_table = id_table,
+ .no_dynamic_id = 1,
+};
+
+
+static int debug;
+
+/* per port private data */
+#define N_IN_URB 4
+#define N_OUT_URB 1
+#define IN_BUFLEN 4096
+#define OUT_BUFLEN 128
+
+struct sierra_port_private {
+ /* Input endpoints and buffer for this port */
+ struct urb *in_urbs[N_IN_URB];
+ char in_buffer[N_IN_URB][IN_BUFLEN];
+ /* Output endpoints and buffer for this port */
+ struct urb *out_urbs[N_OUT_URB];
+ char out_buffer[N_OUT_URB][OUT_BUFLEN];
+
+ /* Settings for the port */
+ int rts_state; /* Handshaking pins (outputs) */
+ int dtr_state;
+ int cts_state; /* Handshaking pins (inputs) */
+ int dsr_state;
+ int dcd_state;
+ int ri_state;
+
+ unsigned long tx_start_time[N_OUT_URB];
+};
+
+static int sierra_send_setup(struct usb_serial_port *port)
+{
+ struct usb_serial *serial = port->serial;
+ struct sierra_port_private *portdata;
+
+ dbg("%s", __FUNCTION__);
+
+ portdata = usb_get_serial_port_data(port);
+
+ if (port->tty) {
+ int val = 0;
+ if (portdata->dtr_state)
+ val |= 0x01;
+ if (portdata->rts_state)
+ val |= 0x02;
+
+ return usb_control_msg(serial->dev,
+ usb_rcvctrlpipe(serial->dev, 0),
+ 0x22,0x21,val,0,NULL,0,USB_CTRL_SET_TIMEOUT);
+ }
+
+ return 0;
+}
+
+static void sierra_rx_throttle(struct usb_serial_port *port)
+{
+ dbg("%s", __FUNCTION__);
+}
+
+static void sierra_rx_unthrottle(struct usb_serial_port *port)
+{
+ dbg("%s", __FUNCTION__);
+}
+
+static void sierra_break_ctl(struct usb_serial_port *port, int break_state)
+{
+ /* Unfortunately, I don't know how to send a break */
+ dbg("%s", __FUNCTION__);
+}
+
+static void sierra_set_termios(struct usb_serial_port *port,
+ struct termios *old_termios)
+{
+ dbg("%s", __FUNCTION__);
+
+ sierra_send_setup(port);
+}
+
+static int sierra_tiocmget(struct usb_serial_port *port, struct file *file)
+{
+ unsigned int value;
+ struct sierra_port_private *portdata;
+
+ portdata = usb_get_serial_port_data(port);
+
+ value = ((portdata->rts_state) ? TIOCM_RTS : 0) |
+ ((portdata->dtr_state) ? TIOCM_DTR : 0) |
+ ((portdata->cts_state) ? TIOCM_CTS : 0) |
+ ((portdata->dsr_state) ? TIOCM_DSR : 0) |
+ ((portdata->dcd_state) ? TIOCM_CAR : 0) |
+ ((portdata->ri_state) ? TIOCM_RNG : 0);
+
+ return value;
+}
+
+static int sierra_tiocmset(struct usb_serial_port *port, struct file *file,
+ unsigned int set, unsigned int clear)
+{
+ struct sierra_port_private *portdata;
+
+ portdata = usb_get_serial_port_data(port);
+
+ if (set & TIOCM_RTS)
+ portdata->rts_state = 1;
+ if (set & TIOCM_DTR)
+ portdata->dtr_state = 1;
+
+ if (clear & TIOCM_RTS)
+ portdata->rts_state = 0;
+ if (clear & TIOCM_DTR)
+ portdata->dtr_state = 0;
+ return sierra_send_setup(port);
+}
+
+static int sierra_ioctl(struct usb_serial_port *port, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ return -ENOIOCTLCMD;
+}
+
+/* Write */
+static int sierra_write(struct usb_serial_port *port,
+ const unsigned char *buf, int count)
+{
+ struct sierra_port_private *portdata;
+ int i;
+ int left, todo;
+ struct urb *this_urb = NULL; /* spurious */
+ int err;
+
+ portdata = usb_get_serial_port_data(port);
+
+ dbg("%s: write (%d chars)", __FUNCTION__, count);
+
+ i = 0;
+ left = count;
+ for (i=0; left > 0 && i < N_OUT_URB; i++) {
+ todo = left;
+ if (todo > OUT_BUFLEN)
+ todo = OUT_BUFLEN;
+
+ this_urb = portdata->out_urbs[i];
+ if (this_urb->status == -EINPROGRESS) {
+ if (time_before(jiffies,
+ portdata->tx_start_time[i] + 10 * HZ))
+ continue;
+ usb_unlink_urb(this_urb);
+ continue;
+ }
+ if (this_urb->status != 0)
+ dbg("usb_write %p failed (err=%d)",
+ this_urb, this_urb->status);
+
+ dbg("%s: endpoint %d buf %d", __FUNCTION__,
+ usb_pipeendpoint(this_urb->pipe), i);
+
+ /* send the data */
+ memcpy (this_urb->transfer_buffer, buf, todo);
+ this_urb->transfer_buffer_length = todo;
+
+ this_urb->dev = port->serial->dev;
+ err = usb_submit_urb(this_urb, GFP_ATOMIC);
+ if (err) {
+ dbg("usb_submit_urb %p (write bulk) failed "
+ "(%d, has %d)", this_urb,
+ err, this_urb->status);
+ continue;
+ }
+ portdata->tx_start_time[i] = jiffies;
+ buf += todo;
+ left -= todo;
+ }
+
+ count -= left;
+ dbg("%s: wrote (did %d)", __FUNCTION__, count);
+ return count;
+}
+
+static void sierra_indat_callback(struct urb *urb)
+{
+ int err;
+ int endpoint;
+ struct usb_serial_port *port;
+ struct tty_struct *tty;
+ unsigned char *data = urb->transfer_buffer;
+
+ dbg("%s: %p", __FUNCTION__, urb);
+
+ endpoint = usb_pipeendpoint(urb->pipe);
+ port = (struct usb_serial_port *) urb->context;
+
+ if (urb->status) {
+ dbg("%s: nonzero status: %d on endpoint %02x.",
+ __FUNCTION__, urb->status, endpoint);
+ } else {
+ tty = port->tty;
+ if (urb->actual_length) {
+ tty_buffer_request_room(tty, urb->actual_length);
+ tty_insert_flip_string(tty, data, urb->actual_length);
+ tty_flip_buffer_push(tty);
+ } else {
+ dbg("%s: empty read urb received", __FUNCTION__);
+ }
+
+ /* Resubmit urb so we continue receiving */
+ if (port->open_count && urb->status != -ESHUTDOWN) {
+ err = usb_submit_urb(urb, GFP_ATOMIC);
+ if (err)
+ printk(KERN_ERR "%s: resubmit read urb failed. "
+ "(%d)", __FUNCTION__, err);
+ }
+ }
+ return;
+}
+
+static void sierra_outdat_callback(struct urb *urb)
+{
+ struct usb_serial_port *port;
+
+ dbg("%s", __FUNCTION__);
+
+ port = (struct usb_serial_port *) urb->context;
+
+ usb_serial_port_softint(port);
+}
+
+static void sierra_instat_callback(struct urb *urb)
+{
+ int err;
+ struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
+ struct sierra_port_private *portdata = usb_get_serial_port_data(port);
+ struct usb_serial *serial = port->serial;
+
+ dbg("%s", __FUNCTION__);
+ dbg("%s: urb %p port %p has data %p", __FUNCTION__,urb,port,portdata);
+
+ if (urb->status == 0) {
+ struct usb_ctrlrequest *req_pkt =
+ (struct usb_ctrlrequest *)urb->transfer_buffer;
+
+ if (!req_pkt) {
+ dbg("%s: NULL req_pkt\n", __FUNCTION__);
+ return;
+ }
+ if ((req_pkt->bRequestType == 0xA1) &&
+ (req_pkt->bRequest == 0x20)) {
+ int old_dcd_state;
+ unsigned char signals = *((unsigned char *)
+ urb->transfer_buffer +
+ sizeof(struct usb_ctrlrequest));
+
+ dbg("%s: signal x%x", __FUNCTION__, signals);
+
+ old_dcd_state = portdata->dcd_state;
+ portdata->cts_state = 1;
+ portdata->dcd_state = ((signals & 0x01) ? 1 : 0);
+ portdata->dsr_state = ((signals & 0x02) ? 1 : 0);
+ portdata->ri_state = ((signals & 0x08) ? 1 : 0);
+
+ if (port->tty && !C_CLOCAL(port->tty) &&
+ old_dcd_state && !portdata->dcd_state)
+ tty_hangup(port->tty);
+ } else {
+ dbg("%s: type %x req %x", __FUNCTION__,
+ req_pkt->bRequestType,req_pkt->bRequest);
+ }
+ } else
+ dbg("%s: error %d", __FUNCTION__, urb->status);
+
+ /* Resubmit urb so we continue receiving IRQ data */
+ if (urb->status != -ESHUTDOWN) {
+ urb->dev = serial->dev;
+ err = usb_submit_urb(urb, GFP_ATOMIC);
+ if (err)
+ dbg("%s: resubmit intr urb failed. (%d)",
+ __FUNCTION__, err);
+ }
+}
+
+static int sierra_write_room(struct usb_serial_port *port)
+{
+ struct sierra_port_private *portdata;
+ int i;
+ int data_len = 0;
+ struct urb *this_urb;
+
+ portdata = usb_get_serial_port_data(port);
+
+ for (i=0; i < N_OUT_URB; i++) {
+ this_urb = portdata->out_urbs[i];
+ if (this_urb && this_urb->status != -EINPROGRESS)
+ data_len += OUT_BUFLEN;
+ }
+
+ dbg("%s: %d", __FUNCTION__, data_len);
+ return data_len;
+}
+
+static int sierra_chars_in_buffer(struct usb_serial_port *port)
+{
+ struct sierra_port_private *portdata;
+ int i;
+ int data_len = 0;
+ struct urb *this_urb;
+
+ portdata = usb_get_serial_port_data(port);
+
+ for (i=0; i < N_OUT_URB; i++) {
+ this_urb = portdata->out_urbs[i];
+ if (this_urb && this_urb->status == -EINPROGRESS)
+ data_len += this_urb->transfer_buffer_length;
+ }
+ dbg("%s: %d", __FUNCTION__, data_len);
+ return data_len;
+}
+
+static int sierra_open(struct usb_serial_port *port, struct file *filp)
+{
+ struct sierra_port_private *portdata;
+ struct usb_serial *serial = port->serial;
+ int i, err;
+ struct urb *urb;
+
+ portdata = usb_get_serial_port_data(port);
+
+ dbg("%s", __FUNCTION__);
+
+ /* Set some sane defaults */
+ portdata->rts_state = 1;
+ portdata->dtr_state = 1;
+
+ /* Reset low level data toggle and start reading from endpoints */
+ for (i = 0; i < N_IN_URB; i++) {
+ urb = portdata->in_urbs[i];
+ if (! urb)
+ continue;
+ if (urb->dev != serial->dev) {
+ dbg("%s: dev %p != %p", __FUNCTION__,
+ urb->dev, serial->dev);
+ continue;
+ }
+
+ /*
+ * make sure endpoint data toggle is synchronized with the
+ * device
+ */
+ usb_clear_halt(urb->dev, urb->pipe);
+
+ err = usb_submit_urb(urb, GFP_KERNEL);
+ if (err) {
+ dbg("%s: submit urb %d failed (%d) %d",
+ __FUNCTION__, i, err,
+ urb->transfer_buffer_length);
+ }
+ }
+
+ /* Reset low level data toggle on out endpoints */
+ for (i = 0; i < N_OUT_URB; i++) {
+ urb = portdata->out_urbs[i];
+ if (! urb)
+ continue;
+ urb->dev = serial->dev;
+ /* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+ usb_pipeout(urb->pipe), 0); */
+ }
+
+ port->tty->low_latency = 1;
+
+ sierra_send_setup(port);
+
+ return (0);
+}
+
+static inline void stop_urb(struct urb *urb)
+{
+ if (urb && urb->status == -EINPROGRESS)
+ usb_kill_urb(urb);
+}
+
+static void sierra_close(struct usb_serial_port *port, struct file *filp)
+{
+ int i;
+ struct usb_serial *serial = port->serial;
+ struct sierra_port_private *portdata;
+
+ dbg("%s", __FUNCTION__);
+ portdata = usb_get_serial_port_data(port);
+
+ portdata->rts_state = 0;
+ portdata->dtr_state = 0;
+
+ if (serial->dev) {
+ sierra_send_setup(port);
+
+ /* Stop reading/writing urbs */
+ for (i = 0; i < N_IN_URB; i++)
+ stop_urb(portdata->in_urbs[i]);
+ for (i = 0; i < N_OUT_URB; i++)
+ stop_urb(portdata->out_urbs[i]);
+ }
+ port->tty = NULL;
+}
+
+/* Helper functions used by sierra_setup_urbs */
+static struct urb *sierra_setup_urb(struct usb_serial *serial, int endpoint,
+ int dir, void *ctx, char *buf, int len,
+ usb_complete_t callback)
+{
+ struct urb *urb;
+
+ if (endpoint == -1)
+ return NULL; /* endpoint not needed */
+
+ urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */
+ if (urb == NULL) {
+ dbg("%s: alloc for endpoint %d failed.", __FUNCTION__, endpoint);
+ return NULL;
+ }
+
+ /* Fill URB using supplied data. */
+ usb_fill_bulk_urb(urb, serial->dev,
+ usb_sndbulkpipe(serial->dev, endpoint) | dir,
+ buf, len, callback, ctx);
+
+ return urb;
+}
+
+/* Setup urbs */
+static void sierra_setup_urbs(struct usb_serial *serial)
+{
+ int i,j;
+ struct usb_serial_port *port;
+ struct sierra_port_private *portdata;
+
+ dbg("%s", __FUNCTION__);
+
+ for (i = 0; i < serial->num_ports; i++) {
+ port = serial->port[i];
+ portdata = usb_get_serial_port_data(port);
+
+ /* Do indat endpoints first */
+ for (j = 0; j < N_IN_URB; ++j) {
+ portdata->in_urbs[j] = sierra_setup_urb (serial,
+ port->bulk_in_endpointAddress, USB_DIR_IN, port,
+ portdata->in_buffer[j], IN_BUFLEN, sierra_indat_callback);
+ }
+
+ /* outdat endpoints */
+ for (j = 0; j < N_OUT_URB; ++j) {
+ portdata->out_urbs[j] = sierra_setup_urb (serial,
+ port->bulk_out_endpointAddress, USB_DIR_OUT, port,
+ portdata->out_buffer[j], OUT_BUFLEN, sierra_outdat_callback);
+ }
+ }
+}
+
+static int sierra_startup(struct usb_serial *serial)
+{
+ int i, err;
+ struct usb_serial_port *port;
+ struct sierra_port_private *portdata;
+
+ dbg("%s", __FUNCTION__);
+
+ /* Now setup per port private data */
+ for (i = 0; i < serial->num_ports; i++) {
+ port = serial->port[i];
+ portdata = kzalloc(sizeof(*portdata), GFP_KERNEL);
+ if (!portdata) {
+ dbg("%s: kmalloc for sierra_port_private (%d) failed!.",
+ __FUNCTION__, i);
+ return (1);
+ }
+
+ usb_set_serial_port_data(port, portdata);
+
+ if (! port->interrupt_in_urb)
+ continue;
+ err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
+ if (err)
+ dbg("%s: submit irq_in urb failed %d",
+ __FUNCTION__, err);
+ }
+
+ sierra_setup_urbs(serial);
+
+ return (0);
+}
+
+static void sierra_shutdown(struct usb_serial *serial)
+{
+ int i, j;
+ struct usb_serial_port *port;
+ struct sierra_port_private *portdata;
+
+ dbg("%s", __FUNCTION__);
+
+ /* Stop reading/writing urbs */
+ for (i = 0; i < serial->num_ports; ++i) {
+ port = serial->port[i];
+ portdata = usb_get_serial_port_data(port);
+ for (j = 0; j < N_IN_URB; j++)
+ stop_urb(portdata->in_urbs[j]);
+ for (j = 0; j < N_OUT_URB; j++)
+ stop_urb(portdata->out_urbs[j]);
+ }
+
+ /* Now free them */
+ for (i = 0; i < serial->num_ports; ++i) {
+ port = serial->port[i];
+ portdata = usb_get_serial_port_data(port);
+
+ for (j = 0; j < N_IN_URB; j++) {
+ if (portdata->in_urbs[j]) {
+ usb_free_urb(portdata->in_urbs[j]);
+ portdata->in_urbs[j] = NULL;
+ }
+ }
+ for (j = 0; j < N_OUT_URB; j++) {
+ if (portdata->out_urbs[j]) {
+ usb_free_urb(portdata->out_urbs[j]);
+ portdata->out_urbs[j] = NULL;
+ }
+ }
+ }
+
+ /* Now free per port private data */
+ for (i = 0; i < serial->num_ports; i++) {
+ port = serial->port[i];
+ kfree(usb_get_serial_port_data(port));
+ }
+}
+
+static struct usb_serial_driver sierra_1port_device = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "sierra1",
+ },
+ .description = "Sierra USB modem (1 port)",
+ .id_table = id_table_1port,
+ .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_device = {
+static struct usb_serial_driver sierra_3port_device = {
.driver = {
- .owner = THIS_MODULE,
- .name = "Sierra_Wireless",
+ .owner = THIS_MODULE,
+ .name = "sierra3",
},
- .id_table = id_table,
- .num_interrupt_in = NUM_DONT_CARE,
- .num_bulk_in = NUM_DONT_CARE,
- .num_bulk_out = NUM_DONT_CARE,
- .num_ports = 3,
+ .description = "Sierra USB modem (3 port)",
+ .id_table = id_table_3port,
+ .num_interrupt_in = NUM_DONT_CARE,
+ .num_bulk_in = 3,
+ .num_bulk_out = 3,
+ .num_ports = 3,
+ .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,
};
+/* Functions used by new usb-serial code. */
static int __init sierra_init(void)
{
int retval;
-
- retval = usb_serial_register(&sierra_device);
+ retval = usb_serial_register(&sierra_1port_device);
+ if (retval)
+ goto failed_1port_device_register;
+ retval = usb_serial_register(&sierra_3port_device);
if (retval)
- return retval;
+ goto failed_3port_device_register;
+
+
retval = usb_register(&sierra_driver);
if (retval)
- usb_serial_deregister(&sierra_device);
+ goto failed_driver_register;
+
+ info(DRIVER_DESC ": " DRIVER_VERSION);
+
+ 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:
return retval;
}
static void __exit sierra_exit(void)
{
- usb_deregister(&sierra_driver);
- usb_serial_deregister(&sierra_device);
+ usb_deregister (&sierra_driver);
+ usb_serial_deregister(&sierra_1port_device);
+ usb_serial_deregister(&sierra_3port_device);
}
module_init(sierra_init);
module_exit(sierra_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_VERSION(DRIVER_VERSION);
MODULE_LICENSE("GPL");
+
+#ifdef CONFIG_USB_DEBUG
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug messages");
+#endif
+