Merge tag 'usb-4.10-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
authorLinus Torvalds <torvalds@linux-foundation.org>
Sun, 15 Jan 2017 20:34:35 +0000 (12:34 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sun, 15 Jan 2017 20:34:35 +0000 (12:34 -0800)
Pull USB fixes from Greg KH:
 "Here are a few small USB driver fixes for 4.10-rc4 to resolve some
  reported issues.

  The "largest" here is a number of bugs being fixed in the ch341
  usb-serial driver, to hopefully resolve the mess of different devices
  floating around that use this driver that have been having problems
  with the 4.10-rc1 release.

  There's also a tiny musb fix that I missed in the last pull request,
  as well as the traditional xhci fix rounding out the batch.

  All have been in linux-next with no reported issues"

* tag 'usb-4.10-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb:
  xhci: fix deadlock at host remove by running watchdog correctly
  USB: serial: ch341: fix control-message error handling
  usb: musb: fix runtime PM in debugfs
  wusbcore: Fix one more crypto-on-the-stack bug
  USB: serial: kl5kusb105: fix line-state error handling
  USB: serial: ch341: fix baud rate and line-control handling
  USB: serial: ch341: fix line settings after reset-resume
  USB: serial: ch341: fix resume after reset
  USB: serial: ch341: fix open error handling
  USB: serial: ch341: fix modem-control and B0 handling
  USB: serial: ch341: fix open and resume after B0
  USB: serial: ch341: fix initial modem-control state

drivers/usb/host/xhci-ring.c
drivers/usb/host/xhci.c
drivers/usb/musb/musb_debugfs.c
drivers/usb/serial/ch341.c
drivers/usb/serial/kl5kusb105.c
drivers/usb/wusbcore/crypto.c

index 25f522b09dd9746938168e6f675464db9f2e6740..e32029a31ca4d2ed5856c18e6e10b4b40de1132a 100644 (file)
@@ -913,17 +913,6 @@ void xhci_stop_endpoint_command_watchdog(unsigned long arg)
        spin_lock_irqsave(&xhci->lock, flags);
 
        ep->stop_cmds_pending--;
-       if (xhci->xhc_state & XHCI_STATE_REMOVING) {
-               spin_unlock_irqrestore(&xhci->lock, flags);
-               return;
-       }
-       if (xhci->xhc_state & XHCI_STATE_DYING) {
-               xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
-                               "Stop EP timer ran, but another timer marked "
-                               "xHCI as DYING, exiting.");
-               spin_unlock_irqrestore(&xhci->lock, flags);
-               return;
-       }
        if (!(ep->stop_cmds_pending == 0 && (ep->ep_state & EP_HALT_PENDING))) {
                xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
                                "Stop EP timer ran, but no command pending, "
index 0c8deb9ed42def112efc8ad1aaf95526315c164f..9a0ec116654acd27740d497c76ba1a6bb6ab6dd9 100644 (file)
@@ -1534,19 +1534,6 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
                xhci_urb_free_priv(urb_priv);
                return ret;
        }
-       if ((xhci->xhc_state & XHCI_STATE_DYING) ||
-                       (xhci->xhc_state & XHCI_STATE_HALTED)) {
-               xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
-                               "Ep 0x%x: URB %p to be canceled on "
-                               "non-responsive xHCI host.",
-                               urb->ep->desc.bEndpointAddress, urb);
-               /* Let the stop endpoint command watchdog timer (which set this
-                * state) finish cleaning up the endpoint TD lists.  We must
-                * have caught it in the middle of dropping a lock and giving
-                * back an URB.
-                */
-               goto done;
-       }
 
        ep_index = xhci_get_endpoint_index(&urb->ep->desc);
        ep = &xhci->devs[urb->dev->slot_id]->eps[ep_index];
index 4fef50e5c8c1295364aca0a28ba9cf8da005ac21..dd70c88419d20798b738c3da2df009887fdfec7f 100644 (file)
@@ -114,6 +114,7 @@ static int musb_regdump_show(struct seq_file *s, void *unused)
        unsigned                i;
 
        seq_printf(s, "MUSB (M)HDRC Register Dump\n");
+       pm_runtime_get_sync(musb->controller);
 
        for (i = 0; i < ARRAY_SIZE(musb_regmap); i++) {
                switch (musb_regmap[i].size) {
@@ -132,6 +133,8 @@ static int musb_regdump_show(struct seq_file *s, void *unused)
                }
        }
 
