]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge remote-tracking branch 'usb/usb-next'
authorStephen Rothwell <sfr@canb.auug.org.au>
Thu, 20 Sep 2012 05:41:47 +0000 (15:41 +1000)
committerStephen Rothwell <sfr@canb.auug.org.au>
Thu, 20 Sep 2012 05:41:52 +0000 (15:41 +1000)
Conflicts:
drivers/usb/serial/digi_acceleport.c
drivers/usb/serial/io_edgeport.c
drivers/usb/serial/io_ti.c
drivers/usb/serial/kl5kusb105.c
drivers/usb/serial/mos7720.c
drivers/usb/serial/mos7840.c

42 files changed:
1  2 
Documentation/feature-removal-schedule.txt
arch/arm/mach-omap2/board-omap3evm.c
arch/arm/mach-omap2/twl-common.c
arch/arm/mach-tegra/devices.c
drivers/block/Kconfig
drivers/staging/serqt_usb2/serqt_usb2.c
drivers/usb/atm/ueagle-atm.c
drivers/usb/class/cdc-acm.c
drivers/usb/gadget/tcm_usb_gadget.c
drivers/usb/gadget/u_ether.c
drivers/usb/serial/ark3116.c
drivers/usb/serial/belkin_sa.c
drivers/usb/serial/console.c
drivers/usb/serial/cp210x.c
drivers/usb/serial/cypress_m8.c
drivers/usb/serial/digi_acceleport.c
drivers/usb/serial/empeg.c
drivers/usb/serial/f81232.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/io_edgeport.c
drivers/usb/serial/io_ti.c
drivers/usb/serial/ir-usb.c
drivers/usb/serial/iuu_phoenix.c
drivers/usb/serial/keyspan.c
drivers/usb/serial/keyspan_pda.c
drivers/usb/serial/kl5kusb105.c
drivers/usb/serial/kobil_sct.c
drivers/usb/serial/mct_u232.c
drivers/usb/serial/metro-usb.c
drivers/usb/serial/mos7720.c
drivers/usb/serial/mos7840.c
drivers/usb/serial/oti6858.c
drivers/usb/serial/pl2303.c
drivers/usb/serial/quatech2.c
drivers/usb/serial/sierra.c
drivers/usb/serial/spcp8x5.c
drivers/usb/serial/ssu100.c
drivers/usb/serial/ti_usb_3410_5052.c
drivers/usb/serial/usb-serial.c
drivers/usb/serial/usb_wwan.c
drivers/usb/serial/vizzini.c
drivers/usb/serial/whiteheat.c

