disconnect/reconnectery

Change-Id: I009f13ccdaf364e08b3a08ad3c37ea6021a8d4ef
diff --git a/zircon/system/dev/usb/dwc2/dwc2.cc b/zircon/system/dev/usb/dwc2/dwc2.cc
index e1969bd..07f458b 100644
--- a/zircon/system/dev/usb/dwc2/dwc2.cc
+++ b/zircon/system/dev/usb/dwc2/dwc2.cc
@@ -79,26 +79,17 @@
         .set_devaddr(0)
         .WriteTo(mmio);
 
-    if (dci_intf_) {
-        dci_intf_->SetConnected(true);
-    }
-    if (usb_phy_) {
-        usb_phy_->ConnectStatusChanged(false);
-    }
+    SetConnected(false);
 }
 
 // Handler for usbsuspend interrupt.
 void Dwc2::HandleSuspend() {
-    if (dci_intf_) {
-        dci_intf_->SetConnected(false);
-    }
+    SetConnected(false);
 }
 
 // Handler for enumdone interrupt.
 void Dwc2::HandleEnumDone() {
-    if (usb_phy_) {
-        usb_phy_->ConnectStatusChanged(true);
-    }
+    SetConnected(true);
 
     auto* mmio = get_mmio();
 
@@ -747,16 +738,7 @@
 
     zx::nanosleep(zx::deadline_after(zx::msec(10)));
 
-    // Configure controller for device mode, enable DMA
-    GUSBCFG::Get()
-        .ReadFrom(mmio)
-        .set_force_dev_mode(1)
-        .set_srpcap(0)
-        .set_hnpcap(0)
-        .set_ulpi_utmi_sel(1)
-        .set_phyif(0)
-        .set_ddrsel(0)
-        .WriteTo(mmio);
+    // Enable DMA
     GAHBCFG::Get()
         .FromValue(0)
         .set_dmaenable(1)
@@ -863,7 +845,7 @@
         .set_inepintr(1)
         .set_outepintr(1)
         .set_usbsuspend(1)
-        .set_modemismatch(1)
+        .set_erlysuspend(1)
         .WriteTo(mmio);
 
     // Enable global interrupts
@@ -875,6 +857,55 @@
     return ZX_OK;
 }
 
+void Dwc2::SetConnected(bool connected) {
+    if (connected == connected_) {
+        return;
+    }
+
+    if (dci_intf_) {
+        dci_intf_->SetConnected(connected);
+    }
+    if (usb_phy_) {
+        usb_phy_->ConnectStatusChanged(connected);
+    }
+
+
+    if (!connected) {
+        // Complete any pending requests
+        RequestQueue complete_reqs;
+
+        for (uint8_t i = 0; i < fbl::count_of(endpoints_); i++) {
+            auto* ep = &endpoints_[i];
+    
+            fbl::AutoLock lock(&ep->lock);
+            if (ep->current_req) {
+                complete_reqs.push(Request(ep->current_req, sizeof(usb_request_t)));
+                ep->current_req = nullptr;
+            }
+            for (auto req = ep->queued_reqs.pop(); req; req = ep->queued_reqs.pop()) {
+                complete_reqs.push(std::move(*req));
+            }
+
+// ???
+            if (ep->enabled) {
+                // what else to to here?
+                ep->enabled = false;
+            }
+        }
+
+        // Reset dynamic FIFO values for IN endpoints.
+        next_dfifo_ = 1;
+        dfifo_base_ = metadata_.rx_fifo_size + metadata_.nptx_fifo_size;
+    
+        // Requests must be completed outside of the lock.
+        for (auto req = complete_reqs.pop(); req; req = complete_reqs.pop()) {
+            req->Complete(ZX_ERR_IO_NOT_PRESENT, 0);
+        }
+    }
+
+    connected_ = connected;
+}
+
 zx_status_t Dwc2::Create(void* ctx, zx_device_t* parent) {
     auto dev = std::make_unique<Dwc2>(parent);
     auto status = dev->Init();
@@ -1004,7 +1035,7 @@
             if (gintsts.usbreset()) {
                 HandleReset();
             }
-            if (gintsts.usbsuspend()) {
+            if (gintsts.usbsuspend() || gintsts.erlysuspend()) {
                 HandleSuspend();
             }
             if (gintsts.enumdone()) {
diff --git a/zircon/system/dev/usb/dwc2/dwc2.h b/zircon/system/dev/usb/dwc2/dwc2.h
index 3ac84e4..efd78c1 100644
--- a/zircon/system/dev/usb/dwc2/dwc2.h
+++ b/zircon/system/dev/usb/dwc2/dwc2.h
@@ -94,7 +94,7 @@
     void FlushTxFifo(uint32_t fifo_num);
     void FlushRxFifo();
     zx_status_t InitController();
-    zx_status_t Start();
+    void SetConnected(bool connected);
     void StartEp0();
     void StartEndpoints();
     void HandleEp0Setup();
@@ -146,6 +146,7 @@
     thrd_t irq_thread_;
 
     dwc2_metadata_t metadata_;
+    bool connected_ = false;
     bool configured_ = false;
 
     // FIFO number for next IN endpoint