+       pm_runtime_mark_last_busy(musb->controller);
+       pm_runtime_put_autosuspend(musb->controller);
        return 0;
 }
 
@@ -145,7 +148,10 @@ static int musb_test_mode_show(struct seq_file *s, void *unused)
        struct musb             *musb = s->private;
        unsigned                test;
 
+       pm_runtime_get_sync(musb->controller);
        test = musb_readb(musb->mregs, MUSB_TESTMODE);
+       pm_runtime_mark_last_busy(musb->controller);
+       pm_runtime_put_autosuspend(musb->controller);
 
        if (test & MUSB_TEST_FORCE_HOST)
                seq_printf(s, "force host\n");
@@ -194,11 +200,12 @@ static ssize_t musb_test_mode_write(struct file *file,
        u8                      test;
        char                    buf[18];
 
+       pm_runtime_get_sync(musb->controller);
        test = musb_readb(musb->mregs, MUSB_TESTMODE);
        if (test) {
                dev_err(musb->controller, "Error: test mode is already set. "
                        "Please do USB Bus Reset to start a new test.\n");
-               return count;
+               goto ret;
        }
 
        memset(buf, 0x00, sizeof(buf));
@@ -234,6 +241,9 @@ static ssize_t musb_test_mode_write(struct file *file,
 
        musb_writeb(musb->mregs, MUSB_TESTMODE, test);
 
+ret:
+       pm_runtime_mark_last_busy(musb->controller);
+       pm_runtime_put_autosuspend(musb->controller);
        return count;
 }
 
@@ -254,8 +264,13 @@ static int musb_softconnect_show(struct seq_file *s, void *unused)
        switch (musb->xceiv->otg->state) {
        case OTG_STATE_A_HOST:
        case OTG_STATE_A_WAIT_BCON:
+               pm_runtime_get_sync(musb->controller);
+
                reg = musb_readb(musb->mregs, MUSB_DEVCTL);
                connect = reg & MUSB_DEVCTL_SESSION ? 1 : 0;
+
+               pm_runtime_mark_last_busy(musb->controller);
+               pm_runtime_put_autosuspend(musb->controller);
                break;
        default:
                connect = -1;
@@ -284,6 +299,7 @@ static ssize_t musb_softconnect_write(struct file *file,
        if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
                return -EFAULT;
 
+       pm_runtime_get_sync(musb->controller);
        if (!strncmp(buf, "0", 1)) {
                switch (musb->xceiv->otg->state) {
                case OTG_STATE_A_HOST:
@@ -314,6 +330,8 @@ static ssize_t musb_softconnect_write(struct file *file,
                }
        }
 
+       pm_runtime_mark_last_busy(musb->controller);
+       pm_runtime_put_autosuspend(musb->controller);
        return count;
 }
 
index 2597b83a8ae254d0eff28b2d2d124ff51c196248..95aa5233726cf86166ae5aad2ea88c446e894d13 100644 (file)
@@ -95,6 +95,7 @@ struct ch341_private {
        unsigned baud_rate; /* set baud rate */
        u8 line_control; /* set line control value RTS/DTR */
        u8 line_status; /* active status of modem control inputs */
+       u8 lcr;
 };
 
 static void ch341_set_termios(struct tty_struct *tty,
@@ -112,6 +113,8 @@ static int ch341_control_out(struct usb_device *dev, u8 request,
        r = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), request,
                            USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
                            value, index, NULL, 0, DEFAULT_TIMEOUT);
+       if (r < 0)
+               dev_err(&dev->dev, "failed to send control message: %d\n", r);
 
        return r;
 }
@@ -129,11 +132,24 @@ static int ch341_control_in(struct usb_device *dev,
        r = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), request,
                            USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
                            value, index, buf, bufsize, DEFAULT_TIMEOUT);
-       return r;
+       if (r < bufsize) {
+               if (r >= 0) {
+                       dev_err(&dev->dev,
+                               "short control message received (%d < %u)\n",
+                               r, bufsize);
+                       r = -EIO;
+               }
+
+               dev_err(&dev->dev, "failed to receive control message: %d\n",
+                       r);
+               return r;
+       }
+
+       return 0;
 }
 
