Merge 3.7-rc3 into usb-next.
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 29 Oct 2012 16:04:39 +0000 (09:04 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 29 Oct 2012 16:04:39 +0000 (09:04 -0700)
This pulls in all of the USB changes in 3.7-rc3 into usb-next and
resolves the merge issue with:
drivers/usb/misc/ezusb.c

Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1  2 
drivers/usb/core/hub.c
drivers/usb/misc/ezusb.c

diff --combined drivers/usb/core/hub.c
index 43ce1467f8c03fc8d7f6d8c1eaf6240f68985be2,1af04bdeaf0c1884487ed830bcee7dd32ee720b6..5b131b6477db060d37fb9c347736b1aad5a3f415
@@@ -39,9 -39,6 +39,9 @@@
  #endif
  #endif
  
 +#define USB_VENDOR_GENESYS_LOGIC              0x05e3
 +#define HUB_QUIRK_CHECK_PORT_AUTOSUSPEND      0x01
 +
  struct usb_port {
        struct usb_device *child;
        struct device dev;
@@@ -89,8 -86,6 +89,8 @@@ struct usb_hub 
        unsigned                quiescing:1;
        unsigned                disconnected:1;
  
 +      unsigned                quirk_check_port_auto_suspend:1;
 +
        unsigned                has_indicators:1;
        u8                      indicator[USB_MAXCHILDREN];
        struct delayed_work     leds;
@@@ -744,13 -739,16 +744,16 @@@ static void hub_tt_work(struct work_str
        int                     limit = 100;
  
        spin_lock_irqsave (&hub->tt.lock, flags);
-       while (--limit && !list_empty (&hub->tt.clear_list)) {
+       while (!list_empty(&hub->tt.clear_list)) {
                struct list_head        *next;
                struct usb_tt_clear     *clear;
                struct usb_device       *hdev = hub->hdev;
                const struct hc_driver  *drv;
                int                     status;
  
+               if (!hub->quiescing && --limit < 0)
+                       break;
                next = hub->tt.clear_list.next;
                clear = list_entry (next, struct usb_tt_clear, clear_list);
                list_del (&clear->clear_list);
@@@ -1215,7 -1213,7 +1218,7 @@@ static void hub_quiesce(struct usb_hub 
        if (hub->has_indicators)
                cancel_delayed_work_sync(&hub->leds);
        if (hub->tt.hub)
-               cancel_work_sync(&hub->tt.clear_work);
+               flush_work(&hub->tt.clear_work);
  }
  
  /* caller has locked the hub device */
@@@ -1614,41 -1612,6 +1617,41 @@@ static int hub_probe(struct usb_interfa
        desc = intf->cur_altsetting;
        hdev = interface_to_usbdev(intf);
  
 +      /*
 +       * Set default autosuspend delay as 0 to speedup bus suspend,
 +       * based on the below considerations:
 +       *
 +       * - Unlike other drivers, the hub driver does not rely on the
 +       *   autosuspend delay to provide enough time to handle a wakeup
 +       *   event, and the submitted status URB is just to check future
 +       *   change on hub downstream ports, so it is safe to do it.
 +       *
 +       * - The patch might cause one or more auto supend/resume for
 +       *   below very rare devices when they are plugged into hub
 +       *   first time:
 +       *
 +       *      devices having trouble initializing, and disconnect
 +       *      themselves from the bus and then reconnect a second
 +       *      or so later
 +       *
 +       *      devices just for downloading firmware, and disconnects
 +       *      themselves after completing it
 +       *
 +       *   For these quite rare devices, their drivers may change the
 +       *   autosuspend delay of their parent hub in the probe() to one
 +       *   appropriate value to avoid the subtle problem if someone
 +       *   does care it.
 +       *
 +       * - The patch may cause one or more auto suspend/resume on
 +       *   hub during running 'lsusb', but it is probably too
 +       *   infrequent to worry about.
 +       *
 +       * - Change autosuspend delay of hub can avoid unnecessary auto
 +       *   suspend timer for hub, also may decrease power consumption
 +       *   of USB bus.
 +       */
 +      pm_runtime_set_autosuspend_delay(&hdev->dev, 0);
 +
        /* Hubs have proper suspend/resume support. */
        usb_enable_autosuspend(hdev);
  
@@@ -1707,9 -1670,6 +1710,9 @@@ descriptor_error
        if (hdev->speed == USB_SPEED_HIGH)
                highspeed_hubs++;
  
 +      if (id->driver_info & HUB_QUIRK_CHECK_PORT_AUTOSUSPEND)
 +              hub->quirk_check_port_auto_suspend = 1;
 +
        if (hub_configure(hub, endpoint) >= 0)
                return 0;
  
@@@ -2919,7 -2879,6 +2922,7 @@@ int usb_port_suspend(struct usb_device 
                                (PMSG_IS_AUTO(msg) ? "auto-" : ""),
                                udev->do_remote_wakeup);
                usb_set_device_state(udev, USB_STATE_SUSPENDED);
 +              udev->port_is_suspended = 1;
                msleep(10);
        }
        usb_mark_last_busy(hub->hdev);
@@@ -3084,7 -3043,6 +3087,7 @@@ int usb_port_resume(struct usb_device *
  
   SuspendCleared:
        if (status == 0) {
 +              udev->port_is_suspended = 0;
                if (hub_is_superspeed(hub->hdev)) {
                        if (portchange & USB_PORT_STAT_C_LINK_STATE)
                                clear_port_feature(hub->hdev, port1,
@@@ -3168,21 -3126,6 +3171,21 @@@ int usb_port_resume(struct usb_device *
  
  #endif
  
 +static int check_ports_changed(struct usb_hub *hub)
 +{
 +      int port1;
 +
 +      for (port1 = 1; port1 <= hub->hdev->maxchild; ++port1) {
 +              u16 portstatus, portchange;
 +              int status;
 +
 +              status = hub_port_status(hub, port1, &portstatus, &portchange);
 +              if (!status && portchange)
 +                      return 1;
 +      }
 +      return 0;
 +}
 +
  static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
  {
        struct usb_hub          *hub = usb_get_intfdata (intf);
                                return -EBUSY;
                }
        }
 +
 +      if (hdev->do_remote_wakeup && hub->quirk_check_port_auto_suspend) {
 +              /* check if there are changes pending on hub ports */
 +              if (check_ports_changed(hub)) {
 +                      if (PMSG_IS_AUTO(msg))
 +                              return -EBUSY;
 +                      pm_wakeup_event(&hdev->dev, 2000);
 +              }
 +      }
 +
        if (hub_is_superspeed(hdev) && hdev->do_remote_wakeup) {
                /* Enable hub to send remote wakeup for all ports. */
                for (port1 = 1; port1 <= hdev->maxchild; port1++) {
@@@ -4715,11 -4648,6 +4718,11 @@@ static int hub_thread(void *__unused
  }
  
  static const struct usb_device_id hub_id_table[] = {
 +    { .match_flags = USB_DEVICE_ID_MATCH_VENDOR
 +                 | USB_DEVICE_ID_MATCH_INT_CLASS,
 +      .idVendor = USB_VENDOR_GENESYS_LOGIC,
 +      .bInterfaceClass = USB_CLASS_HUB,
 +      .driver_info = HUB_QUIRK_CHECK_PORT_AUTOSUSPEND},
      { .match_flags = USB_DEVICE_ID_MATCH_DEV_CLASS,
        .bDeviceClass = USB_CLASS_HUB},
      { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS,
diff --combined drivers/usb/misc/ezusb.c
index 0a48de91df3a5ca5d96ee55dd537df211554cd3e,6589268a651517da44f99cd7391e2ca35f84f12a..e712afed947c0743dffa1a099ca91832288eeb89
@@@ -15,7 -15,6 +15,7 @@@
  #include <linux/usb.h>
  #include <linux/firmware.h>
  #include <linux/ihex.h>
 +#include <linux/usb/ezusb.h>
  
  struct ezusb_fx_type {
        /* EZ-USB Control and Status Register.  Bit 0 controls 8051 reset */
        unsigned short max_internal_adress;
  };
  
 -struct ezusb_fx_type ezusb_fx1 = {
 +static struct ezusb_fx_type ezusb_fx1 = {
        .cpucs_reg = 0x7F92,
        .max_internal_adress = 0x1B3F,
  };
  
 -struct ezusb_fx_type ezusb_fx2 = {
 -      .cpucs_reg = 0xE600,
 -      .max_internal_adress = 0x3FFF,
 -};
 -
  /* Commands for writing to memory */
  #define WRITE_INT_RAM 0xA0
  #define WRITE_EXT_RAM 0xA3
  
 -int ezusb_writememory(struct usb_device *dev, int address,
 +static int ezusb_writememory(struct usb_device *dev, int address,
                                unsigned char *data, int length, __u8 request)
  {
        int result;
        kfree(transfer_buffer);
        return result;
  }
 -EXPORT_SYMBOL_GPL(ezusb_writememory);
  
 -int ezusb_set_reset(struct usb_device *dev, unsigned short cpucs_reg,
 -                       unsigned char reset_bit)
 +static int ezusb_set_reset(struct usb_device *dev, unsigned short cpucs_reg,
 +                         unsigned char reset_bit)
  {
        int response = ezusb_writememory(dev, cpucs_reg, &reset_bit, 1, WRITE_INT_RAM);
        if (response < 0)
@@@ -71,6 -76,12 +71,6 @@@ int ezusb_fx1_set_reset(struct usb_devi
  }
  EXPORT_SYMBOL_GPL(ezusb_fx1_set_reset);
  
 -int ezusb_fx2_set_reset(struct usb_device *dev, unsigned char reset_bit)
 -{
 -      return ezusb_set_reset(dev, ezusb_fx2.cpucs_reg, reset_bit);
 -}
 -EXPORT_SYMBOL_GPL(ezusb_fx2_set_reset);
 -
  static int ezusb_ihex_firmware_download(struct usb_device *dev,
                                        struct ezusb_fx_type fx,
                                        const char *firmware_path)
@@@ -140,26 -151,11 +140,28 @@@ int ezusb_fx1_ihex_firmware_download(st
  }
  EXPORT_SYMBOL_GPL(ezusb_fx1_ihex_firmware_download);
  
 +#if 0
 +/*
 + * Once someone one needs these fx2 functions, uncomment them
 + * and add them to ezusb.h and all should be good.
 + */
 +static struct ezusb_fx_type ezusb_fx2 = {
 +      .cpucs_reg = 0xE600,
 +      .max_internal_adress = 0x3FFF,
 +};
 +
 +int ezusb_fx2_set_reset(struct usb_device *dev, unsigned char reset_bit)
 +{
 +      return ezusb_set_reset(dev, ezusb_fx2.cpucs_reg, reset_bit);
 +}
 +EXPORT_SYMBOL_GPL(ezusb_fx2_set_reset);
 +
  int ezusb_fx2_ihex_firmware_download(struct usb_device *dev,
                                     const char *firmware_path)
  {
        return ezusb_ihex_firmware_download(dev, ezusb_fx2, firmware_path);
  }
  EXPORT_SYMBOL_GPL(ezusb_fx2_ihex_firmware_download);
 +#endif
+ MODULE_LICENSE("GPL");