Simple merge
index fb1f7770139a2056d280e506ab1fcb6d5ad4465e,329b726012f3d01fc3483254785c209f284c8cf8..697bee726d6df14c0c221cb50a9352ac89465c45
@@@ -251,17 -251,8 +251,12 @@@ void __init omap3_pmic_get_config(struc
  
  #if defined(CONFIG_ARCH_OMAP4)
  static struct twl4030_usb_data omap4_usb_pdata = {
-       .phy_init       = omap4430_phy_init,
-       .phy_exit       = omap4430_phy_exit,
-       .phy_power      = omap4430_phy_power,
-       .phy_set_clock  = omap4430_phy_set_clk,
-       .phy_suspend    = omap4430_phy_suspend,
  };
  
 +static struct regulator_consumer_supply omap4_vdda_hdmi_dac_supplies[] = {
 +      REGULATOR_SUPPLY("vdda_hdmi_dac", "omapdss_hdmi"),
 +};
 +
  static struct regulator_init_data omap4_vdac_idata = {
        .constraints = {
                .min_uV                 = 1800000,
Simple merge
Simple merge
index c90de969be8fc167d1677c95457db20b3d230c9a,376269b2bbfc76dd3b7e0b10d07fb79199fb21f8..51a706976b029c62a7fe07797dcf56beda76cdae
@@@ -423,10 -419,10 +419,10 @@@ static void qt_read_bulk_callback(struc
                          qt_read_bulk_callback, port);
        result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
        if (result)
-               dbg("%s - failed resubmitting read urb, error %d",
-                   __func__, result);
+               dev_dbg(&port->dev, "%s - failed resubmitting read urb, error %d",
+                       __func__, result);
        else {
 -              if (tty && RxCount) {
 +              if (RxCount) {
                        tty_flip_buffer_push(tty);
                        tty_schedule_flip(tty);
                }
@@@ -1296,10 -1276,10 +1276,10 @@@ static void qt_set_termios(struct tty_s
                /* disable SW flow control */
                status = BoxDisable_SW_FlowCtrl(port->serial, index);
                if (status < 0)
-                       dbg(__FILE__ "BoxSetSW_FlowCtrl (diabling) failed\n");
+                       dev_dbg(&port->dev, "BoxSetSW_FlowCtrl (diabling) failed\n");
  
        }
 -      tty->termios->c_cflag &= ~CMSPAR;
 +      termios->c_cflag &= ~CMSPAR;
        /* FIXME: Error cases should be returning the actual bits changed only */
  }
  
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index be34f153e56616462aa686611e284e492d1bc60b,3f13cdd159d48804100205290279194e8b73e209..1befce21e1734df489e940e49023a9b8a3c37d95
@@@ -1017,11 -1017,10 +1017,10 @@@ static void cypress_set_termios(struct 
  
        spin_lock_irqsave(&priv->lock, flags);
        if (priv->chiptype == CT_EARTHMATE && priv->baud_rate == 4800) {
-               dbg("Using custom termios settings for a baud rate of "
-                               "4800bps.");
+               dev_dbg(dev, "Using custom termios settings for a baud rate of 4800bps.\n");
                /* define custom termios settings for NMEA protocol */
  
 -              tty->termios->c_iflag /* input modes - */
 +              tty->termios.c_iflag /* input modes - */
                        &= ~(IGNBRK  /* disable ignore break */
                        | BRKINT     /* disable break causes interrupt */
                        | PARMRK     /* disable mark parity errors */
@@@ -1200,9 -1199,9 +1199,9 @@@ static void cypress_read_int_callback(s
  
        /* hangup, as defined in acm.c... this might be a bad place for it
         * though */
 -      if (tty && !(tty->termios->c_cflag & CLOCAL) &&
 +      if (tty && !(tty->termios.c_cflag & CLOCAL) &&
                        !(priv->current_status & UART_CD)) {
-               dbg("%s - calling hangup", __func__);
+               dev_dbg(dev, "%s - calling hangup\n", __func__);
                tty_hangup(tty);
                goto continue_read;
        }
index afd9d2ec577ba02f32afbe4e396252643e29ec0d,d3a8941f66bc56ec726942f602dd7b7ee8d480f7..c86f68c6b0785942e16315ebf34443a0f94b2161
@@@ -687,8 -685,9 +685,9 @@@ static void digi_set_termios(struct tty
                struct usb_serial_port *port, struct ktermios *old_termios)
  {
        struct digi_port *priv = usb_get_serial_port_data(port);
 -      unsigned int iflag = tty->termios->c_iflag;
 -      unsigned int cflag = tty->termios->c_cflag;
+       struct device *dev = &port->dev;
 +      unsigned int iflag = tty->termios.c_iflag;
 +      unsigned int cflag = tty->termios.c_cflag;
        unsigned int old_iflag = old_termios->c_iflag;
        unsigned int old_cflag = old_termios->c_cflag;
        unsigned char buf[32];
Simple merge
Simple merge
index 0c8d1c2262733e22b85474c91fb01a0d9e1d5b4d,8742a0ee2091963fff24421a214152bd39c3f46f..6f7ace8822b7444be7e652cd76f50794d144249e
@@@ -2101,8 -2095,9 +2095,9 @@@ static void ftdi_set_termios(struct tty
                struct usb_serial_port *port, struct ktermios *old_termios)
  {
        struct usb_device *dev = port->serial->dev;
+       struct device *ddev = &port->dev;
        struct ftdi_private *priv = usb_get_serial_port_data(port);
 -      struct ktermios *termios = tty->termios;
 +      struct ktermios *termios = &tty->termios;
        unsigned int cflag = termios->c_cflag;
        __u16 urb_value; /* will hold the new flags */
  
index f435575c4e6e256382d29e6eff05c5c0c00293d6,75b7ccdd2652c029caef4aae31626236bc948cdd..8e6faaf3580cb102abaea73be8d3636446dba7b6
@@@ -1516,13 -1497,9 +1497,9 @@@ static void edge_set_termios(struct tty
        struct edgeport_port *edge_port = usb_get_serial_port_data(port);
        unsigned int cflag;
  
 -      cflag = tty->termios->c_cflag;
 -      dev_dbg(&port->dev, "%s - clfag %08x iflag %08x\n", __func__, tty->termios->c_cflag, tty->termios->c_iflag);
 +      cflag = tty->termios.c_cflag;
-       dbg("%s - clfag %08x iflag %08x", __func__,
-           tty->termios.c_cflag, tty->termios.c_iflag);
-       dbg("%s - old clfag %08x old iflag %08x", __func__,
-           old_termios->c_cflag, old_termios->c_iflag);
-       dbg("%s - port %d", __func__, port->number);
++      dev_dbg(&port->dev, "%s - clfag %08x iflag %08x\n", __func__, tty->termios.c_cflag, tty->termios.c_iflag);
+       dev_dbg(&port->dev, "%s - old clfag %08x old iflag %08x\n", __func__, old_termios->c_cflag, old_termios->c_iflag);
  
        if (edge_port == NULL)
                return;
index 765978ae752ec6b7991154b6fe193029278f8bd9,21c7efa57acf188bdae0e0638639ac3f4bf36237..a2209cd4509396d3827d4a0627c59f42b5d713be
@@@ -2272,9 -2218,8 +2218,8 @@@ static void change_port_settings(struc
  
        config = kmalloc (sizeof (*config), GFP_KERNEL);
        if (!config) {
 -              *tty->termios = *old_termios;
 +              tty->termios = *old_termios;
-               dev_err(&edge_port->port->dev, "%s - out of memory\n",
-                                                               __func__);
+               dev_err(dev, "%s - out of memory\n", __func__);
                return;
        }
  
        /* if we are implementing OUTBOUND XON/XOFF */
        if (I_IXON(tty)) {
                config->wFlags |= UMP_MASK_UART_FLAGS_OUT_X;
-               dbg("%s - OUTBOUND XON/XOFF is enabled, XON = %2x, XOFF = %2x",
-                    __func__, config->cXon, config->cXoff);
+               dev_dbg(dev, "%s - OUTBOUND XON/XOFF is enabled, XON = %2x, XOFF = %2x\n",
+                       __func__, config->cXon, config->cXoff);
        } else
-               dbg("%s - OUTBOUND XON/XOFF is disabled", __func__);
+               dev_dbg(dev, "%s - OUTBOUND XON/XOFF is disabled\n", __func__);
  
 -      tty->termios->c_cflag &= ~CMSPAR;
 +      tty->termios.c_cflag &= ~CMSPAR;
  
        /* Round the baud rate */
        baud = tty_get_baud_rate(tty);
@@@ -2408,13 -2352,13 +2352,13 @@@ static void edge_set_termios(struct tty
        struct edgeport_port *edge_port = usb_get_serial_port_data(port);
        unsigned int cflag;
  
 -      cflag = tty->termios->c_cflag;
 +      cflag = tty->termios.c_cflag;
  
-       dbg("%s - clfag %08x iflag %08x", __func__,
-           tty->termios.c_cflag, tty->termios.c_iflag);
-       dbg("%s - old clfag %08x old iflag %08x", __func__,
-           old_termios->c_cflag, old_termios->c_iflag);
-       dbg("%s - port %d", __func__, port->number);
+       dev_dbg(&port->dev, "%s - clfag %08x iflag %08x\n", __func__,
 -              tty->termios->c_cflag, tty->termios->c_iflag);
++              tty->termios.c_cflag, tty->termios.c_iflag);
+       dev_dbg(&port->dev, "%s - old clfag %08x old iflag %08x\n", __func__,
+               old_termios->c_cflag, old_termios->c_iflag);
+       dev_dbg(&port->dev, "%s - port %d\n", __func__, port->number);
  
        if (edge_port == NULL)
                return;
Simple merge
index bf3864045c1842291d38dc42bd7f536c4413f214,91e6e372cf17d972d209dfed77b23807350f5761..01da3ea36e89d5363a8890339eac6165dec0e14c
@@@ -930,9 -914,9 +914,9 @@@ static void iuu_set_termios(struct tty_
        u32 newval = cflag & supported_mask;
  
        /* Just use the ospeed. ispeed should be the same. */
 -      baud = tty->termios->c_ospeed;
 +      baud = tty->termios.c_ospeed;
  
-       dbg("%s - enter c_ospeed or baud=%d", __func__, baud);
+       dev_dbg(&port->dev, "%s - enter c_ospeed or baud=%d\n", __func__, baud);
  
        /* compute the parity parameter */
        parity = 0;
Simple merge
Simple merge
index def9ad2587157ebc7c0cb856da5a23f96d314f9f,e4aa6c0632d73f12985ce362ef9c0cc0b7b982bd..3f6d7376c02d48e5a145449d79fe5ed4a3f01b3d
@@@ -445,9 -445,10 +445,10 @@@ static void klsi_105_set_termios(struc
                                 struct ktermios *old_termios)
  {
        struct klsi_105_private *priv = usb_get_serial_port_data(port);
 -      unsigned int iflag = tty->termios->c_iflag;
+       struct device *dev = &port->dev;
 +      unsigned int iflag = tty->termios.c_iflag;
        unsigned int old_iflag = old_termios->c_iflag;
 -      unsigned int cflag = tty->termios->c_cflag;
 +      unsigned int cflag = tty->termios.c_cflag;
        unsigned int old_cflag = old_termios->c_cflag;
        struct klsi_105_port_settings *cfg;
        unsigned long flags;
Simple merge
Simple merge
Simple merge
index 012f67b2e4cc2eb50145c3b7b2f9ff1f4fcf5e82,af7bc9b6280c8dac4dc7c8b9e299ae9a165c3378..1bf1ad0666667a9c31284c658814b651d91d2c66
@@@ -1751,19 -1706,15 +1706,15 @@@ static void mos7720_set_termios(struct 
                return;
        }
  
-       dbg("%s\n", "setting termios - ASPIRE");
+       dev_dbg(&port->dev, "setting termios - ASPIRE\n");
  
 -      cflag = tty->termios->c_cflag;
 +      cflag = tty->termios.c_cflag;
  
-       dbg("%s - cflag %08x iflag %08x", __func__,
-           tty->termios.c_cflag,
-           RELEVANT_IFLAG(tty->termios.c_iflag));
+       dev_dbg(&port->dev, "%s - cflag %08x iflag %08x\n", __func__,
 -              tty->termios->c_cflag, RELEVANT_IFLAG(tty->termios->c_iflag));
++              tty->termios.c_cflag, RELEVANT_IFLAG(tty->termios.c_iflag));
  
-       dbg("%s - old cflag %08x old iflag %08x", __func__,
-           old_termios->c_cflag,
-           RELEVANT_IFLAG(old_termios->c_iflag));
-       dbg("%s - port %d", __func__, port->number);
+       dev_dbg(&port->dev, "%s - old cflag %08x old iflag %08x\n", __func__,
+               old_termios->c_cflag, RELEVANT_IFLAG(old_termios->c_iflag));
  
        /* change the port settings to the new ones specified */
        change_port_settings(tty, mos7720_port, old_termios);
index 402c32d7accb8bfa089e5a179b981e462767eb0a,a94297d9c7ac056dde22bc389038565cf3cd327c..d6d4eeca8c68390ef4555e455cbfea66c68038b9
@@@ -2159,15 -2084,15 +2084,15 @@@ static void mos7840_set_termios(struct 
                return;
        }
  
-       dbg("%s", "setting termios - ");
+       dev_dbg(&port->dev, "%s", "setting termios - \n");
  
 -      cflag = tty->termios->c_cflag;
 +      cflag = tty->termios.c_cflag;
  
-       dbg("%s - clfag %08x iflag %08x", __func__,
-           tty->termios.c_cflag, RELEVANT_IFLAG(tty->termios.c_iflag));
-       dbg("%s - old clfag %08x old iflag %08x", __func__,
-           old_termios->c_cflag, RELEVANT_IFLAG(old_termios->c_iflag));
-       dbg("%s - port %d", __func__, port->number);
+       dev_dbg(&port->dev, "%s - clfag %08x iflag %08x\n", __func__,
 -              tty->termios->c_cflag, RELEVANT_IFLAG(tty->termios->c_iflag));
++              tty->termios.c_cflag, RELEVANT_IFLAG(tty->termios.c_iflag));
+       dev_dbg(&port->dev, "%s - old clfag %08x old iflag %08x\n", __func__,
+               old_termios->c_cflag, RELEVANT_IFLAG(old_termios->c_iflag));
+       dev_dbg(&port->dev, "%s - port %d\n", __func__, port->number);
  
        /* change the port settings to the new ones specified */
  
index 9f555560bfbf0355e6fb8e981168b30daedb4f2b,1498b3ddfead50e7dd392bbe93d7c7ae4a9a1476..933241f03fd8382f9e1dcd6f9fee38c8d1b89298
@@@ -420,12 -418,10 +418,10 @@@ static void oti6858_set_termios(struct 
        __le16 divisor;
        int br;
  
-       if (!tty) {
-               dbg("%s(): no tty structures", __func__);
+       if (!tty)
                return;
-       }
  
 -      cflag = tty->termios->c_cflag;
 +      cflag = tty->termios.c_cflag;
  
        spin_lock_irqsave(&priv->lock, flags);
        divisor = priv->pending_setup.divisor;
Simple merge
Simple merge
Simple merge
Simple merge
index cf2d30cf7588c09ca1e502471990d4c2a92cc456,6635743bd8c2ed2ce346cdd07c611c42580ed367..015810b3785bb72938d60691b81433a918583750
@@@ -319,10 -317,10 +317,10 @@@ static int ssu100_open(struct tty_struc
  /* set to 9600 */
        result = ssu100_control_msg(dev, QT_GET_SET_UART, 0x30, 0x0300);
        if (result < 0)
-               dbg("%s - set uart failed", __func__);
+               dev_dbg(&port->dev, "%s - set uart failed\n", __func__);
  
        if (tty)
 -              ssu100_set_termios(tty, port, tty->termios);
 +              ssu100_set_termios(tty, port, &tty->termios);
  
        return usb_serial_generic_open(tty, port);
  }
index f502a16aac215db11f5ce53a4492422495768340,648249e74125833cf0219df4adca0c0f1812ae90..6f49392cda5bdb889192a118c94a0573b48348a8
@@@ -520,9 -507,9 +507,9 @@@ static int ti_open(struct tty_struct *t
        }
  
        if (tty)
 -              ti_set_termios(tty, port, tty->termios);
 +              ti_set_termios(tty, port, &tty->termios);
  
-       dbg("%s - sending TI_OPEN_PORT", __func__);
+       dev_dbg(&port->dev, "%s - sending TI_OPEN_PORT\n", __func__);
        status = ti_command_out_sync(tdev, TI_OPEN_PORT,
                (__u8)(TI_UART1_PORT + port_number), open_settings, NULL, 0);
        if (status) {
        usb_clear_halt(dev, port->read_urb->pipe);
  
        if (tty)
 -              ti_set_termios(tty, port, tty->termios);
 +              ti_set_termios(tty, port, &tty->termios);
  
-       dbg("%s - sending TI_OPEN_PORT (2)", __func__);
+       dev_dbg(&port->dev, "%s - sending TI_OPEN_PORT (2)\n", __func__);
        status = ti_command_out_sync(tdev, TI_OPEN_PORT,
                (__u8)(TI_UART1_PORT + port_number), open_settings, NULL, 0);
        if (status) {
@@@ -831,12 -817,12 +817,12 @@@ static void ti_set_termios(struct tty_s
        int port_number = port->number - port->serial->minor;
        unsigned int mcr;
  
 -      cflag = tty->termios->c_cflag;
 -      iflag = tty->termios->c_iflag;
 +      cflag = tty->termios.c_cflag;
 +      iflag = tty->termios.c_iflag;
  
-       dbg("%s - cflag %08x, iflag %08x", __func__, cflag, iflag);
-       dbg("%s - old clfag %08x, old iflag %08x", __func__,
-                               old_termios->c_cflag, old_termios->c_iflag);
+       dev_dbg(&port->dev, "%s - cflag %08x, iflag %08x\n", __func__, cflag, iflag);
+       dev_dbg(&port->dev, "%s - old clfag %08x, old iflag %08x\n", __func__,
+               old_termios->c_cflag, old_termios->c_iflag);
  
        if (tport == NULL)
                return;
Simple merge
Simple merge
index 0000000000000000000000000000000000000000,2ac48fe3f4ca57c4ee4dc3946d1a1718a2056261..253eaf8d4b6718008e573bc1f417a4410edd26b9
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,1363 +1,1363 @@@
 -      cflag = tty->termios->c_cflag;
+ /*
+  * vizzini.c
+  *
+  * Copyright (c) 2011 Exar Corporation, Inc.
+  *
+  * ChangeLog:
+  *            v0.76- Support for 3.0.0 (Ubuntu 11.10) (Removed all Kernel source
+  *                   compiler conditions and now the base is Kernel 3.0. Ravi Reddy)
+  *            v0.75- Support for 2.6.38.8 (Ubuntu 11.04) - Added
+  *                   .usb_driver = &vizzini_driver.
+  *            v0.74- Support for 2.6.35.22 (Ubuntu 10.10) - Added
+  *                   #include <linux/slab.h> to fix kmalloc/kfree error.
+  *            v0.73- Fixed VZIOC_SET_REG (by Ravi Reddy).
+  *            v0.72- Support for 2.6.32.21 (by Ravi Reddy, for Ubuntu 10.04).
+  *            v0.71- Support for 2.6.31.
+  *            v0.5 - Tentative support for compiling with the CentOS 5.1
+  *                   kernel (2.6.18-53).
+  *            v0.4 - First version.  Lots of stuff lifted from
+  *                   cdc-acm.c (credits due to Armin Fuerst, Pavel Machek,
+  *                   Johannes Erdfelt, Vojtech Pavlik, David Kubicek) and
+  *                   and sierra.c (credit due to Kevin Lloyd).
+  */
+ /*
+  * 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 distributed in the hope that it will be useful,
+  * but WITHOUT ANY WARRANTY; without even the implied warranty of
+  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  * GNU General Public License for more details.
+  *
+  * You should have received a copy of the GNU General Public License
+  * along with this program; if not, write to the Free Software
+  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+  */
+ /* This version of the Linux driver source contains a number of
+    abominable conditional compilation sections to manage the API
+    changes between kernel versions 2.6.18, 2.6.25, and the latest
+    (currently 2.6.27).  At some point we'll hand a version of this
+    driver off to the mainline Linux source tree, and we'll strip all
+    these sections out.  For now it makes it much easier to keep it all
+    in sync while the driver is being developed. */
+ #define DRIVER_VERSION "v.0.76"
+ #define DRIVER_AUTHOR "Rob Duncan <rob.duncan@exar.com>"
+ #define DRIVER_DESC "USB Driver for Vizzini USB serial port"
+ #undef VIZZINI_IWA
+ #include <linux/kernel.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>
+ #include <linux/serial.h>
+ #include <linux/slab.h>
+ #include <linux/uaccess.h>
+ #include <asm/unaligned.h>
+ #include <linux/usb/cdc.h>
+ #ifndef CDC_DATA_INTERFACE_TYPE
+ #define CDC_DATA_INTERFACE_TYPE 0x0a
+ #endif
+ #ifndef USB_RT_ACM
+ #define USB_RT_ACM      (USB_TYPE_CLASS | USB_RECIP_INTERFACE)
+ #define ACM_CTRL_DTR            0x01
+ #define ACM_CTRL_RTS            0x02
+ #define ACM_CTRL_DCD            0x01
+ #define ACM_CTRL_DSR            0x02
+ #define ACM_CTRL_BRK            0x04
+ #define ACM_CTRL_RI             0x08
+ #define ACM_CTRL_FRAMING        0x10
+ #define ACM_CTRL_PARITY         0x20
+ #define ACM_CTRL_OVERRUN        0x40
+ #endif
+ #define XR_SET_REG              0
+ #define XR_GETN_REG             1
+ #define UART_0_REG_BLOCK        0
+ #define UART_1_REG_BLOCK        1
+ #define UART_2_REG_BLOCK        2
+ #define UART_3_REG_BLOCK        3
+ #define URM_REG_BLOCK           4
+ #define PRM_REG_BLOCK           5
+ #define EPMERR_REG_BLOCK        6
+ #define RAMCTL_REG_BLOCK        0x64
+ #define TWI_ROM_REG_BLOCK       0x65
+ #define EPLOCALS_REG_BLOCK      0x66
+ #define MEM_SHADOW_REG_SIZE_S   5
+ #define MEM_SHADOW_REG_SIZE     (1 << MEM_SHADOW_REG_SIZE_S)
+ #define MEM_EP_LOCALS_SIZE_S    3
+ #define MEM_EP_LOCALS_SIZE      (1 << MEM_EP_LOCALS_SIZE_S)
+ #define EP_WIDE_MODE            0x03
+ #define UART_GPIO_MODE                                     0x01a
+ #define UART_GPIO_MODE_SEL_M                               0x7
+ #define UART_GPIO_MODE_SEL_S                               0
+ #define UART_GPIO_MODE_SEL                                 0x007
+ #define UART_GPIO_MODE_SEL_GPIO                            (0x0 << UART_GPIO_MODE_SEL_S)
+ #define UART_GPIO_MODE_SEL_RTS_CTS                         (0x1 << UART_GPIO_MODE_SEL_S)
+ #define UART_GPIO_MODE_SEL_DTR_DSR                         (0x2 << UART_GPIO_MODE_SEL_S)
+ #define UART_GPIO_MODE_SEL_XCVR_EN_ACT                     (0x3 << UART_GPIO_MODE_SEL_S)
+ #define UART_GPIO_MODE_SEL_XCVR_EN_FLOW                    (0x4 << UART_GPIO_MODE_SEL_S)
+ #define UART_GPIO_MODE_XCVR_EN_POL_M                       0x1
+ #define UART_GPIO_MODE_XCVR_EN_POL_S                       3
+ #define UART_GPIO_MODE_XCVR_EN_POL                         0x008
+ #define UART_ENABLE                                        0x003
+ #define UART_ENABLE_TX_M                                   0x1
+ #define UART_ENABLE_TX_S                                   0
+ #define UART_ENABLE_TX                                     0x001
+ #define UART_ENABLE_RX_M                                   0x1
+ #define UART_ENABLE_RX_S                                   1
+ #define UART_ENABLE_RX                                     0x002
+ #define UART_CLOCK_DIVISOR_0                               0x004
+ #define UART_CLOCK_DIVISOR_1                               0x005
+ #define UART_CLOCK_DIVISOR_2                               0x006
+ #define UART_CLOCK_DIVISOR_2_MSB_M                         0x7
+ #define UART_CLOCK_DIVISOR_2_MSB_S                         0
+ #define UART_CLOCK_DIVISOR_2_MSB                           0x007
+ #define UART_CLOCK_DIVISOR_2_DIAGMODE_M                    0x1
+ #define UART_CLOCK_DIVISOR_2_DIAGMODE_S                    3
+ #define UART_CLOCK_DIVISOR_2_DIAGMODE                      0x008
+ #define UART_TX_CLOCK_MASK_0                               0x007
+ #define UART_TX_CLOCK_MASK_1                               0x008
+ #define UART_RX_CLOCK_MASK_0                               0x009
+ #define UART_RX_CLOCK_MASK_1                               0x00a
+ #define UART_FORMAT                                        0x00b
+ #define UART_FORMAT_SIZE_M                                 0xf
+ #define UART_FORMAT_SIZE_S                                 0
+ #define UART_FORMAT_SIZE                                   0x00f
+ #define UART_FORMAT_SIZE_7                                 (0x7 << UART_FORMAT_SIZE_S)
+ #define UART_FORMAT_SIZE_8                                 (0x8 << UART_FORMAT_SIZE_S)
+ #define UART_FORMAT_SIZE_9                                 (0x9 << UART_FORMAT_SIZE_S)
+ #define UART_FORMAT_PARITY_M                               0x7
+ #define UART_FORMAT_PARITY_S                               4
+ #define UART_FORMAT_PARITY                                 0x070
+ #define UART_FORMAT_PARITY_NONE                            (0x0 << UART_FORMAT_PARITY_S)
+ #define UART_FORMAT_PARITY_ODD                             (0x1 << UART_FORMAT_PARITY_S)
+ #define UART_FORMAT_PARITY_EVEN                            (0x2 << UART_FORMAT_PARITY_S)
+ #define UART_FORMAT_PARITY_1                               (0x3 << UART_FORMAT_PARITY_S)
+ #define UART_FORMAT_PARITY_0                               (0x4 << UART_FORMAT_PARITY_S)
+ #define UART_FORMAT_STOP_M                                 0x1
+ #define UART_FORMAT_STOP_S                                 7
+ #define UART_FORMAT_STOP                                   0x080
+ #define UART_FORMAT_STOP_1                                 (0x0 << UART_FORMAT_STOP_S)
+ #define UART_FORMAT_STOP_2                                 (0x1 << UART_FORMAT_STOP_S)
+ #define UART_FORMAT_MODE_7N1                               0
+ #define UART_FORMAT_MODE_RES1                              1
+ #define UART_FORMAT_MODE_RES2                              2
+ #define UART_FORMAT_MODE_RES3                              3
+ #define UART_FORMAT_MODE_7N2                               4
+ #define UART_FORMAT_MODE_7P1                               5
+ #define UART_FORMAT_MODE_8N1                               6
+ #define UART_FORMAT_MODE_RES7                              7
+ #define UART_FORMAT_MODE_7P2                               8
+ #define UART_FORMAT_MODE_8N2                               9
+ #define UART_FORMAT_MODE_8P1                               10
+ #define UART_FORMAT_MODE_9N1                               11
+ #define UART_FORMAT_MODE_8P2                               12
+ #define UART_FORMAT_MODE_RESD                              13
+ #define UART_FORMAT_MODE_RESE                              14
+ #define UART_FORMAT_MODE_9N2                               15
+ #define UART_FLOW                                          0x00c
+ #define UART_FLOW_MODE_M                                   0x7
+ #define UART_FLOW_MODE_S                                   0
+ #define UART_FLOW_MODE                                     0x007
+ #define UART_FLOW_MODE_NONE                                (0x0 << UART_FLOW_MODE_S)
+ #define UART_FLOW_MODE_HW                                  (0x1 << UART_FLOW_MODE_S)
+ #define UART_FLOW_MODE_SW                                  (0x2 << UART_FLOW_MODE_S)
+ #define UART_FLOW_MODE_ADDR_MATCH                          (0x3 << UART_FLOW_MODE_S)
+ #define UART_FLOW_MODE_ADDR_MATCH_TX                       (0x4 << UART_FLOW_MODE_S)
+ #define UART_FLOW_HALF_DUPLEX_M                            0x1
+ #define UART_FLOW_HALF_DUPLEX_S                            3
+ #define UART_FLOW_HALF_DUPLEX                              0x008
+ #define UART_LOOPBACK_CTL                                  0x012
+ #define UART_LOOPBACK_CTL_ENABLE_M                         0x1
+ #define UART_LOOPBACK_CTL_ENABLE_S                         2
+ #define UART_LOOPBACK_CTL_ENABLE                           0x004
+ #define UART_LOOPBACK_CTL_RX_SOURCE_M                      0x3
+ #define UART_LOOPBACK_CTL_RX_SOURCE_S                      0
+ #define UART_LOOPBACK_CTL_RX_SOURCE                        0x003
+ #define UART_LOOPBACK_CTL_RX_UART0                         (0x0 << UART_LOOPBACK_CTL_RX_SOURCE_S)
+ #define UART_LOOPBACK_CTL_RX_UART1                         (0x1 << UART_LOOPBACK_CTL_RX_SOURCE_S)
+ #define UART_LOOPBACK_CTL_RX_UART2                         (0x2 << UART_LOOPBACK_CTL_RX_SOURCE_S)
+ #define UART_LOOPBACK_CTL_RX_UART3                         (0x3 << UART_LOOPBACK_CTL_RX_SOURCE_S)
+ #define UART_CHANNEL_NUM                                   0x00d
+ #define UART_XON_CHAR                                      0x010
+ #define UART_XOFF_CHAR                                     0x011
+ #define UART_GPIO_SET                                      0x01d
+ #define UART_GPIO_CLR                                      0x01e
+ #define UART_GPIO_STATUS                                   0x01f
+ #define URM_ENABLE_BASE                                    0x010
+ #define URM_ENABLE_0                                       0x010
+ #define URM_ENABLE_0_TX_M                                  0x1
+ #define URM_ENABLE_0_TX_S                                  0
+ #define URM_ENABLE_0_TX                                    0x001
+ #define URM_ENABLE_0_RX_M                                  0x1
+ #define URM_ENABLE_0_RX_S                                  1
+ #define URM_ENABLE_0_RX                                    0x002
+ #define URM_RX_FIFO_RESET_0                                0x018
+ #define URM_RX_FIFO_RESET_1                                0x019
+ #define URM_RX_FIFO_RESET_2                                0x01a
+ #define URM_RX_FIFO_RESET_3                                0x01b
+ #define URM_TX_FIFO_RESET_0                                0x01c
+ #define URM_TX_FIFO_RESET_1                                0x01d
+ #define URM_TX_FIFO_RESET_2                                0x01e
+ #define URM_TX_FIFO_RESET_3                                0x01f
+ #define RAMCTL_REGS_TXFIFO_0_LEVEL                         0x000
+ #define RAMCTL_REGS_TXFIFO_1_LEVEL                         0x001
+ #define RAMCTL_REGS_TXFIFO_2_LEVEL                         0x002
+ #define RAMCTL_REGS_TXFIFO_3_LEVEL                         0x003
+ #define RAMCTL_REGS_RXFIFO_0_LEVEL                         0x004
+ #define RAMCTL_REGS_RXFIFO_0_LEVEL_LEVEL_M                 0x7ff
+ #define RAMCTL_REGS_RXFIFO_0_LEVEL_LEVEL_S                 0
+ #define RAMCTL_REGS_RXFIFO_0_LEVEL_LEVEL                   0x7ff
+ #define RAMCTL_REGS_RXFIFO_0_LEVEL_STALE_M                 0x1
+ #define RAMCTL_REGS_RXFIFO_0_LEVEL_STALE_S                 11
+ #define RAMCTL_REGS_RXFIFO_0_LEVEL_STALE                   0x800
+ #define RAMCTL_REGS_RXFIFO_1_LEVEL                         0x005
+ #define RAMCTL_REGS_RXFIFO_2_LEVEL                         0x006
+ #define RAMCTL_REGS_RXFIFO_3_LEVEL                         0x007
+ #define RAMCTL_BUFFER_PARITY                               0x1
+ #define RAMCTL_BUFFER_BREAK                                0x2
+ #define RAMCTL_BUFFER_FRAME                                0x4
+ #define RAMCTL_BUFFER_OVERRUN                              0x8
+ #define N_IN_URB      4
+ #define N_OUT_URB     4
+ #define IN_BUFLEN     4096
+ static struct usb_device_id id_table[] = {
+       { USB_DEVICE(0x04e2, 0x1410) },
+       { USB_DEVICE(0x04e2, 0x1412) },
+       { USB_DEVICE(0x04e2, 0x1414) },
+       { }
+ };
+ MODULE_DEVICE_TABLE(usb, id_table);
+ struct vizzini_serial_private {
+       struct usb_interface *data_interface;
+ };
+ struct vizzini_port_private {
+       spinlock_t lock;
+       int outstanding_urbs;
+       struct urb *in_urbs[N_IN_URB];
+       char *in_buffer[N_IN_URB];
+       int ctrlin;
+       int ctrlout;
+       int clocal;
+       int block;
+       int preciseflags;       /* USB: wide mode, TTY: flags per character */
+       int trans9;             /* USB: wide mode, serial 9N1 */
+       unsigned int baud_base; /* setserial: used to hack in non-standard baud rates */
+       int have_extra_byte;
+       int extra_byte;
+       int bcd_device;
+ #ifdef VIZZINI_IWA
+       int iwa;
+ #endif
+ };
+ static int vizzini_rev_a(struct usb_serial_port *port)
+ {
+       struct vizzini_port_private *portdata = usb_get_serial_port_data(port);
+       return portdata->bcd_device == 0;
+ }
+ static int acm_ctrl_msg(struct usb_serial_port *port, int request,
+                       int value, void *buf, int len)
+ {
+       struct usb_serial *serial = port->serial;
+       int retval = usb_control_msg(serial->dev,
+                                    usb_sndctrlpipe(serial->dev, 0),
+                                    request,
+                                    USB_RT_ACM,
+                                    value,
+                                    serial->interface->cur_altsetting->desc.bInterfaceNumber,
+                                    buf,
+                                    len,
+                                    5000);
+       dev_dbg(&port->dev, "acm_control_msg: rq: 0x%02x val: %#x len: %#x result: %d\n", request, value, len, retval);
+       return retval < 0 ? retval : 0;
+ }
+ #define acm_set_control(port, control)                                        \
+       acm_ctrl_msg(port, USB_CDC_REQ_SET_CONTROL_LINE_STATE, control, NULL, 0)
+ #define acm_set_line(port, line)                                      \
+       acm_ctrl_msg(port, USB_CDC_REQ_SET_LINE_CODING, 0, line, sizeof *(line))
+ #define acm_send_break(port, ms)                                      \
+       acm_ctrl_msg(port, USB_CDC_REQ_SEND_BREAK, ms, NULL, 0)
+ static int vizzini_set_reg(struct usb_serial_port *port, int block, int regnum, int value)
+ {
+       struct usb_serial *serial = port->serial;
+       int result;
+       result = usb_control_msg(serial->dev,                     /* usb device */
+                                usb_sndctrlpipe(serial->dev, 0), /* endpoint pipe */
+                                XR_SET_REG,                      /* request */
+                                USB_DIR_OUT | USB_TYPE_VENDOR,   /* request_type */
+                                value,                           /* request value */
+                                regnum | (block << 8),           /* index */
+                                NULL,                            /* data */
+                                0,                               /* size */
+                                5000);                           /* timeout */
+       return result;
+ }
+ static void vizzini_disable(struct usb_serial_port *port)
+ {
+       struct vizzini_port_private *portdata = usb_get_serial_port_data(port);
+       int block = portdata->block;
+       vizzini_set_reg(port, block, UART_ENABLE, 0);
+       vizzini_set_reg(port, URM_REG_BLOCK, URM_ENABLE_BASE + block, 0);
+ }
+ static void vizzini_enable(struct usb_serial_port *port)
+ {
+       struct vizzini_port_private *portdata = usb_get_serial_port_data(port);
+       int block = portdata->block;
+       vizzini_set_reg(port, URM_REG_BLOCK, URM_ENABLE_BASE + block, URM_ENABLE_0_TX);
+       vizzini_set_reg(port, block, UART_ENABLE, UART_ENABLE_TX | UART_ENABLE_RX);
+       vizzini_set_reg(port, URM_REG_BLOCK, URM_ENABLE_BASE + block, URM_ENABLE_0_TX | URM_ENABLE_0_RX);
+ }
+ struct vizzini_baud_rate {
+       unsigned int tx;
+       unsigned int rx0;
+       unsigned int rx1;
+ };
+ static struct vizzini_baud_rate vizzini_baud_rates[] = {
+       { 0x000, 0x000, 0x000 },
+       { 0x000, 0x000, 0x000 },
+       { 0x100, 0x000, 0x100 },
+       { 0x020, 0x400, 0x020 },
+       { 0x010, 0x100, 0x010 },
+       { 0x208, 0x040, 0x208 },
+       { 0x104, 0x820, 0x108 },
+       { 0x844, 0x210, 0x884 },
+       { 0x444, 0x110, 0x444 },
+       { 0x122, 0x888, 0x224 },
+       { 0x912, 0x448, 0x924 },
+       { 0x492, 0x248, 0x492 },
+       { 0x252, 0x928, 0x292 },
+       { 0X94A, 0X4A4, 0XA52 },
+       { 0X52A, 0XAA4, 0X54A },
+       { 0XAAA, 0x954, 0X4AA },
+       { 0XAAA, 0x554, 0XAAA },
+       { 0x555, 0XAD4, 0X5AA },
+       { 0XB55, 0XAB4, 0X55A },
+       { 0X6B5, 0X5AC, 0XB56 },
+       { 0X5B5, 0XD6C, 0X6D6 },
+       { 0XB6D, 0XB6A, 0XDB6 },
+       { 0X76D, 0X6DA, 0XBB6 },
+       { 0XEDD, 0XDDA, 0X76E },
+       { 0XDDD, 0XBBA, 0XEEE },
+       { 0X7BB, 0XF7A, 0XDDE },
+       { 0XF7B, 0XEF6, 0X7DE },
+       { 0XDF7, 0XBF6, 0XF7E },
+       { 0X7F7, 0XFEE, 0XEFE },
+       { 0XFDF, 0XFBE, 0X7FE },
+       { 0XF7F, 0XEFE, 0XFFE },
+       { 0XFFF, 0XFFE, 0XFFD },
+ };
+ static int vizzini_set_baud_rate(struct usb_serial_port *port, unsigned int rate)
+ {
+       struct vizzini_port_private *portdata = usb_get_serial_port_data(port);
+       int block = portdata->block;
+       unsigned int divisor = 48000000 / rate;
+       unsigned int i = ((32 * 48000000) / rate) & 0x1f;
+       unsigned int tx_mask = vizzini_baud_rates[i].tx;
+       unsigned int rx_mask = (divisor & 1) ? vizzini_baud_rates[i].rx1 : vizzini_baud_rates[i].rx0;
+       dev_dbg(&port->dev, "Setting baud rate to %d: i=%u div=%u tx=%03x rx=%03x\n", rate, i, divisor, tx_mask, rx_mask);
+       vizzini_set_reg(port, block, UART_CLOCK_DIVISOR_0, (divisor >>  0) & 0xff);
+       vizzini_set_reg(port, block, UART_CLOCK_DIVISOR_1, (divisor >>  8) & 0xff);
+       vizzini_set_reg(port, block, UART_CLOCK_DIVISOR_2, (divisor >> 16) & 0xff);
+       vizzini_set_reg(port, block, UART_TX_CLOCK_MASK_0, (tx_mask >>  0) & 0xff);
+       vizzini_set_reg(port, block, UART_TX_CLOCK_MASK_1, (tx_mask >>  8) & 0xff);
+       vizzini_set_reg(port, block, UART_RX_CLOCK_MASK_0, (rx_mask >>  0) & 0xff);
+       vizzini_set_reg(port, block, UART_RX_CLOCK_MASK_1, (rx_mask >>  8) & 0xff);
+       return -EINVAL;
+ }
+ static void vizzini_set_termios(struct tty_struct *tty_param,
+                               struct usb_serial_port *port,
+                               struct ktermios *old_termios)
+ {
+       struct vizzini_port_private *portdata = usb_get_serial_port_data(port);
+       unsigned int             cflag, block;
+       speed_t                  rate;
+       unsigned int             format_size, format_parity, format_stop, flow, gpio_mode;
+       struct tty_struct       *tty = port->port.tty;
++      cflag = tty->termios.c_cflag;
+       portdata->clocal = ((cflag & CLOCAL) != 0);
+       block = portdata->block;
+       vizzini_disable(port);
+       if ((cflag & CSIZE) == CS7) {
+               format_size = UART_FORMAT_SIZE_7;
+       } else if ((cflag & CSIZE) == CS5) {
+               /* Enabling 5-bit mode is really 9-bit mode! */
+               format_size = UART_FORMAT_SIZE_9;
+       } else {
+               format_size = UART_FORMAT_SIZE_8;
+       }
+       portdata->trans9 = (format_size == UART_FORMAT_SIZE_9);
+       if (cflag & PARENB) {
+               if (cflag & PARODD) {
+                       if (cflag & CMSPAR)
+                               format_parity = UART_FORMAT_PARITY_1;
+                       else
+                               format_parity = UART_FORMAT_PARITY_ODD;
+               } else {
+                       if (cflag & CMSPAR)
+                               format_parity = UART_FORMAT_PARITY_0;
+                       else
+                               format_parity = UART_FORMAT_PARITY_EVEN;
+               }
+       } else {
+               format_parity = UART_FORMAT_PARITY_NONE;
+       }
+       if (cflag & CSTOPB)
+               format_stop = UART_FORMAT_STOP_2;
+       else
+               format_stop = UART_FORMAT_STOP_1;
+ #ifdef VIZZINI_IWA
+       if (format_size == UART_FORMAT_SIZE_8) {
+               portdata->iwa = format_parity;
+               if (portdata->iwa != UART_FORMAT_PARITY_NONE) {
+                       format_size = UART_FORMAT_SIZE_9;
+                       format_parity = UART_FORMAT_PARITY_NONE;
+               }
+       } else {
+               portdata->iwa = UART_FORMAT_PARITY_NONE;
+       }
+ #endif
+       vizzini_set_reg(port, block, UART_FORMAT, format_size | format_parity | format_stop);
+       if (cflag & CRTSCTS) {
+               flow      = UART_FLOW_MODE_HW;
+               gpio_mode = UART_GPIO_MODE_SEL_RTS_CTS;
+       } else if (I_IXOFF(tty) || I_IXON(tty)) {
+               unsigned char   start_char = START_CHAR(tty);
+               unsigned char   stop_char  = STOP_CHAR(tty);
+               flow      = UART_FLOW_MODE_SW;
+               gpio_mode = UART_GPIO_MODE_SEL_GPIO;
+               vizzini_set_reg(port, block, UART_XON_CHAR, start_char);
+               vizzini_set_reg(port, block, UART_XOFF_CHAR, stop_char);
+       } else {
+               flow      = UART_FLOW_MODE_NONE;
+               gpio_mode = UART_GPIO_MODE_SEL_GPIO;
+       }
+       vizzini_set_reg(port, block, UART_FLOW, flow);
+       vizzini_set_reg(port, block, UART_GPIO_MODE, gpio_mode);
+       if (portdata->trans9) {
+               /* Turn on wide mode if we're 9-bit transparent. */
+               vizzini_set_reg(port, EPLOCALS_REG_BLOCK, (block * MEM_EP_LOCALS_SIZE) + EP_WIDE_MODE, 1);
+ #ifdef VIZZINI_IWA
+       } else if (portdata->iwa != UART_FORMAT_PARITY_NONE) {
+               vizzini_set_reg(port, EPLOCALS_REG_BLOCK, (block * MEM_EP_LOCALS_SIZE) + EP_WIDE_MODE, 1);
+ #endif
+       } else if (!portdata->preciseflags) {
+               /* Turn off wide mode unless we have precise flags. */
+               vizzini_set_reg(port, EPLOCALS_REG_BLOCK, (block * MEM_EP_LOCALS_SIZE) + EP_WIDE_MODE, 0);
+       }
+       rate = tty_get_baud_rate(tty);
+       if (rate)
+               vizzini_set_baud_rate(port, rate);
+       vizzini_enable(port);
+ }
+ static void vizzini_break_ctl(struct tty_struct *tty, int break_state)
+ {
+       struct usb_serial_port *port = tty->driver_data;
+       dev_dbg(&port->dev, "BREAK %d\n", break_state);
+       if (break_state)
+               acm_send_break(port, 0x10);
+       else
+               acm_send_break(port, 0x000);
+ }
+ static int vizzini_tiocmget(struct tty_struct *tty)
+ {
+       struct usb_serial_port *port = tty->driver_data;
+       struct vizzini_port_private *portdata = usb_get_serial_port_data(port);
+       return (portdata->ctrlout & ACM_CTRL_DTR ? TIOCM_DTR : 0) |
+               (portdata->ctrlout & ACM_CTRL_RTS ? TIOCM_RTS : 0) |
+               (portdata->ctrlin  & ACM_CTRL_DSR ? TIOCM_DSR : 0) |
+               (portdata->ctrlin  & ACM_CTRL_RI  ? TIOCM_RI  : 0) |
+               (portdata->ctrlin  & ACM_CTRL_DCD ? TIOCM_CD  : 0) |
+               TIOCM_CTS;
+ }
+ static int vizzini_tiocmset(struct tty_struct *tty,
+                           unsigned int set, unsigned int clear)
+ {
+       struct usb_serial_port *port = tty->driver_data;
+       struct vizzini_port_private *portdata = usb_get_serial_port_data(port);
+       unsigned int newctrl;
+       newctrl = portdata->ctrlout;
+       set = (set & TIOCM_DTR ? ACM_CTRL_DTR : 0) | (set & TIOCM_RTS ? ACM_CTRL_RTS : 0);
+       clear = (clear & TIOCM_DTR ? ACM_CTRL_DTR : 0) | (clear & TIOCM_RTS ? ACM_CTRL_RTS : 0);
+       newctrl = (newctrl & ~clear) | set;
+       if (portdata->ctrlout == newctrl)
+               return 0;
+       return acm_set_control(port, portdata->ctrlout = newctrl);
+ }
+ static int vizzini_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
+ {
+       struct usb_serial_port *port = tty->driver_data;
+       struct vizzini_port_private *portdata = usb_get_serial_port_data(port);
+       struct serial_struct ss;
+       dev_dbg(&port->dev, "%s %08x\n", __func__, cmd);
+       switch (cmd) {
+       case TIOCGSERIAL:
+               if (!arg)
+                       return -EFAULT;
+               memset(&ss, 0, sizeof(ss));
+               ss.baud_base = portdata->baud_base;
+               if (copy_to_user((void __user *)arg, &ss, sizeof(ss)))
+                       return -EFAULT;
+               break;
+       case TIOCSSERIAL:
+               if (!arg)
+                       return -EFAULT;
+               if (copy_from_user(&ss, (void __user *)arg, sizeof(ss)))
+                       return -EFAULT;
+               portdata->baud_base = ss.baud_base;
+               dev_dbg(&port->dev, "baud_base=%d\n", portdata->baud_base);
+               vizzini_disable(port);
+               if (portdata->baud_base)
+                       vizzini_set_baud_rate(port, portdata->baud_base);
+               vizzini_enable(port);
+               break;
+       default:
+               return -ENOIOCTLCMD;
+       }
+       return 0;
+ }
+ #ifdef VIZZINI_IWA
+ static const int vizzini_parity[] = {
+       0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+       1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+       1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+       0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+       1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+       0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+       0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+       1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+       1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+       0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+       0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+       1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+       0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+       1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+       1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+       0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0
+ };
+ #endif
+ static void vizzini_out_callback(struct urb *urb)
+ {
+       struct usb_serial_port *port = urb->context;
+       struct vizzini_port_private *portdata = usb_get_serial_port_data(port);
+       int status = urb->status;
+       unsigned long flags;
+       dev_dbg(&port->dev, "%s - port %d\n", __func__, port->number);
+       /* free up the transfer buffer, as usb_free_urb() does not do this */
+       kfree(urb->transfer_buffer);
+       if (status)
+               dev_dbg(&port->dev, "%s - nonzero write bulk status received: %d\n", __func__, status);
+       spin_lock_irqsave(&portdata->lock, flags);
+       --portdata->outstanding_urbs;
+       spin_unlock_irqrestore(&portdata->lock, flags);
+       usb_serial_port_softint(port);
+ }
+ static int vizzini_write_room(struct tty_struct *tty)
+ {
+       struct usb_serial_port *port = tty->driver_data;
+       struct vizzini_port_private *portdata = usb_get_serial_port_data(port);
+       unsigned long flags;
+       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 */
+       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;
+       }
+       spin_unlock_irqrestore(&portdata->lock, flags);
+       return 2048;
+ }
+ static int vizzini_write(struct tty_struct *tty, struct usb_serial_port *port,
+                        const unsigned char *buf, int count)
+ {
+       struct vizzini_port_private *portdata = usb_get_serial_port_data(port);
+       struct usb_serial *serial = port->serial;
+       int bufsize = count;
+       unsigned long flags;
+       unsigned char *buffer;
+       struct urb *urb;
+       int status;
+       portdata = usb_get_serial_port_data(port);
+       dev_dbg(&port->dev, "%s: write (%d chars)\n", __func__, count);
+       spin_lock_irqsave(&portdata->lock, flags);
+       if (portdata->outstanding_urbs > N_OUT_URB) {
+               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);
+ #ifdef VIZZINI_IWA
+       if (portdata->iwa != UART_FORMAT_PARITY_NONE)
+               bufsize = count * 2;
+ #endif
+       buffer = kmalloc(bufsize, GFP_ATOMIC);
+       if (!buffer) {
+               dev_err(&port->dev, "out of memory\n");
+               count = -ENOMEM;
+               goto error_no_buffer;
+       }
+       urb = usb_alloc_urb(0, GFP_ATOMIC);
+       if (!urb) {
+               dev_err(&port->dev, "no more free urbs\n");
+               count = -ENOMEM;
+               goto error_no_urb;
+       }
+ #ifdef VIZZINI_IWA
+       if (portdata->iwa != UART_FORMAT_PARITY_NONE) {
+               int i;
+               char *b = buffer;
+               for (i = 0; i < count; ++i) {
+                       int c, p = 0;
+                       c = buf[i];
+                       switch (portdata->iwa) {
+                       case UART_FORMAT_PARITY_ODD:
+                               p = !vizzini_parity[c];
+                               break;
+                       case UART_FORMAT_PARITY_EVEN:
+                               p = vizzini_parity[c];
+                               break;
+                       case UART_FORMAT_PARITY_1:
+                               p = 1;
+                               break;
+                       case UART_FORMAT_PARITY_0:
+                               p = 0;
+                               break;
+                       }
+                       *b++ = c;
+                       *b++ = p;
+               }
+       } else
+ #endif
+               memcpy(buffer, buf, count);
+       usb_fill_bulk_urb(urb, serial->dev,
+                         usb_sndbulkpipe(serial->dev,
+                                         port->bulk_out_endpointAddress),
+                         buffer, bufsize, vizzini_out_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;
+       }
+       /* we are done with this urb, so let the host driver
+        * really free it when it is finished with it */
+       usb_free_urb(urb);
+       return count;
+ error:
+       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;
+ }
+ static void vizzini_in_callback(struct urb *urb)
+ {
+       int endpoint = usb_pipeendpoint(urb->pipe);
+       struct usb_serial_port *port = urb->context;
+       struct vizzini_port_private *portdata = usb_get_serial_port_data(port);
+       struct tty_struct *tty = port->port.tty;
+       int preciseflags = portdata->preciseflags;
+       char *transfer_buffer = urb->transfer_buffer;
+       int length, room, have_extra_byte;
+       int err;
+       if (urb->status) {
+               dev_dbg(&port->dev, "%s: nonzero status: %d on endpoint %02x.\n", __func__, urb->status, endpoint);
+               return;
+       }
+ #ifdef VIZZINI_IWA
+       if (portdata->iwa != UART_FORMAT_PARITY_NONE)
+               preciseflags = true;
+ #endif
+       length = urb->actual_length;
+       if (length == 0) {
+               dev_dbg(&port->dev, "%s: empty read urb received\n", __func__);
+               err = usb_submit_urb(urb, GFP_ATOMIC);
+               if (err)
+                       dev_err(&port->dev, "resubmit read urb failed. (%d)\n", err);
+               return;
+       }
+       length = length + (portdata->have_extra_byte ? 1 : 0);
+       have_extra_byte = (preciseflags && (length & 1));
+       length = (preciseflags) ? (length / 2) : length;
+       room = tty_buffer_request_room(tty, length);
+       if (room != length)
+               dev_dbg(&port->dev, "Not enough room in TTY buf, dropped %d chars.\n", length - room);
+       if (room) {
+               if (preciseflags) {
+                       char *dp = transfer_buffer;
+                       int i, ch, ch_flags;
+                       for (i = 0; i < room; ++i) {
+                               char tty_flag;
+                               if (i == 0) {
+                                       if (portdata->have_extra_byte)
+                                               ch = portdata->extra_byte;
+                                       else
+                                               ch = *dp++;
+                               } else {
+                                       ch = *dp++;
+                               }
+                               ch_flags = *dp++;
+ #ifdef VIZZINI_IWA
+                               {
+                                       int p;
+                                       switch (portdata->iwa) {
+                                       case UART_FORMAT_PARITY_ODD:
+                                               p = !vizzini_parity[ch];
+                                               break;
+                                       case UART_FORMAT_PARITY_EVEN:
+                                               p = vizzini_parity[ch];
+                                               break;
+                                       case UART_FORMAT_PARITY_1:
+                                               p = 1;
+                                               break;
+                                       case UART_FORMAT_PARITY_0:
+                                               p = 0;
+                                               break;
+                                       default:
+                                               p = 0;
+                                               break;
+                                       }
+                                       ch_flags ^= p;
+                               }
+ #endif
+                               if (ch_flags & RAMCTL_BUFFER_PARITY)
+                                       tty_flag = TTY_PARITY;
+                               else if (ch_flags & RAMCTL_BUFFER_BREAK)
+                                       tty_flag = TTY_BREAK;
+                               else if (ch_flags & RAMCTL_BUFFER_FRAME)
+                                       tty_flag = TTY_FRAME;
+                               else if (ch_flags & RAMCTL_BUFFER_OVERRUN)
+                                       tty_flag = TTY_OVERRUN;
+                               else
+                                       tty_flag = TTY_NORMAL;
+                               tty_insert_flip_char(tty, ch, tty_flag);
+                       }
+               } else {
+                       tty_insert_flip_string(tty, transfer_buffer, room);
+               }
+               tty_flip_buffer_push(tty);
+       }
+       portdata->have_extra_byte = have_extra_byte;
+       if (have_extra_byte)
+               portdata->extra_byte = transfer_buffer[urb->actual_length - 1];
+       err = usb_submit_urb(urb, GFP_ATOMIC);
+       if (err)
+               dev_err(&port->dev, "resubmit read urb failed. (%d)\n", err);
+ }
+ static void vizzini_int_callback(struct urb *urb)
+ {
+       struct usb_serial_port *port = urb->context;
+       struct vizzini_port_private *portdata = usb_get_serial_port_data(port);
+       struct tty_struct *tty = port->port.tty;
+       struct usb_cdc_notification *dr = urb->transfer_buffer;
+       unsigned char *data;
+       int newctrl;
+       int status;
+       switch (urb->status) {
+       case 0:
+               /* success */
+               break;
+       case -ECONNRESET:
+       case -ENOENT:
+       case -ESHUTDOWN:
+               /* this urb is terminated, clean up */
+               dev_dbg(&port->dev, "urb shutting down with status: %d\n", urb->status);
+               return;
+       default:
+               dev_dbg(&port->dev, "nonzero urb status received: %d\n", urb->status);
+               goto exit;
+       }
+       data = (unsigned char *)(dr + 1);
+       switch (dr->bNotificationType) {
+       case USB_CDC_NOTIFY_NETWORK_CONNECTION:
+               dev_dbg(&port->dev, "%s network\n", dr->wValue ? "connected to" : "disconnected from");
+               break;
+       case USB_CDC_NOTIFY_SERIAL_STATE:
+               newctrl = le16_to_cpu(get_unaligned((__le16 *)data));
+               if (!portdata->clocal && (portdata->ctrlin & ~newctrl & ACM_CTRL_DCD)) {
+                       dev_dbg(&port->dev, "calling hangup\n");
+                       tty_hangup(tty);
+               }
+               portdata->ctrlin = newctrl;
+               dev_dbg(&port->dev, "input control lines: dcd%c dsr%c break%c ring%c framing%c parity%c overrun%c\n",
+                                  portdata->ctrlin & ACM_CTRL_DCD ? '+' : '-',
+                                  portdata->ctrlin & ACM_CTRL_DSR ? '+' : '-',
+                                  portdata->ctrlin & ACM_CTRL_BRK ? '+' : '-',
+                                  portdata->ctrlin & ACM_CTRL_RI  ? '+' : '-',
+                                  portdata->ctrlin & ACM_CTRL_FRAMING ? '+' : '-',
+                                  portdata->ctrlin & ACM_CTRL_PARITY ? '+' : '-',
+                                  portdata->ctrlin & ACM_CTRL_OVERRUN ? '+' : '-');
+               break;
+       default:
+               dev_dbg(&port->dev, "unknown notification %d received: index %d len %d data0 %d data1 %d\n",
+                                  dr->bNotificationType, dr->wIndex,
+                                  dr->wLength, data[0], data[1]);
+               break;
+       }
+ exit:
+       dev_dbg(&port->dev, "Resubmitting interrupt IN urb %p\n", urb);
+       status = usb_submit_urb(urb, GFP_ATOMIC);
+       if (status)
+               dev_err(&port->dev, "usb_submit_urb failed with result %d", status);
+ }
+ static int vizzini_open(struct tty_struct *tty_param, struct usb_serial_port *port)
+ {
+       struct vizzini_port_private *portdata;
+       struct usb_serial *serial = port->serial;
+       struct tty_struct *tty = port->port.tty;
+       int i;
+       struct urb *urb;
+       int result;
+       portdata = usb_get_serial_port_data(port);
+       acm_set_control(port, portdata->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS);
+       /* Reset low level data toggle and start reading from endpoints */
+       for (i = 0; i < N_IN_URB; i++) {
+               dev_dbg(&port->dev, "%s urb %d\n", __func__, i);
+               urb = portdata->in_urbs[i];
+               if (!urb)
+                       continue;
+               if (urb->dev != serial->dev) {
+                       dev_dbg(&port->dev, "%s: dev %p != %p\n", __func__,
+                                          urb->dev, serial->dev);
+                       continue;
+               }
+               /*
+                * make sure endpoint data toggle is synchronized with the
+                * device
+                */
+               /* dev_dbg(&port->dev, "%s clearing halt on %x\n", __func__, urb->pipe); */
+               /* usb_clear_halt(urb->dev, urb->pipe); */
+               dev_dbg(&port->dev, "%s submitting urb %p\n", __func__, urb);
+               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);
+               }
+       }
+       tty->low_latency = 1;
+       /* 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);
+       }
+       return 0;
+ }
+ static void vizzini_close(struct usb_serial_port *port)
+ {
+       int                              i;
+       struct usb_serial               *serial = port->serial;
+       struct vizzini_port_private     *portdata;
+       struct tty_struct               *tty    = port->port.tty;
+       portdata = usb_get_serial_port_data(port);
+       acm_set_control(port, portdata->ctrlout = 0);
+       if (serial->dev) {
+               /* Stop reading/writing urbs */
+               for (i = 0; i < N_IN_URB; i++)
+                       usb_kill_urb(portdata->in_urbs[i]);
+       }
+       usb_kill_urb(port->interrupt_in_urb);
+       tty = NULL; /* FIXME */
+ }
+ static int vizzini_attach(struct usb_serial *serial)
+ {
+       struct vizzini_serial_private   *serial_priv       = usb_get_serial_data(serial);
+       struct usb_interface            *interface         = serial_priv->data_interface;
+       struct usb_host_interface       *iface_desc;
+       struct usb_endpoint_descriptor  *endpoint;
+       struct usb_endpoint_descriptor  *bulk_in_endpoint  = NULL;
+       struct usb_endpoint_descriptor  *bulk_out_endpoint = NULL;
+       struct usb_serial_port          *port;
+       struct vizzini_port_private     *portdata;
+       struct urb                      *urb;
+       int                              i, j;
+       /* Assume that there's exactly one serial port. */
+       port = serial->port[0];
+       /* The usb_serial is now fully set up, but we want to make a
+        * couple of modifications.  Namely, it was configured based
+        * upon the control interface and not the data interface, so
+        * it has no notion of the bulk in and out endpoints.  So we
+        * essentially do some of the same allocations and
+        * configurations that the usb-serial core would have done if
+        * it had not made any faulty assumptions about the
+        * endpoints. */
+       iface_desc = interface->cur_altsetting;
+       for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+               endpoint = &iface_desc->endpoint[i].desc;
+               if (usb_endpoint_is_bulk_in(endpoint))
+                       bulk_in_endpoint = endpoint;
+               if (usb_endpoint_is_bulk_out(endpoint))
+                       bulk_out_endpoint = endpoint;
+       }
+       if (!bulk_out_endpoint || !bulk_in_endpoint) {
+               dev_dbg(&port->dev, "Missing endpoint!\n");
+               return -EINVAL;
+       }
+       port->bulk_out_endpointAddress = bulk_out_endpoint->bEndpointAddress;
+       port->bulk_in_endpointAddress = bulk_in_endpoint->bEndpointAddress;
+       portdata = kzalloc(sizeof(*portdata), GFP_KERNEL);
+       if (!portdata) {
+               dev_dbg(&port->dev, "%s: kmalloc for vizzini_port_private (%d) failed!.\n",
+                                  __func__, i);
+               return -ENOMEM;
+       }
+       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;
+               }
+       }
+       /* Bulk OUT endpoints 0x1..0x4 map to register blocks 0..3 */
+       portdata->block = port->bulk_out_endpointAddress - 1;
+       usb_set_serial_port_data(port, portdata);
+       portdata->bcd_device = le16_to_cpu(serial->dev->descriptor.bcdDevice);
+       if (vizzini_rev_a(port))
+               dev_info(&port->dev, "Adapting to revA silicon\n");
+       /* 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.\n", __func__);
+                       continue;
+               }
+               /* Fill URB using supplied data. */
+               dev_dbg(&port->dev, "Filling URB %p, EP=%d buf=%p len=%d\n", urb, port->bulk_in_endpointAddress, portdata->in_buffer[j], IN_BUFLEN);
+               usb_fill_bulk_urb(urb, serial->dev,
+                                 usb_rcvbulkpipe(serial->dev,
+                                                 port->bulk_in_endpointAddress),
+                                 portdata->in_buffer[j], IN_BUFLEN,
+                                 vizzini_in_callback, port);
+               portdata->in_urbs[j] = urb;
+       }
+       return 0;
+ }
+ static void vizzini_serial_disconnect(struct usb_serial *serial)
+ {
+       struct usb_serial_port          *port;
+       struct vizzini_port_private     *portdata;
+       int                              i, j;
+       dev_dbg(&serial->dev->dev, "%s %p\n", __func__, serial);
+       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]);
+               }
+       }
+ }
+ static void vizzini_serial_release(struct usb_serial *serial)
+ {
+       struct usb_serial_port          *port;
+       struct vizzini_port_private     *portdata;
+       int                              i, j;
+       dev_dbg(&serial->dev->dev, "%s %p\n", __func__, serial);
+       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++)
+                       kfree(portdata->in_buffer[j]);
+               kfree(portdata);
+               usb_set_serial_port_data(port, NULL);
+       }
+ }
+ static int vizzini_calc_num_ports(struct usb_serial *serial)
+ {
+       return 1;
+ }
+ static int vizzini_probe(struct usb_serial *serial,
+                        const struct usb_device_id *id)
+ {
+       struct usb_interface *intf = serial->interface;
+       unsigned char *buffer = intf->altsetting->extra;
+       int buflen = intf->altsetting->extralen;
+       struct usb_device *usb_dev = interface_to_usbdev(intf);
+       struct usb_cdc_union_desc *union_header = NULL;
+       struct usb_cdc_country_functional_desc  *cfd = NULL;
+       int call_interface_num = -1;
+       int data_interface_num;
+       struct usb_interface *control_interface;
+       struct usb_interface *data_interface;
+       struct usb_endpoint_descriptor *epctrl;
+       struct usb_endpoint_descriptor *epread;
+       struct usb_endpoint_descriptor *epwrite;
+       struct vizzini_serial_private *serial_priv;
+       if (!buffer) {
+               dev_err(&intf->dev, "Weird descriptor references\n");
+               return -EINVAL;
+       }
+       if (!buflen) {
+               if (intf->cur_altsetting->endpoint->extralen && intf->cur_altsetting->endpoint->extra) {
+                       dev_dbg(&intf->dev, "Seeking extra descriptors on endpoint\n");
+                       buflen = intf->cur_altsetting->endpoint->extralen;
+                       buffer = intf->cur_altsetting->endpoint->extra;
+               } else {
+                       dev_err(&intf->dev, "Zero length descriptor references\n");
+                       return -EINVAL;
+               }
+       }
+       while (buflen > 0) {
+               if (buffer[1] != USB_DT_CS_INTERFACE) {
+                       dev_err(&intf->dev, "skipping garbage\n");
+                       goto next_desc;
+               }
+               switch (buffer[2]) {
+               case USB_CDC_UNION_TYPE: /* we've found it */
+                       if (union_header) {
+                               dev_err(&intf->dev, "More than one union descriptor, skipping ...\n");
+                               goto next_desc;
+                       }
+                       union_header = (struct usb_cdc_union_desc *)buffer;
+                       break;
+               case USB_CDC_COUNTRY_TYPE: /* export through sysfs */
+                       cfd = (struct usb_cdc_country_functional_desc *)buffer;
+                       break;
+               case USB_CDC_HEADER_TYPE: /* maybe check version */
+                       break; /* for now we ignore it */
+               case USB_CDC_CALL_MANAGEMENT_TYPE:
+                       call_interface_num = buffer[4];
+                       break;
+               default:
+                       /* there are LOTS more CDC descriptors that
+                        * could legitimately be found here.
+                        */
+                       dev_dbg(&intf->dev, "Ignoring descriptor: type %02x, length %d\n", buffer[2], buffer[0]);
+                       break;
+               }
+ next_desc:
+               buflen -= buffer[0];
+               buffer += buffer[0];
+       }
+       if (!union_header) {
+               if (call_interface_num > 0) {
+                       dev_dbg(&intf->dev, "No union descriptor, using call management descriptor\n");
+                       data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num));
+                       control_interface = intf;
+               } else {
+                       dev_dbg(&intf->dev, "No union descriptor, giving up\n");
+                       return -ENODEV;
+               }
+       } else {
+               control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0);
+               data_interface    = usb_ifnum_to_if(usb_dev, (data_interface_num = union_header->bSlaveInterface0));
+               if (!control_interface || !data_interface) {
+                       dev_dbg(&intf->dev, "no interfaces\n");
+                       return -ENODEV;
+               }
+       }
+       if (data_interface_num != call_interface_num)
+               dev_dbg(&intf->dev, "Separate call control interface. That is not fully supported.\n");
+       /* workaround for switched interfaces */
+       if (data_interface->cur_altsetting->desc.bInterfaceClass != CDC_DATA_INTERFACE_TYPE) {
+               if (control_interface->cur_altsetting->desc.bInterfaceClass == CDC_DATA_INTERFACE_TYPE) {
+                       struct usb_interface *t;
+                       t = control_interface;
+                       control_interface = data_interface;
+                       data_interface = t;
+               } else {
+                       return -EINVAL;
+               }
+       }
+       /* Accept probe requests only for the control interface */
+       if (intf != control_interface)
+               return -ENODEV;
+       if (usb_interface_claimed(data_interface)) { /* valid in this context */
+               dev_dbg(&intf->dev, "The data interface isn't available\n");
+               return -EBUSY;
+       }
+       if (data_interface->cur_altsetting->desc.bNumEndpoints < 2)
+               return -EINVAL;
+       epctrl  = &control_interface->cur_altsetting->endpoint[0].desc;
+       epread  = &data_interface->cur_altsetting->endpoint[0].desc;
+       epwrite = &data_interface->cur_altsetting->endpoint[1].desc;
+       if (!usb_endpoint_dir_in(epread)) {
+               struct usb_endpoint_descriptor *t;
+               t   = epread;
+               epread  = epwrite;
+               epwrite = t;
+       }
+       /* The documentation suggests that we allocate private storage
+        * with the attach() entry point, but we can't allow the data
+        * interface to remain unclaimed until then; so we need
+        * somewhere to save the claimed interface now. */
+       serial_priv = kzalloc(sizeof(struct vizzini_serial_private),
+                             GFP_KERNEL);
+       if (!serial_priv)
+               goto alloc_fail;
+       usb_set_serial_data(serial, serial_priv);
+       //usb_driver_claim_interface(&vizzini_driver, data_interface, NULL);
+       /* Don't set the data interface private data.  When we
+        * disconnect we test this field against NULL to discover
+        * whether we're dealing with the control or data
+        * interface. */
+       serial_priv->data_interface = data_interface;
+       return 0;
+ alloc_fail:
+       return -ENOMEM;
+ }
+ static struct usb_serial_driver vizzini_device = {
+       .driver = {
+               .owner =    THIS_MODULE,
+               .name =     "vizzini",
+       },
+       .description =          "Vizzini USB serial port",
+       .id_table =             id_table,
+       .calc_num_ports =       vizzini_calc_num_ports,
+       .probe =                vizzini_probe,
+       .open =                 vizzini_open,
+       .close =                vizzini_close,
+       .write =                vizzini_write,
+       .write_room =           vizzini_write_room,
+       .ioctl =                vizzini_ioctl,
+       .set_termios =          vizzini_set_termios,
+       .break_ctl =            vizzini_break_ctl,
+       .tiocmget =             vizzini_tiocmget,
+       .tiocmset =             vizzini_tiocmset,
+       .attach =               vizzini_attach,
+       .disconnect =           vizzini_serial_disconnect,
+       .release =              vizzini_serial_release,
+       .read_int_callback =    vizzini_int_callback,
+ };
+ static struct usb_serial_driver * const serial_drivers[] = {
+       &vizzini_device, NULL
+ };
+ module_usb_serial_driver(serial_drivers, id_table);
+ MODULE_AUTHOR(DRIVER_AUTHOR);
+ MODULE_DESCRIPTION(DRIVER_DESC);
+ MODULE_VERSION(DRIVER_VERSION);
+ MODULE_LICENSE("GPL");
index b36077de72b96e17fe9eb1c830ec73c0d6e3f0eb,efa32bf5f7587f49d478eb7daec89a535f278357..346c7efc20b06d42899616cb8bb0766007cde82e
@@@ -723,8 -651,9 +651,9 @@@ static int firm_close(struct usb_serial
  static void firm_setup_port(struct tty_struct *tty)
  {
        struct usb_serial_port *port = tty->driver_data;
+       struct device *dev = &port->dev;
        struct whiteheat_port_settings port_settings;
 -      unsigned int cflag = tty->termios->c_cflag;
 +      unsigned int cflag = tty->termios.c_cflag;
  
        port_settings.port = port->number + 1;