From: Stephen Rothwell Date: Wed, 19 Sep 2012 04:16:33 +0000 (+1000) Subject: Merge remote-tracking branch 'usb/usb-next' X-Git-Tag: next-20120919~22 X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=866de3f7fe7132ccdfc4fd41c5a2f0d56e850919;p=karo-tx-linux.git Merge remote-tracking branch 'usb/usb-next' 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 --- 866de3f7fe7132ccdfc4fd41c5a2f0d56e850919 diff --cc arch/arm/mach-omap2/twl-common.c index fb1f7770139a,329b726012f3..697bee726d6d --- a/arch/arm/mach-omap2/twl-common.c +++ b/arch/arm/mach-omap2/twl-common.c @@@ -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, diff --cc drivers/staging/serqt_usb2/serqt_usb2.c index c90de969be8f,376269b2bbfc..51a706976b02 --- a/drivers/staging/serqt_usb2/serqt_usb2.c +++ b/drivers/staging/serqt_usb2/serqt_usb2.c @@@ -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 */ } diff --cc drivers/usb/serial/cypress_m8.c index be34f153e566,3f13cdd159d4..1befce21e173 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@@ -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; } diff --cc drivers/usb/serial/digi_acceleport.c index afd9d2ec577b,d3a8941f66bc..c86f68c6b078 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@@ -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); + struct device *dev = &port->dev; - unsigned int iflag = tty->termios->c_iflag; - unsigned int cflag = tty->termios->c_cflag; + 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]; diff --cc drivers/usb/serial/ftdi_sio.c index 0c8d1c226273,8742a0ee2091..6f7ace8822b7 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@@ -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 */ diff --cc drivers/usb/serial/io_edgeport.c index f435575c4e6e,75b7ccdd2652..8e6faaf3580c --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@@ -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; diff --cc drivers/usb/serial/io_ti.c index 765978ae752e,21c7efa57acf..a2209cd45093 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@@ -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; } @@@ -2357,12 -2302,12 +2302,12 @@@ /* 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; diff --cc drivers/usb/serial/iuu_phoenix.c index bf3864045c18,91e6e372cf17..01da3ea36e89 --- a/drivers/usb/serial/iuu_phoenix.c +++ b/drivers/usb/serial/iuu_phoenix.c @@@ -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; diff --cc drivers/usb/serial/kl5kusb105.c index def9ad258715,e4aa6c0632d7..3f6d7376c02d --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c @@@ -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); + struct device *dev = &port->dev; - unsigned int iflag = tty->termios->c_iflag; + 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; diff --cc drivers/usb/serial/mos7720.c index 012f67b2e4cc,af7bc9b6280c..1bf1ad066666 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@@ -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); diff --cc drivers/usb/serial/mos7840.c index 402c32d7accb,a94297d9c7ac..d6d4eeca8c68 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@@ -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 */ diff --cc drivers/usb/serial/oti6858.c index 9f555560bfbf,1498b3ddfead..933241f03fd8 --- a/drivers/usb/serial/oti6858.c +++ b/drivers/usb/serial/oti6858.c @@@ -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; diff --cc drivers/usb/serial/ssu100.c index cf2d30cf7588,6635743bd8c2..015810b3785b --- a/drivers/usb/serial/ssu100.c +++ b/drivers/usb/serial/ssu100.c @@@ -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); } diff --cc drivers/usb/serial/ti_usb_3410_5052.c index f502a16aac21,648249e74125..6f49392cda5b --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@@ -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) { @@@ -562,9 -549,9 +549,9 @@@ 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; diff --cc drivers/usb/serial/vizzini.c index 000000000000,2ac48fe3f4ca..253eaf8d4b67 mode 000000,100644..100644 --- a/drivers/usb/serial/vizzini.c +++ b/drivers/usb/serial/vizzini.c @@@ -1,0 -1,1363 +1,1363 @@@ + /* + * 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 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 " + #define DRIVER_DESC "USB Driver for Vizzini USB serial port" + + #undef VIZZINI_IWA + + + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + + #include + #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; ++ 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"); diff --cc drivers/usb/serial/whiteheat.c index b36077de72b9,efa32bf5f758..346c7efc20b0 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@@ -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;