Merge tag 'usb-serial-5.13-rc1' of https://git.kernel.org/pub/scm/linux/kernel/git...
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 22 Apr 2021 09:19:49 +0000 (11:19 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 22 Apr 2021 09:19:49 +0000 (11:19 +0200)
Johan writes:

USB-serial updates for 5.13-rc1

Here are the USB-serial updates for 5.13-rc1, including:

 - better type detection for pl2303
 - support for more line speeds for pl2303 (TA/TB)
 - fixed CSIZE handling for the new xr driver
 - core support for multi-interface functions
 - TIOCGSERIAL and TIOCSSERIAL fixes
 - generic TIOCSSERIAL support (e.g. for closing_wait)
 - fixed return value for unsupported ioctls
 - support for gpio valid masks in cp210x
 - drain-delay fixes and improvements
 - support for multi-port devices for xr
 - generalisation of the xr driver to support three new device classes
   (XR21B142X, XR21B1411 and XR2280X)

Included are also various clean ups.

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

* tag 'usb-serial-5.13-rc1' of https://git.kernel.org/pub/scm/linux/kernel/git/johan/usb-serial: (72 commits)
  USB: cdc-acm: add more Maxlinear/Exar models to ignore list
  USB: serial: xr: add copyright notice
  USB: serial: xr: reset FIFOs on open
  USB: serial: xr: add support for XR22801, XR22802, XR22804
  USB: serial: xr: add support for XR21B1411
  USB: serial: xr: add support for XR21B1421, XR21B1422 and XR21B1424
  USB: serial: xr: add type abstraction
  USB: serial: xr: drop type prefix from shared defines
  USB: serial: xr: move pin configuration to probe
  USB: serial: xr: rename GPIO-pin defines
  USB: serial: xr: rename GPIO-mode defines
  USB: serial: xr: add support for XR21V1412 and XR21V1414
  USB: serial: ti_usb_3410_5052: clean up termios CSIZE handling
  USB: serial: ti_usb_3410_5052: use kernel types consistently
  USB: serial: ti_usb_3410_5052: add port-command helpers
  USB: serial: ti_usb_3410_5052: clean up vendor-request helpers
  USB: serial: ti_usb_3410_5052: drop unnecessary packed attributes
  USB: serial: io_ti: drop unnecessary packed attributes
  USB: serial: io_ti: use kernel types consistently
  USB: serial: io_ti: add read-port-command helper
  ...

1  2 
drivers/usb/class/cdc-acm.c

@@@ -147,29 -147,17 +147,29 @@@ static inline int acm_set_control(struc
  #define acm_send_break(acm, ms) \
        acm_ctrl_msg(acm, USB_CDC_REQ_SEND_BREAK, ms, NULL, 0)
  
 -static void acm_kill_urbs(struct acm *acm)
 +static void acm_poison_urbs(struct acm *acm)
  {
        int i;
  
 -      usb_kill_urb(acm->ctrlurb);
 +      usb_poison_urb(acm->ctrlurb);
        for (i = 0; i < ACM_NW; i++)
 -              usb_kill_urb(acm->wb[i].urb);
 +              usb_poison_urb(acm->wb[i].urb);
        for (i = 0; i < acm->rx_buflimit; i++)
 -              usb_kill_urb(acm->read_urbs[i]);
 +              usb_poison_urb(acm->read_urbs[i]);
 +}
 +
 +static void acm_unpoison_urbs(struct acm *acm)
 +{
 +      int i;
 +
 +      for (i = 0; i < acm->rx_buflimit; i++)
 +              usb_unpoison_urb(acm->read_urbs[i]);
 +      for (i = 0; i < ACM_NW; i++)
 +              usb_unpoison_urb(acm->wb[i].urb);
 +      usb_unpoison_urb(acm->ctrlurb);
  }
  
 +
  /*
   * Write buffer management.
   * All of these assume proper locks taken by the caller.
@@@ -238,10 -226,9 +238,10 @@@ static int acm_start_wb(struct acm *acm
  
        rc = usb_submit_urb(wb->urb, GFP_ATOMIC);
        if (rc < 0) {
 -              dev_err(&acm->data->dev,
 -                      "%s - usb_submit_urb(write bulk) failed: %d\n",
 -                      __func__, rc);
 +              if (rc != -EPERM)
 +                      dev_err(&acm->data->dev,
 +                              "%s - usb_submit_urb(write bulk) failed: %d\n",
 +                              __func__, rc);
                acm_write_done(acm, wb);
        }
        return rc;
@@@ -326,10 -313,8 +326,10 @@@ static void acm_process_notification(st
                        acm->iocount.dsr++;
                if (difference & ACM_CTRL_DCD)
                        acm->iocount.dcd++;
 -              if (newctrl & ACM_CTRL_BRK)
 +              if (newctrl & ACM_CTRL_BRK) {
                        acm->iocount.brk++;
 +                      tty_insert_flip_char(&acm->port, 0, TTY_BREAK);
 +              }
                if (newctrl & ACM_CTRL_RI)
                        acm->iocount.rng++;
                if (newctrl & ACM_CTRL_FRAMING)
@@@ -495,6 -480,11 +495,6 @@@ static void acm_read_bulk_callback(stru
        dev_vdbg(&acm->data->dev, "got urb %d, len %d, status %d\n",
                rb->index, urb->actual_length, status);
  
 -      if (!acm->dev) {
 -              dev_dbg(&acm->data->dev, "%s - disconnected\n", __func__);
 -              return;
 -      }
 -
        switch (status) {
        case 0:
                usb_mark_last_busy(acm->dev);
@@@ -659,8 -649,7 +659,8 @@@ static void acm_port_dtr_rts(struct tty
  
        res = acm_set_control(acm, val);
        if (res && (acm->ctrl_caps & USB_CDC_CAP_LINE))
 -              dev_err(&acm->control->dev, "failed to set dtr/rts\n");
 +              /* This is broken in too many devices to spam the logs */
 +              dev_dbg(&acm->control->dev, "failed to set dtr/rts\n");
  }
  
  static int acm_port_activate(struct tty_port *port, struct tty_struct *tty)
@@@ -742,7 -731,6 +742,7 @@@ static void acm_port_shutdown(struct tt
         * Need to grab write_lock to prevent race with resume, but no need to
         * hold it due to the tty-port initialised flag.
         */
 +      acm_poison_urbs(acm);
        spin_lock_irq(&acm->write_lock);
        spin_unlock_irq(&acm->write_lock);
  
                usb_autopm_put_interface_async(acm->control);
        }
  
 -      acm_kill_urbs(acm);
 +      acm_unpoison_urbs(acm);
 +
  }
  
  static void acm_tty_cleanup(struct tty_struct *tty)