-static int ch341_init_set_baudrate(struct usb_device *dev,
-                                  struct ch341_private *priv, unsigned ctrl)
+static int ch341_set_baudrate_lcr(struct usb_device *dev,
+                                 struct ch341_private *priv, u8 lcr)
 {
        short a;
        int r;
@@ -156,9 +172,19 @@ static int ch341_init_set_baudrate(struct usb_device *dev,
        factor = 0x10000 - factor;
        a = (factor & 0xff00) | divisor;
 
-       /* 0x9c is "enable SFR_UART Control register and timer" */
-       r = ch341_control_out(dev, CH341_REQ_SERIAL_INIT,
-                             0x9c | (ctrl << 8), a | 0x80);
+       /*
+        * CH341A buffers data until a full endpoint-size packet (32 bytes)
+        * has been received unless bit 7 is set.
+        */
+       a |= BIT(7);
+
+       r = ch341_control_out(dev, CH341_REQ_WRITE_REG, 0x1312, a);
+       if (r)
+               return r;
+
+       r = ch341_control_out(dev, CH341_REQ_WRITE_REG, 0x2518, lcr);
+       if (r)
+               return r;
 
        return r;
 }
@@ -170,9 +196,9 @@ static int ch341_set_handshake(struct usb_device *dev, u8 control)
 
 static int ch341_get_status(struct usb_device *dev, struct ch341_private *priv)
 {
+       const unsigned int size = 2;
        char *buffer;
        int r;
-       const unsigned size = 8;
        unsigned long flags;
 
        buffer = kmalloc(size, GFP_KERNEL);
@@ -183,14 +209,9 @@ static int ch341_get_status(struct usb_device *dev, struct ch341_private *priv)
        if (r < 0)
                goto out;
 
-       /* setup the private status if available */
-       if (r == 2) {
-               r = 0;
-               spin_lock_irqsave(&priv->lock, flags);
-               priv->line_status = (~(*buffer)) & CH341_BITS_MODEM_STAT;
-               spin_unlock_irqrestore(&priv->lock, flags);
-       } else
-               r = -EPROTO;
+       spin_lock_irqsave(&priv->lock, flags);
+       priv->line_status = (~(*buffer)) & CH341_BITS_MODEM_STAT;
+       spin_unlock_irqrestore(&priv->lock, flags);
 
 out:   kfree(buffer);
        return r;
@@ -200,9 +221,9 @@ out:        kfree(buffer);
 
 static int ch341_configure(struct usb_device *dev, struct ch341_private *priv)
 {
+       const unsigned int size = 2;
        char *buffer;
        int r;
-       const unsigned size = 8;
 
        buffer = kmalloc(size, GFP_KERNEL);
        if (!buffer)
@@ -232,7 +253,7 @@ static int ch341_configure(struct usb_device *dev, struct ch341_private *priv)
        if (r < 0)
                goto out;
 
-       r = ch341_init_set_baudrate(dev, priv, 0);
+       r = ch341_set_baudrate_lcr(dev, priv, priv->lcr);
        if (r < 0)
                goto out;
 
@@ -258,7 +279,6 @@ static int ch341_port_probe(struct usb_serial_port *port)
 
        spin_lock_init(&priv->lock);
        priv->baud_rate = DEFAULT_BAUD_RATE;
-       priv->line_control = CH341_BIT_RTS | CH341_BIT_DTR;
 
        r = ch341_configure(port->serial->dev, priv);
        if (r < 0)
@@ -320,7 +340,7 @@ static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port)
 
        r = ch341_configure(serial->dev, priv);
        if (r)
-               goto out;
+               return r;
 
        if (tty)
                ch341_set_termios(tty, port, NULL);
@@ -330,12 +350,19 @@ static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port)
        if (r) {
                dev_err(&port->dev, "%s - failed to submit interrupt urb: %d\n",
                        __func__, r);
-               goto out;
+               return r;
        }
 
        r = usb_serial_generic_open(tty, port);
+       if (r)
+               goto err_kill_interrupt_urb;
+
+       return 0;
+
+err_kill_interrupt_urb:
+       usb_kill_urb(port->interrupt_in_urb);
 
-out:   return r;
+       return r;
 }
 
 /* Old_termios contains the original termios settings and
@@ -356,7 +383,6 @@ static void ch341_set_termios(struct tty_struct *tty,
 
        baud_rate = tty_get_baud_rate(tty);
 
-       priv->baud_rate = baud_rate;
        ctrl = CH341_LCR_ENABLE_RX | CH341_LCR_ENABLE_TX;
 
        switch (C_CSIZE(tty)) {
@@ -386,22 +412,25 @@ static void ch341_set_termios(struct tty_struct *tty,
                ctrl |= CH341_LCR_STOP_BITS_2;
 
        if (baud_rate) {
-               spin_lock_irqsave(&priv->lock, flags);
-               priv->line_control |= (CH341_BIT_DTR | CH341_BIT_RTS);
-               spin_unlock_irqrestore(&priv->lock, flags);
-               r = ch341_init_set_baudrate(port->serial->dev, priv, ctrl);
+               priv->baud_rate = baud_rate;
+
+               r = ch341_set_baudrate_lcr(port->serial->dev, priv, ctrl);
                if (r < 0 && old_termios) {
                        priv->baud_rate = tty_termios_baud_rate(old_termios);
                        tty_termios_copy_hw(&tty->termios, old_termios);
+               } else if (r == 0) {
+                       priv->lcr = ctrl;
                }
-       } else {
-               spin_lock_irqsave(&priv->lock, flags);
-               priv->line_control &= ~(CH341_BIT_DTR | CH341_BIT_RTS);
-               spin_unlock_irqrestore(&priv->lock, flags);
        }
 
-       ch341_set_handshake(port->serial->dev, priv->line_control);
+       spin_lock_irqsave(&priv->lock, flags);
+       if (C_BAUD(tty) == B0)
+               priv->line_control &= ~(CH341_BIT_DTR | CH341_BIT_RTS);
+       else if (old_termios && (old_termios->c_cflag & CBAUD) == B0)
+               priv->line_control |= (CH341_BIT_DTR | CH341_BIT_RTS);
+       spin_unlock_irqrestore(&priv->lock, flags);
 
+       ch341_set_handshake(port->serial->dev, priv->line_control);
 }
 
 static void ch341_break_ctl(struct tty_struct *tty, int break_state)
@@ -576,14 +605,23 @@ static int ch341_tiocmget(struct tty_struct *tty)
 
 static int ch341_reset_resume(struct usb_serial *serial)
 {
-       struct ch341_private *priv;
-
-       priv = usb_get_serial_port_data(serial->port[0]);
+       struct usb_serial_port *port = serial->port[0];
+       struct ch341_private *priv = usb_get_serial_port_data(port);
+       int ret;
 
        /* reconfigure ch341 serial port after bus-reset */
        ch341_configure(serial->dev, priv);
 
