summaryrefslogtreecommitdiff
path: root/recipes/linux/linux-2.6.28/mtcdp/linux-2.6.28-sierra-20100405.patch
diff options
context:
space:
mode:
authorJames Maki <jmaki@multitech.com>2010-05-03 18:00:26 -0500
committerJames Maki <jmaki@multitech.com>2010-05-03 18:00:26 -0500
commit62255161cf0279ca34e8469af53cf57761539339 (patch)
treec6e98202a59182c9bfbac7136b4020b194426532 /recipes/linux/linux-2.6.28/mtcdp/linux-2.6.28-sierra-20100405.patch
parent0fb0c84c1fb7d0248a25f6ccea3ac142f9322a7c (diff)
register devices with spi controller
Diffstat (limited to 'recipes/linux/linux-2.6.28/mtcdp/linux-2.6.28-sierra-20100405.patch')
-rw-r--r--recipes/linux/linux-2.6.28/mtcdp/linux-2.6.28-sierra-20100405.patch1668
1 files changed, 0 insertions, 1668 deletions
diff --git a/recipes/linux/linux-2.6.28/mtcdp/linux-2.6.28-sierra-20100405.patch b/recipes/linux/linux-2.6.28/mtcdp/linux-2.6.28-sierra-20100405.patch
deleted file mode 100644
index 5d93c0edd3..0000000000
--- a/recipes/linux/linux-2.6.28/mtcdp/linux-2.6.28-sierra-20100405.patch
+++ /dev/null
@@ -1,1668 +0,0 @@
-diff -uprN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28-vanilla/drivers/usb/serial/sierra.c linux-2.6.28/drivers/usb/serial/sierra.c
---- linux-2.6.28-vanilla/drivers/usb/serial/sierra.c 2008-12-24 17:26:37.000000000 -0600
-+++ linux-2.6.28/drivers/usb/serial/sierra.c 2010-04-05 15:25:29.000000000 -0500
-@@ -2,6 +2,9 @@
- USB Driver for Sierra Wireless
-
- Copyright (C) 2006, 2007, 2008 Kevin Lloyd <klloyd@sierrawireless.com>
-+
-+ Copyright (C) 2008, 2009 Elina Pasheva, Matthew Safar, Rory Filer
-+ <linux@sierrawireless.com>
-
- IMPORTANT DISCLAIMER: This driver is not commercially supported by
- Sierra Wireless. Use at your own risk.
-@@ -13,9 +16,14 @@
- 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>
- */
--
--#define DRIVER_VERSION "v.1.3.2"
--#define DRIVER_AUTHOR "Kevin Lloyd <klloyd@sierrawireless.com>"
-+/* Uncomment to log function calls */
-+/* #define DEBUG */
-+/* Uncomment to force power level set to auto when attaching a device */
-+/* #define POWER_LEVEL_AUTO */
-+
-+/* Sierra driver - kernel 2.6.28 */
-+#define DRIVER_VERSION "v.1.7.30"
-+#define DRIVER_AUTHOR "Kevin Lloyd, Elina Pasheva, Matthew Safar, Rory Filer"
- #define DRIVER_DESC "USB Driver for Sierra Wireless USB modems"
-
- #include <linux/kernel.h>
-@@ -26,25 +34,89 @@
- #include <linux/module.h>
- #include <linux/usb.h>
- #include <linux/usb/serial.h>
--#include <linux/usb/ch9.h>
-+#include <asm/unaligned.h>
-
--#define SWIMS_USB_REQUEST_SetPower 0x00
-+#define SWIMS_USB_REQUEST_SetDevPower 0x00
-+#define SWIMS_USB_REQUEST_GetFwAttr 0x06
- #define SWIMS_USB_REQUEST_SetNmea 0x07
-+#define USB_REQUEST_TYPE_CLASS 0xA1
-+#define USB_REQUEST_IFACE 0x20
-
--/* per port private data */
-+#define N_IN_URB_HM 8
-+#define N_OUT_URB_HM 64
- #define N_IN_URB 4
- #define N_OUT_URB 4
- #define IN_BUFLEN 4096
-
-+#define MAX_TRANSFER (PAGE_SIZE - 512)
-+/* MAX_TRANSFER is chosen so that the VM is not stressed by
-+ allocations > PAGE_SIZE and the number of packets in a page
-+ is an integer 512 is the largest possible packet on EHCI */
-+
-+#define SWI_FW_ATTR_PM_MASK 0x02
-+/* PORTION_LEN defines the length of data written to a file at once */
-+#define PORTION_LEN 4096
-+
- static int debug;
- static int nmea;
-
-+/* sysfs attributes */
-+static int sierra_create_sysfs_attrs(struct usb_serial_port *port);
-+static int sierra_remove_sysfs_attrs(struct usb_serial_port *port);
-+/* autopm worker */
-+static void sierra_kevent(struct work_struct * work);
-+
-+/* Used in interface blacklisting */
-+struct sierra_iface_info {
-+ const u32 infolen; /* number of interface numbers on blacklist */
-+ const u8 *ifaceinfo; /* pointer to the array holding the numbers */
-+};
-+
-+/* per interface statistics */
-+struct sierra_intf_stats {
-+ atomic_t rx_bytes; /* received bytes */
-+ atomic_t indat_cb_cnt; /* indat callback count */
-+ atomic_t indat_cb_fail; /* indat cb with error */
-+
-+ atomic_t tx_bytes; /* transmitted bytes */
-+ atomic_t write_cnt; /* no. of writes */
-+ atomic_t write_err; /* no. of failed writes */
-+
-+ atomic_t delayed_writes; /* no. of delayed writes */
-+ atomic_t delayed_write_err; /* no. of delayed write errs */
-+
-+ atomic_t outdat_cb_cnt; /* outdat callback count */
-+ atomic_t outdat_cb_fail; /* outdat cb with error */
-+
-+ atomic_t async_gets; /* async get requests */
-+ atomic_t async_puts; /* async put requests */
-+
-+ atomic_t sync_gets; /* serviced async get requests */
-+ atomic_t sync_puts; /* serviced async put requests */
-+};
-+
-+struct sierra_intf_private {
-+ spinlock_t susp_lock;
-+ unsigned int suspended:1;
-+ int in_flight;
-+ atomic_t disconnected;
-+ int alternate; /* alternate settings selected */
-+
-+ struct sierra_intf_stats stats;
-+
-+ struct work_struct autopm_kevent;
-+ struct kref ref_cnt;
-+ struct usb_serial *serial;
-+ atomic_t puts;
-+ atomic_t gets;
-+};
-+
- static int sierra_set_power_state(struct usb_device *udev, __u16 swiState)
- {
- int result;
-- dev_dbg(&udev->dev, "%s", __func__);
-+ dev_dbg(&udev->dev, "%s\n", __func__);
- result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
-- SWIMS_USB_REQUEST_SetPower, /* __u8 request */
-+ SWIMS_USB_REQUEST_SetDevPower, /* __u8 request */
- USB_TYPE_VENDOR, /* __u8 request type */
- swiState, /* __u16 value */
- 0, /* __u16 index */
-@@ -57,7 +129,7 @@ static int sierra_set_power_state(struct
- static int sierra_vsc_set_nmea(struct usb_device *udev, __u16 enable)
- {
- int result;
-- dev_dbg(&udev->dev, "%s", __func__);
-+ dev_dbg(&udev->dev, "%s\n", __func__);
- result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
- SWIMS_USB_REQUEST_SetNmea, /* __u8 request */
- USB_TYPE_VENDOR, /* __u8 request type */
-@@ -69,28 +141,97 @@ static int sierra_vsc_set_nmea(struct us
- return result;
- }
-
--static int sierra_calc_num_ports(struct usb_serial *serial)
-+static int sierra_get_fw_attr(struct usb_device *udev, u16 *data)
- {
- int result;
-- int *num_ports = usb_get_serial_data(serial);
-- dev_dbg(&serial->dev->dev, "%s", __func__);
-+ u16 *attrdata;
-
-- result = *num_ports;
-+ dev_dbg(&udev->dev, "%s\n", __func__);
-
-- if (result) {
-- kfree(num_ports);
-- usb_set_serial_data(serial, NULL);
-+ attrdata = kmalloc(sizeof(*attrdata), GFP_KERNEL);
-+ if (!attrdata)
-+ return -ENOMEM;
-+
-+ result = usb_control_msg(udev,
-+ usb_rcvctrlpipe(udev, 0),
-+ SWIMS_USB_REQUEST_GetFwAttr, /* __u8 request*/
-+ USB_TYPE_VENDOR | USB_DIR_IN, /* request type*/
-+ 0x0000, /* __u16 value */
-+ 0x0000, /* __u16 index */
-+ attrdata, /* void *data */
-+ sizeof(*attrdata), /* _u16 size */
-+ USB_CTRL_SET_TIMEOUT); /* in timeout */
-+
-+ if (result < 0) {
-+ kfree(attrdata);
-+ return -EIO;
- }
-
-+ *data = *attrdata;
-+
-+ kfree(attrdata);
- return result;
- }
-
-+static int sierra_calc_num_ports(struct usb_serial *serial)
-+{
-+ int num_ports = 0;
-+ u8 ifnum, numendpoints;
-+
-+ dev_dbg(&serial->dev->dev, "%s\n", __func__);
-+
-+ ifnum = serial->interface->cur_altsetting->desc.bInterfaceNumber;
-+ numendpoints = serial->interface->cur_altsetting->desc.bNumEndpoints;
-+
-+ /* Dummy interface present on some SKUs should be ignored */
-+ if (ifnum == 0x99)
-+ num_ports = 0;
-+ else if (numendpoints <= 3)
-+ num_ports = 1;
-+ else
-+ num_ports = (numendpoints-1)/2;
-+ return num_ports;
-+}
-+
-+static int is_blacklisted(const u8 ifnum,
-+ const struct sierra_iface_info *blacklist)
-+{
-+ const u8 *info;
-+ int i;
-+
-+ if (blacklist) {
-+ info = blacklist->ifaceinfo;
-+
-+ for (i = 0; i < blacklist->infolen; i++) {
-+ if (info[i] == ifnum)
-+ return 1;
-+ }
-+ }
-+ return 0;
-+}
-+
-+static int is_himemory(const u8 ifnum,
-+ const struct sierra_iface_info *himemorylist)
-+{
-+ const u8 *info;
-+ int i;
-+
-+ if (himemorylist) {
-+ info = himemorylist->ifaceinfo;
-+
-+ for (i=0; i < himemorylist->infolen; i++) {
-+ if (info[i] == ifnum)
-+ return 1;
-+ }
-+ }
-+ return 0;
-+}
-+
- static int sierra_calc_interface(struct usb_serial *serial)
- {
- int interface;
- struct usb_interface *p_interface;
- struct usb_host_interface *p_host_interface;
-- dev_dbg(&serial->dev->dev, "%s", __func__);
-
- /* Get the interface structure pointer from the serial struct */
- p_interface = serial->interface;
-@@ -99,8 +240,7 @@ static int sierra_calc_interface(struct
- p_host_interface = p_interface->cur_altsetting;
-
- /* read the interface descriptor for this active altsetting
-- * to find out the interface number we are on
-- */
-+ * to find out the interface number we are on */
- interface = p_host_interface->desc.bInterfaceNumber;
-
- return interface;
-@@ -111,23 +251,15 @@ static int sierra_probe(struct usb_seria
- {
- int result = 0;
- struct usb_device *udev;
-- int *num_ports;
-- u8 ifnum;
-- u8 numendpoints;
--
-- dev_dbg(&serial->dev->dev, "%s", __func__);
--
-- num_ports = kmalloc(sizeof(*num_ports), GFP_KERNEL);
-- if (!num_ports)
-- return -ENOMEM;
-+ struct sierra_intf_private *intfdata;
-+ int alternate;
-+ u8 ifnum;
-
-- ifnum = serial->interface->cur_altsetting->desc.bInterfaceNumber;
-- numendpoints = serial->interface->cur_altsetting->desc.bNumEndpoints;
- udev = serial->dev;
-+ dev_dbg(&udev->dev, "%s\n", __func__);
-
-- /* Figure out the interface number from the serial structure */
- ifnum = sierra_calc_interface(serial);
--
-+ alternate = 0; /* go with the first */
- /*
- * If this interface supports more than 1 alternate
- * select the 2nd one
-@@ -135,62 +267,114 @@ static int sierra_probe(struct usb_seria
- if (serial->interface->num_altsetting == 2) {
- dev_dbg(&udev->dev, "Selecting alt setting for interface %d\n",
- ifnum);
-- /* We know the alternate setting is 1 for the MC8785 */
-- usb_set_interface(udev, ifnum, 1);
-+ /* We know the alternate setting is for composite USB interface
-+ * modems
-+ */
-+ alternate = 1;
- }
-+ usb_set_interface(udev, ifnum, alternate);
-
-- /* Dummy interface present on some SKUs should be ignored */
-- if (ifnum == 0x99)
-- *num_ports = 0;
-- else if (numendpoints <= 3)
-- *num_ports = 1;
-- else
-- *num_ports = (numendpoints-1)/2;
-+ /* ifnum could have changed - by calling usb_set_interface */
-+ ifnum = sierra_calc_interface(serial);
-
-- /*
-- * save off our num_ports info so that we can use it in the
-- * calc_num_ports callback
-- */
-- usb_set_serial_data(serial, (void *)num_ports);
-+ if (is_blacklisted(ifnum,
-+ (struct sierra_iface_info *)id->driver_info)) {
-+ dev_dbg(&serial->dev->dev,
-+ "Ignoring blacklisted interface #%d\n", ifnum);
-+ return -ENODEV;
-+ }
-+
-+ intfdata = serial->private = kzalloc(sizeof(struct sierra_intf_private),
-+ GFP_KERNEL);
-+ if (!intfdata)
-+ return -ENOMEM;
-+ spin_lock_init(&intfdata->susp_lock);
-+
-+ kref_init(&intfdata->ref_cnt);
-+ atomic_set(&intfdata->disconnected, 0);
-+ intfdata->serial = serial;
-+ intfdata->alternate = alternate;
-+ atomic_set(&intfdata->puts, 0);
-+ atomic_set(&intfdata->gets, 0);
-+ INIT_WORK(&intfdata->autopm_kevent, sierra_kevent);
-
- return result;
-+
- }
-
-+/* interfaces with higher memory requirements */
-+static const u8 hi_memory_typeA_ifaces[] = { 0, 2 };
-+static const struct sierra_iface_info typeA_interface_list = {
-+ .infolen = ARRAY_SIZE(hi_memory_typeA_ifaces),
-+ .ifaceinfo = hi_memory_typeA_ifaces,
-+};
-+
-+static const u8 hi_memory_typeB_ifaces[] = { 3, 4, 5, 6 };
-+static const struct sierra_iface_info typeB_interface_list = {
-+ .infolen = ARRAY_SIZE(hi_memory_typeB_ifaces),
-+ .ifaceinfo = hi_memory_typeB_ifaces,
-+};
-+
-+/* 'blacklist' of interfaces not served by this driver */
-+static const u8 direct_ip_non_serial_ifaces[] = { 7, 8, 9, 10, 11 };
-+static const struct sierra_iface_info direct_ip_interface_blacklist = {
-+ .infolen = ARRAY_SIZE( direct_ip_non_serial_ifaces ),
-+ .ifaceinfo = direct_ip_non_serial_ifaces,
-+};
-+
-+
- static struct usb_device_id id_table [] = {
-+ { USB_DEVICE(0x0F3D, 0x0112) }, /* Airprime/Sierra PC 5220 */
-+ { USB_DEVICE(0x03F0, 0x1B1D) }, /* HP ev2200 a.k.a MC5720 */
-+ { USB_DEVICE(0x03F0, 0x1E1D) }, /* HP hs2300 a.k.a MC8775 */
-+
- { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */
- { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */
- { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */
-- { USB_DEVICE(0x03f0, 0x1b1d) }, /* HP ev2200 a.k.a MC5720 */
- { USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */
-- { USB_DEVICE(0x1199, 0x0024) }, /* Sierra Wireless MC5727 */
- { USB_DEVICE(0x1199, 0x0220) }, /* Sierra Wireless MC5725 */
-+ { USB_DEVICE(0x1199, 0x0022) }, /* Sierra Wireless EM5725 */
-+ { USB_DEVICE(0x1199, 0x0024) }, /* Sierra Wireless MC5727 */
-+ { USB_DEVICE(0x1199, 0x0224) }, /* Sierra Wireless MC5727 */
- { USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */
- { USB_DEVICE(0x1199, 0x0021) }, /* Sierra Wireless AirCard 597E */
-+ { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless AirCard 580 */
- { USB_DEVICE(0x1199, 0x0120) }, /* Sierra Wireless USB Dongle 595U */
-- /* Sierra Wireless C597 */
-+ /* Sierra Wireless C597 */
- { USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x0023, 0xFF, 0xFF, 0xFF) },
-- /* Sierra Wireless Device */
-+ /* Sierra Wireless T598 */
- { USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x0025, 0xFF, 0xFF, 0xFF) },
-- { USB_DEVICE(0x1199, 0x0026) }, /* Sierra Wireless Device */
-- { USB_DEVICE(0x1199, 0x0027) }, /* Sierra Wireless Device */
-- { USB_DEVICE(0x1199, 0x0028) }, /* Sierra Wireless Device */
-+ { USB_DEVICE(0x1199, 0x0026) }, /* Sierra Wireless T11 */
-+ { USB_DEVICE(0x1199, 0x0027) }, /* Sierra Wireless AC402 */
-+ { USB_DEVICE(0x1199, 0x0028) }, /* Sierra Wireless MC5728 */
-+ { USB_DEVICE(0x1199, 0x0029) }, /* Sierra Wireless Device */
-
- { USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */
-- { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 */
- { USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */
-+ { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 */
-+ { USB_DEVICE(0x1199, 0x6805) }, /* Sierra Wireless MC8765 */
-+ { USB_DEVICE(0x1199, 0x6808) }, /* Sierra Wireless MC8755 */
-+ { USB_DEVICE(0x1199, 0x6809) }, /* Sierra Wireless MC8765 */
- { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 & AC 875U */
-- { USB_DEVICE(0x1199, 0x6813) }, /* Sierra Wireless MC8775 (Lenovo) */
-+ { USB_DEVICE(0x1199, 0x6813) }, /* Sierra Wireless MC8775 */
- { USB_DEVICE(0x1199, 0x6815) }, /* Sierra Wireless MC8775 */
-- { USB_DEVICE(0x03f0, 0x1e1d) }, /* HP hs2300 a.k.a MC8775 */
-+ { USB_DEVICE(0x1199, 0x6816) }, /* Sierra Wireless MC8775 */
- { USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */
- { USB_DEVICE(0x1199, 0x6821) }, /* Sierra Wireless AirCard 875U */
-+ { USB_DEVICE(0x1199, 0x6822) }, /* Sierra Wireless AirCard 875E */
- { USB_DEVICE(0x1199, 0x6832) }, /* Sierra Wireless MC8780 */
- { USB_DEVICE(0x1199, 0x6833) }, /* Sierra Wireless MC8781 */
-+ { USB_DEVICE(0x1199, 0x6834) }, /* Sierra Wireless MC8780 */
-+ { USB_DEVICE(0x1199, 0x6835) }, /* Sierra Wireless MC8781 */
-+ { USB_DEVICE(0x1199, 0x6838) }, /* Sierra Wireless MC8780 */
-+ { USB_DEVICE(0x1199, 0x6839) }, /* Sierra Wireless MC8781 */
- { USB_DEVICE(0x1199, 0x683A) }, /* Sierra Wireless MC8785 */
- { USB_DEVICE(0x1199, 0x683B) }, /* Sierra Wireless MC8785 Composite */
-- { USB_DEVICE(0x1199, 0x683C) }, /* Sierra Wireless MC8790 */
-- { USB_DEVICE(0x1199, 0x683D) }, /* Sierra Wireless MC8790 */
-- { USB_DEVICE(0x1199, 0x683E) }, /* Sierra Wireless MC8790 */
-+ /* Sierra Wireless MC8790, MC8791, MC8792 Composite */
-+ { USB_DEVICE(0x1199, 0x683C) },
-+ { USB_DEVICE(0x1199, 0x683D) }, /* Sierra Wireless MC8791 Composite */
-+ /* Sierra Wireless MC8790, MC8791, MC8792 */
-+ { USB_DEVICE(0x1199, 0x683E) },
- { USB_DEVICE(0x1199, 0x6850) }, /* Sierra Wireless AirCard 880 */
- { USB_DEVICE(0x1199, 0x6851) }, /* Sierra Wireless AirCard 881 */
- { USB_DEVICE(0x1199, 0x6852) }, /* Sierra Wireless AirCard 880 E */
-@@ -201,35 +385,35 @@ static struct usb_device_id id_table []
- { USB_DEVICE(0x1199, 0x685A) }, /* Sierra Wireless AirCard 885 E */
- /* Sierra Wireless C885 */
- { USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x6880, 0xFF, 0xFF, 0xFF)},
-- /* Sierra Wireless Device */
-+ /* Sierra Wireless C888, Air Card 501, USB 303, USB 304 */
- { USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x6890, 0xFF, 0xFF, 0xFF)},
-- /* Sierra Wireless Device */
-+ /* Sierra Wireless C22/C33 */
- { USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x6891, 0xFF, 0xFF, 0xFF)},
-- /* Sierra Wireless Device */
-+ /* Sierra Wireless HSPA Non-Composite Device */
- { USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x6892, 0xFF, 0xFF, 0xFF)},
--
-- { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless AirCard 580 */
-- { USB_DEVICE(0x0F3D, 0x0112) }, /* Airprime/Sierra PC 5220 */
-+ { USB_DEVICE(0x1199, 0x6893) }, /* Sierra Wireless Device */
-+ /* Sierra Wireless Direct IP modems */
-+ { USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x68A3, 0xFF, 0xFF, 0xFF),
-+ .driver_info = (kernel_ulong_t)&direct_ip_interface_blacklist
-+ },
-
- { }
- };
- MODULE_DEVICE_TABLE(usb, id_table);
-
--static struct usb_driver sierra_driver = {
-- .name = "sierra",
-- .probe = usb_serial_probe,
-- .disconnect = usb_serial_disconnect,
-- .id_table = id_table,
-- .no_dynamic_id = 1,
--};
-
-+/* per port private data */
- struct sierra_port_private {
- spinlock_t lock; /* lock the structure */
- int outstanding_urbs; /* number of out urbs in flight */
-
-+ struct usb_anchor active;
-+ struct usb_anchor delayed;
-+
-+ int num_out_urbs;
-+ int num_in_urbs;
- /* Input endpoints and buffers for this port */
-- struct urb *in_urbs[N_IN_URB];
-- char *in_buffer[N_IN_URB];
-+ struct urb *in_urbs[N_IN_URB_HM];
-
- /* Settings for the port */
- int rts_state; /* Handshaking pins (outputs) */
-@@ -238,29 +422,89 @@ struct sierra_port_private {
- int dsr_state;
- int dcd_state;
- int ri_state;
-+ unsigned int opened:1;
- };
-
-+static void destroy_intfdata(struct kref * kref)
-+{
-+ struct sierra_intf_private *intfdata;
-+ intfdata = container_of(kref, struct sierra_intf_private, ref_cnt);
-+
-+ dev_dbg(&intfdata->serial->dev->dev, "%s\n", __func__);
-+ kfree(intfdata);
-+
-+}
-+
-+static void inline intfdata_get(struct sierra_intf_private *intfdata)
-+{
-+ kref_get(&intfdata->ref_cnt);
-+}
-+
-+static void inline intfdata_put(struct sierra_intf_private *intfdata)
-+{
-+ kref_put(&intfdata->ref_cnt, destroy_intfdata);
-+}
-+
-+static void sierra_kevent(struct work_struct * work)
-+{
-+ int action;
-+ struct sierra_intf_private *intfdata;
-+
-+ intfdata = container_of(work, struct sierra_intf_private, autopm_kevent);
-+
-+ dev_dbg(&intfdata->serial->dev->dev, "%s\n", __func__);
-+
-+ do {
-+ action = 0;
-+
-+ while ( !atomic_read(&intfdata->disconnected) &&
-+ atomic_add_unless(&intfdata->gets,-1,0)) {
-+ usb_autopm_get_interface(intfdata->serial->interface);
-+ atomic_inc(&intfdata->stats.sync_gets);
-+ action |= 1;
-+ }
-+
-+ while ( !atomic_read(&intfdata->disconnected) &&
-+ atomic_add_unless(&intfdata->puts,-1,0)) {
-+ usb_autopm_put_interface(intfdata->serial->interface);
-+ atomic_inc(&intfdata->stats.sync_puts);
-+ action |= 1;
-+ }
-+
-+ } while(action);
-+
-+ intfdata_put(intfdata);
-+}
-+
- static int sierra_send_setup(struct tty_struct *tty,
-- struct usb_serial_port *port)
-+ struct usb_serial_port *port)
- {
- struct usb_serial *serial = port->serial;
-- struct sierra_port_private *portdata;
-+ struct sierra_port_private *portdata = usb_get_serial_port_data(port);
- __u16 interface = 0;
-+ int val = 0;
-+ int do_send = 0;
-+ int retval;
-
-- dev_dbg(&port->dev, "%s", __func__);
--
-- portdata = usb_get_serial_port_data(port);
-+ dev_dbg(&port->dev, "%s\n", __func__);
-
- if (tty) {
-- int val = 0;
- if (portdata->dtr_state)
- val |= 0x01;
- if (portdata->rts_state)
- val |= 0x02;
-
- /* If composite device then properly report interface */
-- if (serial->num_ports == 1)
-+ if (serial->num_ports == 1) {
- interface = sierra_calc_interface(serial);
-+ /* Control message is send only to interfaces with
-+ * interrupt_in endpoints
-+ */
-+ if(port->interrupt_in_urb) {
-+ /* send control message */
-+ do_send = 1;
-+ }
-+ }
-
- /* Otherwise the need to do non-composite mapping */
- else {
-@@ -270,21 +514,25 @@ static int sierra_send_setup(struct tty_
- interface = 1;
- else if (port->bulk_out_endpointAddress == 5)
- interface = 2;
-- }
-
-- return usb_control_msg(serial->dev,
-- usb_rcvctrlpipe(serial->dev, 0),
-- 0x22, 0x21, val, interface,
-- NULL, 0, USB_CTRL_SET_TIMEOUT);
-+ do_send = 1;
-+ }
- }
-+ if (!do_send)
-+ return 0;
-
-- return 0;
-+ usb_autopm_get_interface(serial->interface);
-+ retval = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
-+ 0x22, 0x21, val, interface, NULL, 0, USB_CTRL_SET_TIMEOUT);
-+ usb_autopm_put_interface(serial->interface);
-+
-+ return retval;
- }
-
- static void sierra_set_termios(struct tty_struct *tty,
- struct usb_serial_port *port, struct ktermios *old_termios)
- {
-- dev_dbg(&port->dev, "%s", __func__);
-+ dev_dbg(&port->dev, "%s\n", __func__);
- tty_termios_copy_hw(tty->termios, old_termios);
- sierra_send_setup(tty, port);
- }
-@@ -295,7 +543,7 @@ static int sierra_tiocmget(struct tty_st
- unsigned int value;
- struct sierra_port_private *portdata;
-
-- dev_dbg(&port->dev, "%s", __func__);
-+ dev_dbg(&port->dev, "%s\n", __func__);
- portdata = usb_get_serial_port_data(port);
-
- value = ((portdata->rts_state) ? TIOCM_RTS : 0) |
-@@ -328,25 +576,303 @@ static int sierra_tiocmset(struct tty_st
- return sierra_send_setup(tty, port);
- }
-
-+static void sierra_release_urb(struct urb *urb)
-+{
-+ struct usb_serial_port *port;
-+ if (urb) {
-+ port = urb->context;
-+ dev_dbg(&port->dev, "%s: %p\n", __func__, urb);
-+ usb_free_urb(urb);
-+ }
-+}
-+
-+/* Sysfs Attributes */
-+static ssize_t show_suspend_status(struct device *dev,
-+ struct device_attribute *attr, char *buf)
-+{
-+ struct usb_serial_port *port;
-+ struct sierra_intf_private *intfdata;
-+ unsigned long flags;
-+ unsigned int flag_suspended;
-+
-+ port = to_usb_serial_port(dev);
-+ intfdata = port->serial->private;
-+
-+ spin_lock_irqsave(&intfdata->susp_lock, flags);
-+ flag_suspended = intfdata->suspended;
-+ spin_unlock_irqrestore(&intfdata->susp_lock, flags);
-+
-+ return snprintf(buf, PORTION_LEN, "%i %i %i\n",
-+ flag_suspended,
-+ port->serial->interface->pm_usage_cnt,
-+ port->serial->dev->pm_usage_cnt);
-+}
-+
-+static ssize_t show_stats(struct device *dev,
-+ struct device_attribute *attr, char *buf)
-+{
-+ struct usb_serial_port *port;
-+ struct sierra_intf_private *intfdata;
-+
-+ port = to_usb_serial_port(dev);
-+ intfdata = port->serial->private;
-+
-+ return snprintf(buf, 4096,
-+ "rx: %i B\tindat: %i\tindat err: %i\n"
-+ "tx: %i B\toutdat: %i\toutdat err: %i\n"
-+ "writes: %i\t\twrite err: %i\n"
-+ "delayed writes: %i\tdelayed write err: %i\n"
-+ "gets: %i/%i\tputs %i/%i\n" ,
-+ atomic_read(&intfdata->stats.rx_bytes), atomic_read(&intfdata->stats.indat_cb_cnt), atomic_read(&intfdata->stats.indat_cb_fail),
-+ atomic_read(&intfdata->stats.tx_bytes), atomic_read(&intfdata->stats.outdat_cb_cnt), atomic_read(&intfdata->stats.outdat_cb_fail),
-+ atomic_read(&intfdata->stats.write_cnt), atomic_read(&intfdata->stats.write_err),
-+ atomic_read(&intfdata->stats.delayed_writes), atomic_read(&intfdata->stats.delayed_write_err),
-+ atomic_read(&intfdata->stats.async_gets), atomic_read(&intfdata->stats.sync_gets),
-+ atomic_read(&intfdata->stats.async_puts), atomic_read(&intfdata->stats.sync_puts)
-+ );
-+}
-+
-+/* Read only suspend status */
-+static DEVICE_ATTR(suspend_status, S_IWUSR | S_IRUGO, show_suspend_status,
-+ NULL);
-+
-+/* Read only statistics */
-+static DEVICE_ATTR(stats, S_IWUSR | S_IRUGO, show_stats, NULL);
-+
-+static int sierra_create_sysfs_attrs(struct usb_serial_port *port)
-+{
-+ int result = 0;
-+
-+ result = device_create_file(&port->dev, &dev_attr_stats);
-+ if (unlikely (result < 0))
-+ return result;
-+ return device_create_file(&port->dev, &dev_attr_suspend_status);
-+}
-+
-+static int sierra_remove_sysfs_attrs(struct usb_serial_port *port)
-+{
-+ device_remove_file(&port->dev, &dev_attr_stats);
-+ device_remove_file(&port->dev, &dev_attr_suspend_status);
-+ return 0;
-+}
-+
-+static void sierra_stop_rx_urbs(struct usb_serial_port *port)
-+{
-+ int i;
-+ struct sierra_port_private *portdata = usb_get_serial_port_data(port);
-+
-+ for (i = 0; i < portdata->num_in_urbs; i++) {
-+ usb_kill_urb(portdata->in_urbs[i]);
-+ }
-+ usb_kill_urb(port->interrupt_in_urb);
-+}
-+
-+static int sierra_submit_rx_urbs(struct usb_serial_port *port, gfp_t mem_flags)
-+{
-+ int ok_cnt;
-+ int err = -EINVAL;
-+ int i;
-+ struct urb *urb;
-+ struct sierra_port_private *portdata = usb_get_serial_port_data(port);
-+
-+ ok_cnt = 0;
-+ for (i = 0; i < portdata->num_in_urbs; i++) {
-+ urb = portdata->in_urbs[i];
-+ if (!urb)
-+ continue;
-+
-+ urb->transfer_flags |= URB_FREE_BUFFER;
-+ err = usb_submit_urb(urb, mem_flags);
-+ if (err) {
-+ dev_err(&port->dev, "%s: submit urb failed: %d\n",
-+ __func__, err);
-+ } else {
-+ ok_cnt++;
-+ }
-+ }
-+
-+ if (ok_cnt && port->interrupt_in_urb) {
-+ err = usb_submit_urb(port->interrupt_in_urb, mem_flags);
-+ if (err) {
-+ dev_err(&port->dev, "%s: submit intr urb failed: %d\n",
-+ __func__, err);
-+ }
-+ }
-+
-+ if (ok_cnt > 0) /* at least one rx urb submitted */
-+ return 0;
-+ else
-+ return err;
-+}
-+
-+#ifdef CONFIG_PM
-+static int schedule_sync_work(struct sierra_intf_private *intfdata)
-+{
-+ int scheduled;
-+
-+ intfdata_get(intfdata);
-+ scheduled = schedule_work(&intfdata->autopm_kevent);
-+ if (!scheduled) {
-+ /* was scheduled already, fix reference count */
-+ intfdata_put(intfdata);
-+ }
-+ return scheduled;
-+}
-+
-+static int sierra_autopm_get_interface_async(struct sierra_intf_private *intfdata)
-+{
-+ atomic_inc(&intfdata->stats.async_gets);
-+ atomic_inc(&intfdata->gets);
-+ return schedule_sync_work(intfdata);
-+}
-+static int sierra_autopm_put_interface_async(struct sierra_intf_private *intfdata)
-+{
-+ atomic_inc(&intfdata->stats.async_puts);
-+ atomic_inc(&intfdata->puts);
-+ return schedule_sync_work(intfdata);
-+}
-+
-+static void stop_read_write_urbs(struct usb_serial *serial)
-+{
-+ int i;
-+ struct usb_serial_port *port;
-+ struct sierra_port_private *portdata;
-+
-+ /* Stop reading/writing urbs */
-+ for (i = 0; i < serial->num_ports; ++i) {
-+ port = serial->port[i];
-+ portdata = usb_get_serial_port_data(port);
-+ sierra_stop_rx_urbs(port);
-+
-+ usb_kill_anchored_urbs(&portdata->active);
-+ }
-+}
-+
-+static int sierra_suspend(struct usb_serial *serial, pm_message_t message)
-+{
-+ struct sierra_intf_private *intfdata;
-+
-+ dev_dbg(&serial->dev->dev, "%s\n", __func__);
-+
-+ intfdata = serial->private;
-+ spin_lock_irq(&intfdata->susp_lock);
-+
-+ if (serial->dev->auto_pm) {
-+ if (intfdata->in_flight) {
-+ spin_unlock_irq(&intfdata->susp_lock);
-+ return -EBUSY;
-+ }
-+ }
-+
-+ intfdata->suspended = 1;
-+ spin_unlock_irq(&intfdata->susp_lock);
-+
-+ stop_read_write_urbs(serial);
-+
-+ return 0;
-+}
-+
-+static int sierra_resume(struct usb_serial *serial)
-+{
-+ struct usb_serial_port *port;
-+ struct sierra_intf_private *intfdata = serial->private;
-+ struct sierra_port_private *portdata;
-+ struct urb *urb;
-+ int ec = 0;
-+ int i, err;
-+ int len;
-+ int failed_submits;
-+
-+ dev_dbg(&serial->dev->dev, "%s\n", __func__);
-+
-+ spin_lock_irq(&intfdata->susp_lock);
-+ for (i = 0; i < serial->num_ports; i++) {
-+ port = serial->port[i];
-+ portdata = usb_get_serial_port_data(port);
-+ failed_submits = 0;
-+ while ((urb = usb_get_from_anchor(&portdata->delayed))) {
-+ usb_anchor_urb(urb, &portdata->active);
-+ intfdata->in_flight++;
-+ len = urb->transfer_buffer_length;
-+ err = usb_submit_urb(urb, GFP_ATOMIC);
-+ if (err < 0) {
-+ intfdata->in_flight--;
-+ usb_unanchor_urb(urb);
-+ failed_submits++;
-+ atomic_inc(&intfdata->stats.delayed_write_err);
-+ /* fix pm_usage_cnt */
-+ sierra_autopm_put_interface_async(intfdata);
-+ } else {
-+ atomic_inc(&intfdata->stats.delayed_writes);
-+ atomic_add(len, &intfdata->stats.tx_bytes);
-+ }
-+ /* release urb - usb_get_from_anchor increased kref */
-+ usb_free_urb(urb);
-+ }
-+
-+ if (portdata->opened) {
-+ err = sierra_submit_rx_urbs(port, GFP_ATOMIC);
-+ if (err)
-+ ec++;
-+ }
-+ if (failed_submits) {
-+ /* fix outstanding_urbs counter */
-+ spin_lock(&portdata->lock); /* assuming irq disabled */
-+ portdata->outstanding_urbs -= failed_submits;
-+ spin_unlock(&portdata->lock);
-+ /* unblock a writer */
-+ usb_serial_port_softint(port);
-+ }
-+ }
-+ intfdata->suspended = 0;
-+ spin_unlock_irq(&intfdata->susp_lock);
-+
-+ return ec ? -EIO : 0;
-+}
-+#else
-+#define sierra_suspend NULL
-+#define sierra_resume NULL
-+
-+static int inline sierra_autopm_get_interface_async(struct sierra_intf_private *intfdata)
-+{
-+ (void)intfdata;
-+ return 0;
-+}
-+
-+static int inline sierra_autopm_put_interface_async(struct sierra_intf_private *intfdata)
-+{
-+ (void)intfdata;
-+ return 0;
-+}
-+#endif
-+
- static void sierra_outdat_callback(struct urb *urb)
- {
- struct usb_serial_port *port = urb->context;
- struct sierra_port_private *portdata = usb_get_serial_port_data(port);
-+ struct sierra_intf_private *intfdata;
- int status = urb->status;
-- unsigned long flags;
-
-- dev_dbg(&port->dev, "%s - port %d", __func__, port->number);
-+ dev_dbg(&port->dev, "%s - port %d\n", __func__, port->number);
-+ intfdata = port->serial->private;
-+
-+ sierra_autopm_put_interface_async(intfdata);
-
-- /* free up the transfer buffer, as usb_free_urb() does not do this */
-- kfree(urb->transfer_buffer);
-+ atomic_inc(&intfdata->stats.outdat_cb_cnt);
-
-- if (status)
-+ if (status) {
- dev_dbg(&port->dev, "%s - nonzero write bulk status "
-- "received: %d", __func__, status);
-+ "received: %d\n", __func__, status);
-+ atomic_inc(&intfdata->stats.outdat_cb_fail);
-+ }
-
-- spin_lock_irqsave(&portdata->lock, flags);
-+ spin_lock(&portdata->lock);
- --portdata->outstanding_urbs;
-- spin_unlock_irqrestore(&portdata->lock, flags);
-+ spin_unlock(&portdata->lock);
-+
-+ spin_lock(&intfdata->susp_lock);
-+ --intfdata->in_flight;
-+ spin_unlock(&intfdata->susp_lock);
-
- usb_serial_port_softint(port);
- }
-@@ -356,109 +882,169 @@ static int sierra_write(struct tty_struc
- const unsigned char *buf, int count)
- {
- struct sierra_port_private *portdata = usb_get_serial_port_data(port);
-+ struct sierra_intf_private *intfdata;
- struct usb_serial *serial = port->serial;
- unsigned long flags;
- unsigned char *buffer;
- struct urb *urb;
-- int status;
-+ size_t writesize = min((size_t)count, (size_t)MAX_TRANSFER);
-+ int retval = 0;
-
-- portdata = usb_get_serial_port_data(port);
-+ /* verify that we actually have some data to write */
-+ if (count == 0)
-+ return 0;
-
-- dev_dbg(&port->dev, "%s: write (%d chars)", __func__, count);
-+ dev_dbg(&port->dev, "%s: write (%zu bytes)\n", __func__, writesize);
-+
-+ intfdata = serial->private;
-
- spin_lock_irqsave(&portdata->lock, flags);
-- if (portdata->outstanding_urbs > N_OUT_URB) {
-+ if (portdata->outstanding_urbs > portdata->num_out_urbs) {
- spin_unlock_irqrestore(&portdata->lock, flags);
-- dev_dbg(&port->dev, "%s - write limit hit\n", __func__);
- return 0;
- }
- portdata->outstanding_urbs++;
- spin_unlock_irqrestore(&portdata->lock, flags);
-
-- buffer = kmalloc(count, GFP_ATOMIC);
-+ retval = sierra_autopm_get_interface_async(intfdata);
-+ if (unlikely(retval < 0)) {
-+ spin_lock_irqsave(&portdata->lock, flags);
-+ portdata->outstanding_urbs--;
-+ spin_unlock_irqrestore(&portdata->lock, flags);
-+ return retval;
-+ }
-+
-+ buffer = kmalloc(writesize, GFP_ATOMIC);
- if (!buffer) {
- dev_err(&port->dev, "out of memory\n");
-- count = -ENOMEM;
-- goto error_no_buffer;
-+ spin_lock_irqsave(&portdata->lock, flags);
-+ --portdata->outstanding_urbs;
-+ spin_unlock_irqrestore(&portdata->lock, flags);
-+ sierra_autopm_put_interface_async(intfdata);
-+ return -ENOMEM;
- }
-
- urb = usb_alloc_urb(0, GFP_ATOMIC);
- if (!urb) {
- dev_err(&port->dev, "no more free urbs\n");
-- count = -ENOMEM;
-- goto error_no_urb;
-+ kfree(buffer);
-+ spin_lock_irqsave(&portdata->lock, flags);
-+ --portdata->outstanding_urbs;
-+ spin_unlock_irqrestore(&portdata->lock, flags);
-+ sierra_autopm_put_interface_async(intfdata);
-+ return -ENOMEM;
- }
-
-- memcpy(buffer, buf, count);
-+ memcpy(buffer, buf, writesize);
-
-- usb_serial_debug_data(debug, &port->dev, __func__, count, buffer);
-+ usb_serial_debug_data(debug, &port->dev, __func__, writesize, buffer);
-
- usb_fill_bulk_urb(urb, serial->dev,
- usb_sndbulkpipe(serial->dev,
- port->bulk_out_endpointAddress),
-- buffer, count, sierra_outdat_callback, port);
-+ buffer, writesize, sierra_outdat_callback, port);
-
-- /* send it down the pipe */
-- status = usb_submit_urb(urb, GFP_ATOMIC);
-- if (status) {
-- dev_err(&port->dev, "%s - usb_submit_urb(write bulk) failed "
-- "with status = %d\n", __func__, status);
-- count = status;
-- goto error;
-+ /* Handle the need to send a zero length packet and release the
-+ * transfer buffer
-+ */
-+ urb->transfer_flags |= (URB_ZERO_PACKET | URB_FREE_BUFFER);
-+
-+ spin_lock_irqsave(&intfdata->susp_lock, flags);
-+
-+ if (intfdata->suspended) {
-+ usb_anchor_urb(urb, &portdata->delayed);
-+ spin_unlock_irqrestore(&intfdata->susp_lock, flags);
-+ /* release our reference to this urb, the USB core will
-+ * eventually free it entirely */
-+ usb_free_urb(urb);
-+ return writesize;
- }
-
-- /* we are done with this urb, so let the host driver
-- * really free it when it is finished with it */
-- usb_free_urb(urb);
-+ usb_anchor_urb(urb, &portdata->active);
-
-- return count;
--error:
-+ /* send it down the pipe */
-+ retval = usb_submit_urb(urb, GFP_ATOMIC);
-+ if (retval) {
-+ usb_unanchor_urb(urb);
-+ spin_unlock_irqrestore(&intfdata->susp_lock, flags);
-+ dev_err(&port->dev, "%s - usb_submit_urb(write bulk) failed "
-+ "with status = %d\n", __func__, retval);
-+ usb_free_urb(urb);
-+ spin_lock_irqsave(&portdata->lock, flags);
-+ --portdata->outstanding_urbs;
-+ spin_unlock_irqrestore(&portdata->lock, flags);
-+ sierra_autopm_put_interface_async(intfdata);
-+ atomic_inc(&intfdata->stats.write_err);
-+ return retval;
-+ } else {
-+ intfdata->in_flight++;
-+ spin_unlock_irqrestore(&intfdata->susp_lock, flags);
-+ atomic_inc(&intfdata->stats.write_cnt);
-+ atomic_add(writesize, &intfdata->stats.tx_bytes);
-+ }
-+ /* release our reference to this urb, the USB core will eventually
-+ * free it entirely */
- usb_free_urb(urb);
--error_no_urb:
-- kfree(buffer);
--error_no_buffer:
-- spin_lock_irqsave(&portdata->lock, flags);
-- --portdata->outstanding_urbs;
-- spin_unlock_irqrestore(&portdata->lock, flags);
-- return count;
-+ return writesize;
- }
-
- static void sierra_indat_callback(struct urb *urb)
- {
- int err;
- int endpoint;
-- struct usb_serial_port *port;
-+ struct usb_serial_port *port = urb->context;
- struct tty_struct *tty;
-+ struct sierra_intf_private *intfdata;
- unsigned char *data = urb->transfer_buffer;
- int status = urb->status;
-
-- dbg("%s: %p", __func__, urb);
--
- endpoint = usb_pipeendpoint(urb->pipe);
-- port = urb->context;
-+
-+ dev_dbg(&port->dev, "%s: %p\n", __func__, urb);
-+
-+ intfdata = port->serial->private;
-+
-+ atomic_inc(&intfdata->stats.indat_cb_cnt); /* indat calls */
-
- if (status) {
- dev_dbg(&port->dev, "%s: nonzero status: %d on"
-- " endpoint %02x.", __func__, status, endpoint);
-+ " endpoint %02x\n", __func__, status, endpoint);
-+ atomic_inc(&intfdata->stats.indat_cb_fail); /* indat fails */
- } else {
- if (urb->actual_length) {
-- tty = tty_port_tty_get(&port->port);
-- tty_buffer_request_room(tty, urb->actual_length);
-- tty_insert_flip_string(tty, data, urb->actual_length);
-- tty_flip_buffer_push(tty);
-- tty_kref_put(tty);
-- } else
-+ tty = tty_port_tty_get(&port->port);
-+ if (tty) {
-+ tty_buffer_request_room(tty,
-+ urb->actual_length);
-+ tty_insert_flip_string(tty, data,
-+ urb->actual_length);
-+ tty_flip_buffer_push(tty);
-+
-+ tty_kref_put(tty);
-+ /* tty invalid after this point */
-+
-+ /* rx'd bytes */
-+ atomic_add(urb->actual_length,
-+ &intfdata->stats.rx_bytes);
-+ usb_serial_debug_data(debug, &port->dev,
-+ __func__, urb->actual_length, data);
-+ }
-+ } else {
- dev_dbg(&port->dev, "%s: empty read urb"
-- " received", __func__);
--
-- /* Resubmit urb so we continue receiving */
-- if (port->port.count && status != -ESHUTDOWN) {
-- err = usb_submit_urb(urb, GFP_ATOMIC);
-- if (err)
-- dev_err(&port->dev, "resubmit read urb failed."
-- "(%d)\n", err);
-+ " received\n", __func__);
- }
- }
-+
-+ /* Resubmit urb so we continue receiving */
-+ if (port->port.count &&
-+ status != -ESHUTDOWN && status != -ENOENT && status != -ENODEV) {
-+ usb_mark_last_busy(port->serial->dev);
-+ err = usb_submit_urb(urb, GFP_ATOMIC);
-+ if (err && err != -ENODEV)
-+ dev_err(&port->dev, "resubmit read urb failed."
-+ "(%d)\n", err);
-+ }
-+
- return;
- }
-
-@@ -470,32 +1056,30 @@ static void sierra_instat_callback(struc
- struct sierra_port_private *portdata = usb_get_serial_port_data(port);
- struct usb_serial *serial = port->serial;
-
-- dev_dbg(&port->dev, "%s", __func__);
-- dev_dbg(&port->dev, "%s: urb %p port %p has data %p", __func__,
-+ dev_dbg(&port->dev, "%s: urb %p port %p has data %p\n", __func__,
- urb, port, portdata);
-
- if (status == 0) {
- struct usb_ctrlrequest *req_pkt =
- (struct usb_ctrlrequest *)urb->transfer_buffer;
-
-- if (!req_pkt) {
-- dev_dbg(&port->dev, "%s: NULL req_pkt\n",
-- __func__);
-- return;
-- }
-- if ((req_pkt->bRequestType == 0xA1) &&
-- (req_pkt->bRequest == 0x20)) {
-+ const u16 *sigp = (u16 *)(req_pkt + 1);
-+ /* usb_ctrlrequest we parsed is followed by two bytes of data
-+ * make sure we received that many bytes
-+ */
-+ if (urb->actual_length >= sizeof(*req_pkt) + sizeof(*sigp) &&
-+ req_pkt->bRequestType == USB_REQUEST_TYPE_CLASS &&
-+ req_pkt->bRequest == USB_REQUEST_IFACE) {
- int old_dcd_state;
-- unsigned char signals = *((unsigned char *)
-- urb->transfer_buffer +
-- sizeof(struct usb_ctrlrequest));
-+ const u16 signals = get_unaligned_le16(sigp);
- struct tty_struct *tty;
-
-- dev_dbg(&port->dev, "%s: signal x%x", __func__,
-+ dev_dbg(&port->dev, "%s: signal x%x\n", __func__,
- signals);
-
- old_dcd_state = portdata->dcd_state;
-- portdata->cts_state = 1;
-+ /* Note: CTS from modem is in reverse logic! */
-+ portdata->cts_state = ((signals & 0x100) ? 0 : 1);
- portdata->dcd_state = ((signals & 0x01) ? 1 : 0);
- portdata->dsr_state = ((signals & 0x02) ? 1 : 0);
- portdata->ri_state = ((signals & 0x08) ? 1 : 0);
-@@ -506,20 +1090,22 @@ static void sierra_instat_callback(struc
- tty_hangup(tty);
- tty_kref_put(tty);
- } else {
-- dev_dbg(&port->dev, "%s: type %x req %x",
-- __func__, req_pkt->bRequestType,
-- req_pkt->bRequest);
-+ /* dump the data we don't understand to log */
-+ usb_serial_debug_data(1, &port->dev, __func__,
-+ urb->actual_length, urb->transfer_buffer);
- }
- } else
-- dev_dbg(&port->dev, "%s: error %d", __func__, status);
-+ dev_dbg(&port->dev, "%s: error %d\n", __func__, status);
-
- /* Resubmit urb so we continue receiving IRQ data */
-- if (status != -ESHUTDOWN) {
-+ if (port->port.count &&
-+ status != -ESHUTDOWN && status != -ENOENT && status != -ENODEV) {
-+ usb_mark_last_busy(serial->dev);
- urb->dev = serial->dev;
- err = usb_submit_urb(urb, GFP_ATOMIC);
-- if (err)
-- dev_dbg(&port->dev, "%s: resubmit intr urb "
-- "failed. (%d)", __func__, err);
-+ if (err && err != -ENODEV)
-+ dev_err(&port->dev, "%s: resubmit intr urb "
-+ "failed. (%d)\n", __func__, err);
- }
- }
-
-@@ -528,115 +1114,168 @@ static int sierra_write_room(struct tty_
- struct usb_serial_port *port = tty->driver_data;
- struct sierra_port_private *portdata = usb_get_serial_port_data(port);
- unsigned long flags;
-+ int retval;
-
-- dev_dbg(&port->dev, "%s - port %d", __func__, port->number);
-+ dev_dbg(&port->dev, "%s - port %d\n", __func__, port->number);
-
- /* try to give a good number back based on if we have any free urbs at
- * this point in time */
-+ retval = MAX_TRANSFER;
-+
- spin_lock_irqsave(&portdata->lock, flags);
-- if (portdata->outstanding_urbs > N_OUT_URB * 2 / 3) {
-- spin_unlock_irqrestore(&portdata->lock, flags);
-- dev_dbg(&port->dev, "%s - write limit hit\n", __func__);
-- return 0;
-+ if (portdata->outstanding_urbs >= portdata->num_out_urbs) {
-+ retval = 0;
- }
- spin_unlock_irqrestore(&portdata->lock, flags);
-
-- return 2048;
-+ return retval;
- }
-
--static int sierra_open(struct tty_struct *tty,
-- struct usb_serial_port *port, struct file *filp)
-+static struct urb *sierra_setup_urb(struct usb_serial *serial, int endpoint,
-+ int dir, void *ctx, int len,
-+ usb_complete_t callback)
- {
-- struct sierra_port_private *portdata;
-- struct usb_serial *serial = port->serial;
-- int i;
-- struct urb *urb;
-- int result;
--
-- portdata = usb_get_serial_port_data(port);
-+ struct urb *urb;
-+ u8 *buf;
-
-- dev_dbg(&port->dev, "%s", __func__);
--
-- /* 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) {
-- dev_dbg(&port->dev, "%s: dev %p != %p",
-- __func__, urb->dev, serial->dev);
-- continue;
-- }
--
-- /*
-- * make sure endpoint data toggle is synchronized with the
-- * device
-- */
-- usb_clear_halt(urb->dev, urb->pipe);
-+ if (endpoint == -1)
-+ return NULL;
-
-- result = usb_submit_urb(urb, GFP_KERNEL);
-- if (result) {
-- dev_err(&port->dev, "submit urb %d failed (%d) %d\n",
-- i, result, urb->transfer_buffer_length);
-- }
-+ urb = usb_alloc_urb( 0, GFP_KERNEL );
-+ if (urb == NULL) {
-+ dev_dbg(&serial->dev->dev, "%s: alloc for endpoint %d failed\n",
-+ __func__, endpoint);
-+ return NULL;
- }
-
-- if (tty)
-- tty->low_latency = 1;
--
-- sierra_send_setup(tty, port);
-+ buf = kmalloc(len, GFP_KERNEL);
-+ if (buf)
-+ {
-+ /* Fill URB using supplied data */
-+ usb_fill_bulk_urb(urb, serial->dev,
-+ usb_sndbulkpipe(serial->dev, endpoint) | dir,
-+ buf, len, callback, ctx);
-+
-+ /* debug */
-+ dev_dbg(&serial->dev->dev,"%s %c u:%p d:%p\n", __func__,
-+ dir == USB_DIR_IN?'i':'o', urb, buf );
-+ } else {
-+ dev_dbg(&serial->dev->dev,"%s %c u:%p d:%p\n", __func__,
-+ dir == USB_DIR_IN?'i':'o', urb, buf );
-
-- /* start up the interrupt endpoint if we have one */
-- if (port->interrupt_in_urb) {
-- result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
-- if (result)
-- dev_err(&port->dev, "submit irq_in urb failed %d\n",
-- result);
-+ sierra_release_urb(urb);
-+ urb = NULL;
- }
-- return 0;
-+
-+ return urb;
- }
-
- static void sierra_close(struct tty_struct *tty,
- struct usb_serial_port *port, struct file *filp)
- {
- int i;
-+ struct urb *urb;
- struct usb_serial *serial = port->serial;
- struct sierra_port_private *portdata;
-+ struct sierra_intf_private *intfdata = port->serial->private;
-
-- dev_dbg(&port->dev, "%s", __func__);
-+ dev_dbg(&port->dev, "%s\n", __func__);
- portdata = usb_get_serial_port_data(port);
-
- portdata->rts_state = 0;
- portdata->dtr_state = 0;
-+ usb_autopm_get_interface(serial->interface);
-
- if (serial->dev) {
- mutex_lock(&serial->disc_mutex);
- if (!serial->disconnected)
- sierra_send_setup(tty, port);
- mutex_unlock(&serial->disc_mutex);
-+ spin_lock_irq(&intfdata->susp_lock);
-+ portdata->opened = 0;
-+ spin_unlock_irq(&intfdata->susp_lock);
-+
-+ /* Stop reading urbs */
-+ sierra_stop_rx_urbs(port);
-+ /* .. and release them */
-+ for (i = 0; i < portdata->num_in_urbs; i++) {
-+ sierra_release_urb(portdata->in_urbs[i]);
-+ portdata->in_urbs[i] = NULL;
-+ }
-
-- /* Stop reading/writing urbs */
-- for (i = 0; i < N_IN_URB; i++)
-- usb_kill_urb(portdata->in_urbs[i]);
-- }
-+ while((urb = usb_get_from_anchor(&portdata->delayed))) {
-+ sierra_release_urb(urb);
-+ usb_autopm_put_interface(serial->interface);
-+ }
-
-- usb_kill_urb(port->interrupt_in_urb);
-- tty_port_tty_set(&port->port, NULL);
-+ /* wait for active to finish */
-+ usb_wait_anchor_empty_timeout(&portdata->active, 500);
-+ usb_kill_anchored_urbs(&portdata->active);
-+ }
- }
-
--static int sierra_startup(struct usb_serial *serial)
-+static int sierra_open(struct tty_struct *tty,
-+ struct usb_serial_port *port, struct file *filp)
- {
-- struct usb_serial_port *port;
- struct sierra_port_private *portdata;
-+ struct usb_serial *serial = port->serial;
-+ struct sierra_intf_private *intfdata = serial->private;
-+ int i;
-+ int err;
-+ int endpoint;
- struct urb *urb;
-+
-+ portdata = usb_get_serial_port_data(port);
-+
-+ dev_dbg(&port->dev, "%s\n", __func__);
-+
-+ /* Set some sane defaults */
-+ portdata->rts_state = 1;
-+ portdata->dtr_state = 1;
-+
-+ endpoint = port->bulk_in_endpointAddress;
-+
-+ for (i = 0; i < portdata->num_in_urbs; i++) {
-+ urb = sierra_setup_urb(serial, endpoint, USB_DIR_IN, port,
-+ IN_BUFLEN, sierra_indat_callback);
-+ portdata->in_urbs[i] = urb;
-+ }
-+ /* clear halt condition */
-+ usb_clear_halt(serial->dev,
-+ usb_sndbulkpipe(serial->dev, endpoint) | USB_DIR_IN);
-+
-+ /* reset outstanding out urbs counter */
-+ spin_lock_irq(&portdata->lock);
-+ portdata->outstanding_urbs = 0;
-+ spin_unlock_irq(&portdata->lock);
-+
-+ err = sierra_submit_rx_urbs(port, GFP_KERNEL);
-+ if (err) {
-+ /* get rid of everything as in close */
-+ sierra_close(tty, port, filp);
-+ usb_autopm_put_interface(serial->interface);
-+ return err;
-+ }
-+ sierra_send_setup(tty, port);
-+ spin_lock_irq(&intfdata->susp_lock);
-+ portdata->opened = 1;
-+ spin_unlock_irq(&intfdata->susp_lock);
-+ usb_autopm_put_interface(serial->interface);
-+
-+ return 0;
-+}
-+
-+static int sierra_startup(struct usb_serial *serial)
-+{
-+ struct usb_serial_port *port = NULL;
-+ struct sierra_port_private *portdata = NULL;
-+ struct sierra_iface_info *himemoryp = NULL;
- int i;
-- int j;
-+ u8 ifnum;
-+ u16 fw_attr;
-+ int result;
-
-- dev_dbg(&serial->dev->dev, "%s", __func__);
-+ dev_dbg(&serial->dev->dev, "%s\n", __func__);
-
- /* Set Device mode to D0 */
- sierra_set_power_state(serial->dev, 0x0000);
-@@ -645,45 +1284,77 @@ static int sierra_startup(struct usb_ser
- if (nmea)
- sierra_vsc_set_nmea(serial->dev, 1);
-
-- /* Now setup per port private data */
-- for (i = 0; i < serial->num_ports; i++) {
-- port = serial->port[i];
-- portdata = kzalloc(sizeof(*portdata), GFP_KERNEL);
-+ if (serial->num_ports) {
-+ /* Note: One big piece of memory is allocated for all ports
-+ * private data in one shot. This memory is split into equal
-+ * pieces for each port.
-+ */
-+ portdata = (struct sierra_port_private *)kzalloc
-+ (sizeof(*portdata) * serial->num_ports, GFP_KERNEL);
- if (!portdata) {
-- dev_dbg(&port->dev, "%s: kmalloc for "
-- "sierra_port_private (%d) failed!.",
-- __func__, i);
-+ dev_dbg(&serial->dev->dev, "%s: No memory!\n", __func__);
- return -ENOMEM;
- }
-+ }
-+ /* Now setup per port private data */
-+ for (i = 0; i < serial->num_ports; i++, portdata++) {
-+ port = serial->port[i];
-+ /* Initialize selected members of private data because these
-+ * may be referred to right away */
- spin_lock_init(&portdata->lock);
-- for (j = 0; j < N_IN_URB; j++) {
-- portdata->in_buffer[j] = kmalloc(IN_BUFLEN, GFP_KERNEL);
-- if (!portdata->in_buffer[j]) {
-- for (--j; j >= 0; j--)
-- kfree(portdata->in_buffer[j]);
-- kfree(portdata);
-- return -ENOMEM;
-+ init_usb_anchor(&portdata->active);
-+ init_usb_anchor(&portdata->delayed);
-+ portdata->cts_state = 1;
-+ ifnum = i;
-+ /* Assume low memory requirements */
-+ portdata->num_out_urbs = N_OUT_URB;
-+ portdata->num_in_urbs = N_IN_URB;
-+
-+ /* Determine actual memory requirements */
-+ if (serial->num_ports == 1) {
-+ /* Get interface number for composite device */
-+ ifnum = sierra_calc_interface(serial);
-+ himemoryp =
-+ (struct sierra_iface_info *)&typeB_interface_list;
-+ if (is_himemory(ifnum, himemoryp)) {
-+ portdata->num_out_urbs = N_OUT_URB_HM;
-+ portdata->num_in_urbs = N_IN_URB_HM;
- }
- }
--
-- usb_set_serial_port_data(port, portdata);
--
-- /* initialize the in urbs */
-- for (j = 0; j < N_IN_URB; ++j) {
-- urb = usb_alloc_urb(0, GFP_KERNEL);
-- if (urb == NULL) {
-- dev_dbg(&port->dev, "%s: alloc for in "
-- "port failed.", __func__);
-- continue;
-+ else {
-+ himemoryp =
-+ (struct sierra_iface_info *)&typeA_interface_list;
-+ if (is_himemory(i, himemoryp)) {
-+ portdata->num_out_urbs = N_OUT_URB_HM;
-+ portdata->num_in_urbs = N_IN_URB_HM;
- }
-- /* Fill URB using supplied data. */
-- usb_fill_bulk_urb(urb, serial->dev,
-- usb_rcvbulkpipe(serial->dev,
-- port->bulk_in_endpointAddress),
-- portdata->in_buffer[j], IN_BUFLEN,
-- sierra_indat_callback, port);
-- portdata->in_urbs[j] = urb;
- }
-+ dev_dbg(&serial->dev->dev,
-+ "Memory usage (urbs) interface #%d, in=%d, out=%d\n",
-+ ifnum,portdata->num_in_urbs, portdata->num_out_urbs );
-+ /* Set the port private data pointer */
-+ usb_set_serial_port_data(port, portdata);
-+ }
-+ serial->interface->needs_remote_wakeup = 1;
-+ usb_autopm_disable(serial->interface);
-+
-+ result = sierra_get_fw_attr(serial->dev, &fw_attr);
-+ if (result == sizeof(fw_attr) && (fw_attr & SWI_FW_ATTR_PM_MASK) ) {
-+ dev_info(&serial->dev->dev,
-+ "APM supported, enabling autosuspend.\n");
-+ usb_autopm_enable(serial->interface);
-+
-+/*******************************************************************************
-+ * If you want the default /sys/bus/usb/devices/.../.../power/level to be forced
-+ * to auto, the following needs to be compiled in.
-+ * Other combinations may be used for other default values (see
-+ * drivers/usb/core/sysfs.c function set_level.
-+ */
-+#ifdef POWER_LEVEL_AUTO
-+ /* make power level default be 'auto' */
-+ serial->dev->autoresume_disabled = 0;
-+ serial->dev->autosuspend_disabled = 0;
-+#endif
- }
-
- return 0;
-@@ -691,30 +1362,55 @@ static int sierra_startup(struct usb_ser
-
- static void sierra_shutdown(struct usb_serial *serial)
- {
-- int i, j;
-+ int i;
- struct usb_serial_port *port;
-- struct sierra_port_private *portdata;
-+ struct sierra_intf_private *intfdata = serial->private;
-+
-+ dev_dbg(&serial->dev->dev, "%s\n", __func__);
-
-- dev_dbg(&serial->dev->dev, "%s", __func__);
-+ atomic_set(&intfdata->disconnected, 1);
-+
-+ if (serial->num_ports > 0) {
-+ port = serial->port[0];
-+ if (port)
-+ /* Note: The entire piece of memory that was allocated
-+ * in the startup routine can be released by passing
-+ * a pointer to the beginning of the piece.
-+ * This address corresponds to the address of the chunk
-+ * that was given to port 0.
-+ */
-+ kfree(usb_get_serial_port_data(port));
-+ }
-
- for (i = 0; i < serial->num_ports; ++i) {
- port = serial->port[i];
- if (!port)
- continue;
-- portdata = usb_get_serial_port_data(port);
-- if (!portdata)
-- continue;
--
-- for (j = 0; j < N_IN_URB; j++) {
-- usb_kill_urb(portdata->in_urbs[j]);
-- usb_free_urb(portdata->in_urbs[j]);
-- kfree(portdata->in_buffer[j]);
-- }
-- kfree(portdata);
- usb_set_serial_port_data(port, NULL);
- }
-+ intfdata_put(intfdata);
- }
-
-+static int sierra_reset_resume(struct usb_interface *intf)
-+{
-+ struct usb_serial *serial = usb_get_intfdata(intf);
-+ dev_err(&serial->dev->dev, "%s\n", __func__);
-+ return usb_serial_resume(intf);
-+}
-+
-+static struct usb_driver sierra_driver = {
-+ .name = "sierra",
-+ .probe = usb_serial_probe,
-+ .disconnect = usb_serial_disconnect,
-+ .suspend = usb_serial_suspend,
-+ .resume = usb_serial_resume,
-+ .reset_resume = sierra_reset_resume,
-+ .id_table = id_table,
-+
-+ .no_dynamic_id = 1,
-+ .supports_autosuspend = 1,
-+};
-+
- static struct usb_serial_driver sierra_device = {
- .driver = {
- .owner = THIS_MODULE,
-@@ -724,7 +1420,7 @@ static struct usb_serial_driver sierra_d
- .id_table = id_table,
- .usb_driver = &sierra_driver,
- .calc_num_ports = sierra_calc_num_ports,
-- .probe = sierra_probe,
-+ .probe = sierra_probe,
- .open = sierra_open,
- .close = sierra_close,
- .write = sierra_write,
-@@ -734,7 +1430,11 @@ static struct usb_serial_driver sierra_d
- .tiocmset = sierra_tiocmset,
- .attach = sierra_startup,
- .shutdown = sierra_shutdown,
-+ .port_probe = sierra_create_sysfs_attrs,
-+ .port_remove = sierra_remove_sysfs_attrs,
- .read_int_callback = sierra_instat_callback,
-+ .suspend = sierra_suspend,
-+ .resume = sierra_resume,
- };
-
- /* Functions used by new usb-serial code. */
-@@ -745,13 +1445,11 @@ static int __init sierra_init(void)
- if (retval)
- goto failed_device_register;
-
--
- retval = usb_register(&sierra_driver);
- if (retval)
- goto failed_driver_register;
-
-- printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
-- DRIVER_DESC "\n");
-+ info( "sierra version: %s", DRIVER_VERSION);
-
- return 0;
-