@@@ -929,7 -916,8 +929,7 @@@ static int get_serial_info(struct tty_s
  {
        struct acm *acm = tty->driver_data;
  
 -      ss->xmit_fifo_size = acm->writesize;
 -      ss->baud_base = le32_to_cpu(acm->line.dwDTERate);
 +      ss->line = acm->minor;
        ss->close_delay = jiffies_to_msecs(acm->port.close_delay) / 10;
        ss->closing_wait = acm->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
                                ASYNC_CLOSING_WAIT_NONE :
@@@ -941,6 -929,7 +941,6 @@@ static int set_serial_info(struct tty_s
  {
        struct acm *acm = tty->driver_data;
        unsigned int closing_wait, close_delay;
 -      unsigned int old_closing_wait, old_close_delay;
        int retval = 0;
  
        close_delay = msecs_to_jiffies(ss->close_delay * 10);
                        ASYNC_CLOSING_WAIT_NONE :
                        msecs_to_jiffies(ss->closing_wait * 10);
  
 -      /* we must redo the rounding here, so that the values match */
 -      old_close_delay = jiffies_to_msecs(acm->port.close_delay) / 10;
 -      old_closing_wait = acm->port.closing_wait == ASYNC_CLOSING_WAIT_NONE ?
 -                              ASYNC_CLOSING_WAIT_NONE :
 -                              jiffies_to_msecs(acm->port.closing_wait) / 10;
 -
        mutex_lock(&acm->port.mutex);
  
        if (!capable(CAP_SYS_ADMIN)) {
 -              if ((ss->close_delay != old_close_delay) ||
 -                  (ss->closing_wait != old_closing_wait))
 +              if ((close_delay != acm->port.close_delay) ||
 +                  (closing_wait != acm->port.closing_wait))
                        retval = -EPERM;
 -              else
 -                      retval = -EOPNOTSUPP;
        } else {
                acm->port.close_delay  = close_delay;
                acm->port.closing_wait = closing_wait;
@@@ -1299,6 -1296,13 +1299,6 @@@ skip_normal_probe
        if (!combined_interfaces && intf != control_interface)
                return -ENODEV;
  
 -      if (!combined_interfaces && 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 ||
            control_interface->cur_altsetting->desc.bNumEndpoints == 0)
                return -EINVAL;
@@@ -1319,8 -1323,8 +1319,8 @@@ made_compressed_probe
        dev_dbg(&intf->dev, "interfaces are valid\n");
  
        acm = kzalloc(sizeof(struct acm), GFP_KERNEL);
 -      if (acm == NULL)
 -              goto alloc_fail;
 +      if (!acm)
 +              return -ENOMEM;
  
        tty_port_init(&acm->port);
        acm->port.ops = &acm_port_ops;
  
        minor = acm_alloc_minor(acm);
        if (minor < 0)
 -              goto alloc_fail1;
 +              goto err_put_port;
  
        acm->minor = minor;
        acm->dev = usb_dev;
  
        buf = usb_alloc_coherent(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma);
        if (!buf)
 -              goto alloc_fail1;
 +              goto err_put_port;
        acm->ctrl_buffer = buf;
  
        if (acm_write_buffers_alloc(acm) < 0)
 -              goto alloc_fail2;
 +              goto err_free_ctrl_buffer;
  
        acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL);
        if (!acm->ctrlurb)
 -              goto alloc_fail3;
 +              goto err_free_write_buffers;
  
        for (i = 0; i < num_rx_buf; i++) {
                struct acm_rb *rb = &(acm->read_buffers[i]);
                rb->base = usb_alloc_coherent(acm->dev, readsize, GFP_KERNEL,
                                                                &rb->dma);
                if (!rb->base)
 -                      goto alloc_fail4;
 +                      goto err_free_read_urbs;
                rb->index = i;
                rb->instance = acm;
  
                urb = usb_alloc_urb(0, GFP_KERNEL);
                if (!urb)
 -                      goto alloc_fail4;
 +                      goto err_free_read_urbs;
  
                urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
                urb->transfer_dma = rb->dma;
                struct acm_wb *snd = &(acm->wb[i]);
  
                snd->urb = usb_alloc_urb(0, GFP_KERNEL);
 -              if (snd->urb == NULL)
 -                      goto alloc_fail5;
 +              if (!snd->urb)
 +                      goto err_free_write_urbs;
  
                if (usb_endpoint_xfer_int(epwrite))
                        usb_fill_int_urb(snd->urb, usb_dev, acm->out,
  
        i = device_create_file(&intf->dev, &dev_attr_bmCapabilities);
        if (i < 0)
 -              goto alloc_fail5;
 +              goto err_free_write_urbs;
  
        if (h.usb_cdc_country_functional_desc) { /* export the country data */
                struct usb_cdc_country_functional_desc * cfd =
@@@ -1476,21 -1480,20 +1476,21 @@@ skip_countries
        acm->nb_index = 0;
        acm->nb_size = 0;
  
 -      dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor);
 -
        acm->line.dwDTERate = cpu_to_le32(9600);
        acm->line.bDataBits = 8;
        acm_set_line(acm, &acm->line);
  
 -      usb_driver_claim_interface(&acm_driver, data_interface, acm);
 -      usb_set_intfdata(data_interface, acm);
 +      if (!acm->combined_interfaces) {
 +              rv = usb_driver_claim_interface(&acm_driver, data_interface, acm);
 +              if (rv)
 +                      goto err_remove_files;
 +      }
  
        tty_dev = tty_port_register_device(&acm->port, acm_tty_driver, minor,
                        &control_interface->dev);
        if (IS_ERR(tty_dev)) {
                rv = PTR_ERR(tty_dev);
 -              goto alloc_fail6;
 +              goto err_release_data_interface;
        }
  
        if (quirks & CLEAR_HALT_CONDITIONS) {
                usb_clear_halt(usb_dev, acm->out);
        }
  
 +      dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor);
 +
        return 0;
 -alloc_fail6:
 +
 +err_release_data_interface:
 +      if (!acm->combined_interfaces) {
 +              /* Clear driver data so that disconnect() returns early. */
 +              usb_set_intfdata(data_interface, NULL);
 +              usb_driver_release_interface(&acm_driver, data_interface);
 +      }
 +err_remove_files:
        if (acm->country_codes) {
                device_remove_file(&acm->control->dev,
                                &dev_attr_wCountryCodes);
                device_remove_file(&acm->control->dev,
                                &dev_attr_iCountryCodeRelDate);
 -              kfree(acm->country_codes);
        }
        device_remove_file(&acm->control->dev, &dev_attr_bmCapabilities);
 -alloc_fail5:
 -      usb_set_intfdata(intf, NULL);
 +err_free_write_urbs:
        for (i = 0; i < ACM_NW; i++)
                usb_free_urb(acm->wb[i].urb);
 -alloc_fail4:
 +err_free_read_urbs:
        for (i = 0; i < num_rx_buf; i++)
                usb_free_urb(acm->read_urbs[i]);
        acm_read_buffers_free(acm);
        usb_free_urb(acm->ctrlurb);
 -alloc_fail3:
 +err_free_write_buffers:
        acm_write_buffers_free(acm);
 -alloc_fail2:
 +err_free_ctrl_buffer:
        usb_free_coherent(usb_dev, ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
 -alloc_fail1:
 +err_put_port:
        tty_port_put(&acm->port);
 -alloc_fail:
 +
        return rv;
  }
  
@@@ -1544,14 -1540,8 +1544,14 @@@ static void acm_disconnect(struct usb_i
        if (!acm)
                return;
  
 -      mutex_lock(&acm->mutex);
        acm->disconnected = true;
 +      /*
 +       * there is a circular dependency. acm_softint() can resubmit
 +       * the URBs in error handling so we need to block any
 +       * submission right away
 +       */
 +      acm_poison_urbs(acm);
 +      mutex_lock(&acm->mutex);
        if (acm->country_codes) {
                device_remove_file(&acm->control->dev,
                                &dev_attr_wCountryCodes);
                tty_kref_put(tty);
        }
  
 -      acm_kill_urbs(acm);
        cancel_delayed_work_sync(&acm->dwork);
  
        tty_unregister_device(acm_tty_driver, acm->minor);
@@@ -1611,7 -1602,7 +1611,7 @@@ static int acm_suspend(struct usb_inter
        if (cnt)
                return 0;
  
 -      acm_kill_urbs(acm);
 +      acm_poison_urbs(acm);
        cancel_delayed_work_sync(&acm->dwork);
        acm->urbs_in_error_delay = 0;
  
@@@ -1629,8 -1620,6 +1629,8 @@@ static int acm_resume(struct usb_interf
        if (--acm->susp_count)
                goto out;
  
 +      acm_unpoison_urbs(acm);
 +
        if (tty_port_initialized(&acm->port)) {
                rv = usb_submit_urb(acm->ctrlurb, GFP_ATOMIC);
  
@@@ -1913,9 -1902,17 +1913,17 @@@ static const struct usb_device_id acm_i
  #endif
  
  #if IS_ENABLED(CONFIG_USB_SERIAL_XR)
-       { USB_DEVICE(0x04e2, 0x1410),   /* Ignore XR21V141X USB to Serial converter */
-       .driver_info = IGNORE_DEVICE,
-       },
+       { USB_DEVICE(0x04e2, 0x1400), .driver_info = IGNORE_DEVICE },
+       { USB_DEVICE(0x04e2, 0x1401), .driver_info = IGNORE_DEVICE },
+       { USB_DEVICE(0x04e2, 0x1402), .driver_info = IGNORE_DEVICE },
+       { USB_DEVICE(0x04e2, 0x1403), .driver_info = IGNORE_DEVICE },
+       { USB_DEVICE(0x04e2, 0x1410), .driver_info = IGNORE_DEVICE },
+       { USB_DEVICE(0x04e2, 0x1411), .driver_info = IGNORE_DEVICE },
+       { USB_DEVICE(0x04e2, 0x1412), .driver_info = IGNORE_DEVICE },
+       { USB_DEVICE(0x04e2, 0x1414), .driver_info = IGNORE_DEVICE },
+       { USB_DEVICE(0x04e2, 0x1420), .driver_info = IGNORE_DEVICE },
+       { USB_DEVICE(0x04e2, 0x1422), .driver_info = IGNORE_DEVICE },
+       { USB_DEVICE(0x04e2, 0x1424), .driver_info = IGNORE_DEVICE },
  #endif
  
        /*Samsung phone in firmware update mode */