-       return 0;
+       if (tty_port_initialized(&port->port)) {
+               ret = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO);
+               if (ret) {
+                       dev_err(&port->dev, "failed to submit interrupt urb: %d\n",
+                               ret);
+                       return ret;
+               }
+       }
+
+       return usb_serial_generic_resume(serial);
 }
 
 static struct usb_serial_driver ch341_device = {
index 0ee190fc1bf8ce7154a4a4eac7023a377aa03365..6cb45757818fae2222383358b4d38d7c87b2dbf4 100644 (file)
@@ -192,10 +192,11 @@ static int klsi_105_get_line_state(struct usb_serial_port *port,
                             status_buf, KLSI_STATUSBUF_LEN,
                             10000
                             );
-       if (rc < 0)
-               dev_err(&port->dev, "Reading line status failed (error = %d)\n",
-                       rc);
-       else {
+       if (rc != KLSI_STATUSBUF_LEN) {
+               dev_err(&port->dev, "reading line status failed: %d\n", rc);
+               if (rc >= 0)
+                       rc = -EIO;
+       } else {
                status = get_unaligned_le16(status_buf);
 
                dev_info(&port->serial->dev->dev, "read status %x %x\n",
index 79451f7ef1b76301cc881379ad28ce12e4b4dc33..062c205f00469faf1f7226e152f61d920d71f27b 100644 (file)
@@ -216,7 +216,6 @@ static int wusb_ccm_mac(struct crypto_skcipher *tfm_cbc,
        struct scatterlist sg[4], sg_dst;
        void *dst_buf;
        size_t dst_size;
-       const u8 bzero[16] = { 0 };
        u8 iv[crypto_skcipher_ivsize(tfm_cbc)];
        size_t zero_padding;
 
@@ -261,7 +260,7 @@ static int wusb_ccm_mac(struct crypto_skcipher *tfm_cbc,
        sg_set_buf(&sg[1], &scratch->b1, sizeof(scratch->b1));
        sg_set_buf(&sg[2], b, blen);
        /* 0 if well behaved :) */
-       sg_set_buf(&sg[3], bzero, zero_padding);
+       sg_set_page(&sg[3], ZERO_PAGE(0), zero_padding, 0);
        sg_init_one(&sg_dst, dst_buf, dst_size);
 
        skcipher_request_set_tfm(req, tfm_cbc);