I think it works now!

Change-Id: I3d07c907fb45fd251430a3fd4e9812ec0528cb3a
diff --git a/system/dev/usb/usb-virtual-bus/usb-virtual-bus.cpp b/system/dev/usb/usb-virtual-bus/usb-virtual-bus.cpp
index 9c4ffb6..cdb9433 100644
--- a/system/dev/usb/usb-virtual-bus/usb-virtual-bus.cpp
+++ b/system/dev/usb/usb-virtual-bus/usb-virtual-bus.cpp
@@ -128,11 +128,9 @@
         sync_completion_wait(&completion_, ZX_TIME_INFINITE);
         sync_completion_reset(&completion_);
 
-printf("thread acquire\n");
         lock_.Acquire();
 
         if (unbinding_) {
-printf("unbinding_\n");
             for (unsigned i = 0; i < USB_MAX_EPS; i++) {
                 usb_virtual_ep_t* ep = &eps_[i];
 
@@ -146,12 +144,12 @@
                 }
             }
 
-printf("thread release 1\n");
             lock_.Release();
 
+            // Complete requests outside of the lock to avoid deadlock.
             while ((req_int = list_remove_head_type(&completed, virt_usb_req_internal_t, node))
                     != nullptr) {
-                usb_request_t* req = INTERNAL_TO_USB_REQ(req_int);               
+                usb_request_t* req = INTERNAL_TO_USB_REQ(req_int);
                 usb_request_complete(req, ZX_ERR_IO_NOT_PRESENT, 0, &req_int->complete_cb);
             }
             
@@ -162,6 +160,7 @@
         while ((req_int = list_remove_head_type(&eps_[0].host_reqs, virt_usb_req_internal_t, node))
                 != nullptr) {
             lock_.Release();
+            // Handle control requests outside of the lock to avoid deadlock.
             HandleControl(INTERNAL_TO_USB_REQ(req_int));
             lock_.Acquire();
         }
@@ -214,12 +213,12 @@
             }
         }
 
-printf("thread release 2\n");
         lock_.Release();
 
+        // Complete requests outside of the lock to avoid deadlock.
         while ((req_int = list_remove_head_type(&completed, virt_usb_req_internal_t, node))
                 != nullptr) {
-            usb_request_t* req = INTERNAL_TO_USB_REQ(req_int);               
+            usb_request_t* req = INTERNAL_TO_USB_REQ(req_int);
             usb_request_complete(req, req->response.status, req->response.actual,
                                  &req_int->complete_cb);
         }
@@ -278,8 +277,31 @@
             dci_intf_->SetConnected(false);
         }
 
-        // Signal our thread to complete pending transactions.
-        sync_completion_signal(&completion_);
+        lock_.Acquire();
+
+        list_node_t completed = LIST_INITIAL_VALUE(completed);
+        virt_usb_req_internal_t* req_int;
+
+        for (unsigned i = 0; i < USB_MAX_EPS; i++) {
+            usb_virtual_ep_t* ep = &eps_[i];
+
+            while ((req_int = list_remove_head_type(&ep->host_reqs, virt_usb_req_internal_t, node))
+                    != nullptr) {
+                list_add_tail(&completed, &req_int->node);
+            }
+            while ((req_int = list_remove_head_type(&ep->device_reqs, virt_usb_req_internal_t, node))
+                    != nullptr) {
+                list_add_tail(&completed, &req_int->node);
+            }
+        }
+
+       lock_.Release();
+
+        while ((req_int = list_remove_head_type(&completed, virt_usb_req_internal_t, node))
+                != nullptr) {
+            usb_request_t* req = INTERNAL_TO_USB_REQ(req_int);
+            usb_request_complete(req, ZX_ERR_IO_NOT_PRESENT, 0, &req_int->complete_cb);
+        }
     }
 }
 
@@ -336,18 +358,14 @@
     auto* req_int = USB_REQ_TO_INTERNAL(req);
     req_int->complete_cb = *complete_cb;
 
-printf("UsbDciRequestQueue start\n");
     uint8_t index = ep_address_to_index(req->header.ep_address);
     if (index == 0 || index >= USB_MAX_EPS) {
         printf("%s: bad endpoint %u\n", __func__, req->header.ep_address);
         usb_request_complete(req, ZX_ERR_INVALID_ARGS, 0, complete_cb);
         return;
     }
-printf("UsbDciRequestQueue 2\n");
     lock_.Acquire();
-printf("UsbDciRequestQueue 3\n");
     if (!connected_) {
-printf("UsbDciRequestQueue ZX_ERR_IO_NOT_PRESENT\n");
         lock_.Release();
         usb_request_complete(req, ZX_ERR_IO_NOT_PRESENT, 0, complete_cb);
         return;
@@ -356,7 +374,6 @@
     list_add_tail(&eps_[index].device_reqs, &req_int->node);
     lock_.Release();
 
-printf("UsbDciRequestQueue done\n");
     sync_completion_signal(&completion_);
 }
 
@@ -394,7 +411,6 @@
                                        const usb_request_complete_t* complete_cb) {
     auto* req_int = USB_REQ_TO_INTERNAL(req);
     req_int->complete_cb = *complete_cb;
-printf("UsbHciRequestQueue start\n");
 
     uint8_t index = ep_address_to_index(req->header.ep_address);
     if (index >= USB_MAX_EPS) {
@@ -405,7 +421,6 @@
 
     lock_.Acquire();
     if (!connected_) {
-printf("UsbHciRequestQueue ZX_ERR_IO_NOT_PRESENT\n");
         lock_.Release();
         usb_request_complete(req, ZX_ERR_IO_NOT_PRESENT, 0, complete_cb);
         return;
@@ -415,14 +430,12 @@
 
     if (ep->stalled) {
         lock_.Release();
-printf("UsbHciRequestQueue ZX_ERR_IO_REFUSED\n");
         usb_request_complete(req, ZX_ERR_IO_REFUSED, 0, complete_cb);
         return;
     }
     list_add_tail(&ep->host_reqs, &req_int->node);
     lock_.Release();
 
-printf("UsbHciRequestQueue done\n");
     sync_completion_signal(&completion_);
 }
 
diff --git a/system/dev/usb/usb-virtual-bus/usb-virtual-bus.h b/system/dev/usb/usb-virtual-bus/usb-virtual-bus.h
index 4a0ba38..e7101fb 100644
--- a/system/dev/usb/usb-virtual-bus/usb-virtual-bus.h
+++ b/system/dev/usb/usb-virtual-bus/usb-virtual-bus.h
@@ -21,15 +21,6 @@
 
 namespace usb_virtual_bus {
 
-struct usb_virtual_ep_t {
-    list_node_t host_reqs;
-    list_node_t device_reqs;
-    // offset into current host req, for dealing with host reqs that are bigger than
-    // their matching device req
-    zx_off_t req_offset;
-    bool stalled;
-};
-
 class UsbVirtualBus;
 class UsbVirtualDevice;
 class UsbVirtualHost;
@@ -82,6 +73,15 @@
 private:
     DISALLOW_COPY_ASSIGN_AND_MOVE(UsbVirtualBus);
 
+    struct usb_virtual_ep_t {
+        list_node_t host_reqs __TA_GUARDED(lock_);
+        list_node_t device_reqs __TA_GUARDED(lock_);
+        // offset into current host req, for dealing with host reqs that are bigger than
+        // their matching device req
+        zx_off_t req_offset;
+        bool stalled;
+    };
+
     zx_status_t Init();
     zx_status_t CreateDevice();
     zx_status_t CreateHost();