add toggle for disabling newly added USB devices
[GitHub/LineageOS/android_kernel_motorola_exynos9610.git] / drivers / usb / core / hub.c
index 638dc6f66d70d5d7840744b28a10140a8af3f75f..1f3aa1b96e3745a43d0a293437530c2cb59c267e 100644 (file)
@@ -38,6 +38,8 @@
 #define USB_VENDOR_GENESYS_LOGIC               0x05e3
 #define HUB_QUIRK_CHECK_PORT_AUTOSUSPEND       0x01
 
+extern int deny_new_usb;
+
 /* Protect struct usb_device->state and ->children members
  * Note: Both are also protected by ->dev.sem, except that ->state can
  * change to USB_STATE_NOTATTACHED even when the semaphore isn't held. */
@@ -1110,6 +1112,16 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
                                                   USB_PORT_FEAT_ENABLE);
                }
 
+               /*
+                * Add debounce if USB3 link is in polling/link training state.
+                * Link will automatically transition to Enabled state after
+                * link training completes.
+                */
+               if (hub_is_superspeed(hdev) &&
+                   ((portstatus & USB_PORT_STAT_LINK_STATE) ==
+                                               USB_SS_PORT_LS_POLLING))
+                       need_debounce_delay = true;
+
                /* Clear status-change flags; we'll debounce later */
                if (portchange & USB_PORT_STAT_C_CONNECTION) {
                        need_debounce_delay = true;
@@ -1694,6 +1706,7 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
        struct usb_host_interface *desc;
        struct usb_device *hdev;
        struct usb_hub *hub;
+       struct usb_hcd *hcd;
 
        desc = intf->cur_altsetting;
        hdev = interface_to_usbdev(intf);
@@ -1735,7 +1748,13 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
         *   usbcore.autosuspend = -1 then keep autosuspend disabled.
         */
 #ifdef CONFIG_PM
-       if (hdev->dev.power.autosuspend_delay >= 0)
+       /*
+        * bus suspend is executed before USB3.0 hub and devices are detected,
+        * which causes USB3.0 hub and devices aren't recognized when l2 sleep is enabled.
+        * Restoring suspend delay will resolve USB3.0 hub detect issue.
+        */
+       hcd = bus_to_hcd(hdev->bus);
+       if ((hdev->dev.power.autosuspend_delay >= 0) && !hcd->driver->usb_l2_check(hcd))
                pm_runtime_set_autosuspend_delay(&hdev->dev, 0);
 #endif
 
@@ -2231,7 +2250,7 @@ static int usb_enumerate_device_otg(struct usb_device *udev)
                /* descriptor may appear anywhere in config */
                err = __usb_get_extra_descriptor(udev->rawdescriptors[0],
                                le16_to_cpu(udev->config[0].desc.wTotalLength),
-                               USB_DT_OTG, (void **) &desc);
+                               USB_DT_OTG, (void **) &desc, sizeof(*desc));
                if (err || !(desc->bmAttributes & USB_OTG_HNP))
                        return 0;
 
@@ -4818,6 +4837,12 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus,
                        goto done;
                return;
        }
+
+       if (deny_new_usb) {
+               dev_err(&port_dev->dev, "denied insert of USB device on port %d\n", port1);
+               goto done;
+       }
+
        if (hub_is_superspeed(hub->hdev))
                unit_load = 150;
        else
@@ -5153,6 +5178,7 @@ static void hub_event(struct work_struct *work)
        struct usb_interface *intf;
        struct usb_hub *hub;
        struct device *hub_dev;
+       struct usb_hcd *hcd;
        u16 hubstatus;
        u16 hubchange;
        int i, ret;
@@ -5160,6 +5186,7 @@ static void hub_event(struct work_struct *work)
        hub = container_of(work, struct usb_hub, events);
        hdev = hub->hdev;
        hub_dev = hub->intfdev;
+       hcd = bus_to_hcd(hdev->bus);
        intf = to_usb_interface(hub_dev);
 
        dev_dbg(hub_dev, "state %d ports %d chg %04x evt %04x\n",
@@ -5171,6 +5198,7 @@ static void hub_event(struct work_struct *work)
        /* Lock the device, then check to see if we were
         * disconnected while waiting for the lock to succeed. */
        usb_lock_device(hdev);
+       hcd->is_in_hub_event = true;
        if (unlikely(hub->disconnected))
                goto out_hdev_lock;
 
@@ -5263,6 +5291,7 @@ out_autopm:
        /* Balance the usb_autopm_get_interface() above */
        usb_autopm_put_interface_no_suspend(intf);
 out_hdev_lock:
+       hcd->is_in_hub_event = false;
        usb_unlock_device(hdev);
 
        /* Balance the stuff in kick_hub_wq() and allow autosuspend */