[usb] More prep work for soft transition of USB protocol

Copy system/dev/lib/usb to system/dev/lib/usb-old
and use usb-old for all the USB drivers in zircon.
After garnet switches to use usb-old, we can switch system/dev/lib/usb
to use banjo based USB protocol.

TEST: builds
Change-Id: I631ea8be4880576eaf2e574fbf380f7f1e2f0c07
diff --git a/system/dev/audio/usb-audio/rules.mk b/system/dev/audio/usb-audio/rules.mk
index 190ea1a..2818456 100644
--- a/system/dev/audio/usb-audio/rules.mk
+++ b/system/dev/audio/usb-audio/rules.mk
@@ -30,7 +30,7 @@
 MODULE_STATIC_LIBS := \
     system/ulib/audio-driver-proto \
     system/ulib/audio-proto-utils \
-    system/dev/lib/usb \
+    system/dev/lib/usb-old \
     system/ulib/digest \
     system/ulib/dispatcher-pool \
     system/ulib/ddk \
diff --git a/system/dev/block/ums-function/rules.mk b/system/dev/block/ums-function/rules.mk
index 7b43969..3e331fa 100644
--- a/system/dev/block/ums-function/rules.mk
+++ b/system/dev/block/ums-function/rules.mk
@@ -11,7 +11,7 @@
 MODULE_SRCS := \
     $(LOCAL_DIR)/ums-function.c \
 
-MODULE_STATIC_LIBS := system/ulib/ddk system/ulib/sync system/dev/lib/usb
+MODULE_STATIC_LIBS := system/ulib/ddk system/ulib/sync system/dev/lib/usb-old
 
 MODULE_LIBS := system/ulib/driver system/ulib/zircon system/ulib/c
 
diff --git a/system/dev/block/usb-mass-storage/rules.mk b/system/dev/block/usb-mass-storage/rules.mk
index e2b960c..87306a4 100644
--- a/system/dev/block/usb-mass-storage/rules.mk
+++ b/system/dev/block/usb-mass-storage/rules.mk
@@ -12,7 +12,7 @@
     $(LOCAL_DIR)/block.c \
     $(LOCAL_DIR)/usb-mass-storage.c \
 
-MODULE_STATIC_LIBS := system/ulib/ddk system/dev/lib/usb system/ulib/sync
+MODULE_STATIC_LIBS := system/ulib/ddk system/dev/lib/usb-old system/ulib/sync
 
 MODULE_LIBS := system/ulib/driver system/ulib/zircon system/ulib/c
 
diff --git a/system/dev/bluetooth/bt-transport-usb/rules.mk b/system/dev/bluetooth/bt-transport-usb/rules.mk
index 91ff239..0b23a94 100644
--- a/system/dev/bluetooth/bt-transport-usb/rules.mk
+++ b/system/dev/bluetooth/bt-transport-usb/rules.mk
@@ -10,7 +10,7 @@
 
 MODULE_SRCS := $(LOCAL_DIR)/bt-transport-usb.c
 
-MODULE_STATIC_LIBS := system/ulib/ddk system/dev/lib/usb system/ulib/sync
+MODULE_STATIC_LIBS := system/ulib/ddk system/dev/lib/usb-old system/ulib/sync
 
 MODULE_LIBS := system/ulib/driver system/ulib/zircon system/ulib/c
 
diff --git a/system/dev/ethernet/asix-88179/rules.mk b/system/dev/ethernet/asix-88179/rules.mk
index 637ceed..11b0e68 100644
--- a/system/dev/ethernet/asix-88179/rules.mk
+++ b/system/dev/ethernet/asix-88179/rules.mk
@@ -6,7 +6,7 @@
 
 MODULE_TYPE := driver
 
-MODULE_STATIC_LIBS := system/ulib/ddk system/dev/lib/usb \
+MODULE_STATIC_LIBS := system/ulib/ddk system/dev/lib/usb-old \
                       system/ulib/pretty system/ulib/sync third_party/ulib/cksum
 
 MODULE_LIBS := system/ulib/driver system/ulib/zircon system/ulib/c
diff --git a/system/dev/ethernet/asix-88772b/rules.mk b/system/dev/ethernet/asix-88772b/rules.mk
index c26145c..73eb2f9 100644
--- a/system/dev/ethernet/asix-88772b/rules.mk
+++ b/system/dev/ethernet/asix-88772b/rules.mk
@@ -6,7 +6,7 @@
 
 MODULE_TYPE := driver
 
-MODULE_STATIC_LIBS := system/ulib/ddk system/dev/lib/usb system/ulib/sync
+MODULE_STATIC_LIBS := system/ulib/ddk system/dev/lib/usb-old system/ulib/sync
 
 MODULE_LIBS := system/ulib/driver system/ulib/zircon system/ulib/c
 
diff --git a/system/dev/ethernet/rndis/rules.mk b/system/dev/ethernet/rndis/rules.mk
index 138f791..8fe9f00 100644
--- a/system/dev/ethernet/rndis/rules.mk
+++ b/system/dev/ethernet/rndis/rules.mk
@@ -6,7 +6,7 @@
 
 MODULE_TYPE := driver
 
-MODULE_STATIC_LIBS := system/ulib/ddk system/dev/lib/usb
+MODULE_STATIC_LIBS := system/ulib/ddk system/dev/lib/usb-old
 
 MODULE_LIBS := system/ulib/driver system/ulib/zircon system/ulib/c
 
diff --git a/system/dev/ethernet/usb-cdc-ecm/rules.mk b/system/dev/ethernet/usb-cdc-ecm/rules.mk
index 0087cc5..9ffcd7f 100644
--- a/system/dev/ethernet/usb-cdc-ecm/rules.mk
+++ b/system/dev/ethernet/usb-cdc-ecm/rules.mk
@@ -6,7 +6,7 @@
 
 MODULE_TYPE := driver
 
-MODULE_STATIC_LIBS := system/ulib/ddk system/dev/lib/usb \
+MODULE_STATIC_LIBS := system/ulib/ddk system/dev/lib/usb-old \
                       system/ulib/pretty system/ulib/sync
 
 MODULE_LIBS := system/ulib/driver system/ulib/zircon system/ulib/c
diff --git a/system/dev/ethernet/usb-cdc-function/rules.mk b/system/dev/ethernet/usb-cdc-function/rules.mk
index fd63491..4509f6f 100644
--- a/system/dev/ethernet/usb-cdc-function/rules.mk
+++ b/system/dev/ethernet/usb-cdc-function/rules.mk
@@ -15,7 +15,7 @@
     system/ulib/ddk \
     system/ulib/fbl \
     system/ulib/sync \
-    system/dev/lib/usb \
+    system/dev/lib/usb-old \
 
 MODULE_LIBS := \
     system/ulib/driver \
diff --git a/system/dev/input/usb-hid/rules.mk b/system/dev/input/usb-hid/rules.mk
index 64bfc9f..fa30c86 100644
--- a/system/dev/input/usb-hid/rules.mk
+++ b/system/dev/input/usb-hid/rules.mk
@@ -10,7 +10,7 @@
 
 MODULE_SRCS := $(LOCAL_DIR)/usb-hid.c
 
-MODULE_STATIC_LIBS := system/ulib/ddk system/dev/lib/usb \
+MODULE_STATIC_LIBS := system/ulib/ddk system/dev/lib/usb-old \
                       system/ulib/pretty system/ulib/sync
 
 MODULE_LIBS := system/ulib/driver system/ulib/zircon system/ulib/c
diff --git a/system/dev/lib/usb-old/include/ddk/usb/usb.h b/system/dev/lib/usb-old/include/ddk/usb/usb.h
new file mode 100644
index 0000000..636a1ce
--- /dev/null
+++ b/system/dev/lib/usb-old/include/ddk/usb/usb.h
@@ -0,0 +1,48 @@
+// Copyright 2016 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#pragma once
+
+#include <ddk/protocol/usb-old.h>
+#include <ddk/protocol/usb/composite.h>
+#include <zircon/compiler.h>
+#include <zircon/hw/usb.h>
+
+__BEGIN_CDECLS;
+
+// helper function for claiming additional interfaces that satisfy the want_interface predicate,
+// want_interface will be passed the supplied arg
+zx_status_t usb_claim_additional_interfaces(usb_composite_protocol_t* comp,
+    bool (*want_interface)(usb_interface_descriptor_t*, void*),
+    void* arg);
+
+// Utilities for iterating through descriptors within a device's USB configuration descriptor
+typedef struct {
+    uint8_t* desc;      // start of configuration descriptor
+    uint8_t* desc_end;  // end of configuration descriptor
+    uint8_t* current;   // current position in configuration descriptor
+} usb_desc_iter_t;
+
+// initializes a usb_desc_iter_t
+zx_status_t usb_desc_iter_init(usb_protocol_t* usb, usb_desc_iter_t* iter);
+
+// releases resources in a usb_desc_iter_t
+void usb_desc_iter_release(usb_desc_iter_t* iter);
+
+// resets iterator to the beginning
+void usb_desc_iter_reset(usb_desc_iter_t* iter);
+
+// returns the next descriptor
+usb_descriptor_header_t* usb_desc_iter_next(usb_desc_iter_t* iter);
+
+// returns the next descriptor without incrementing the iterator
+usb_descriptor_header_t* usb_desc_iter_peek(usb_desc_iter_t* iter);
+
+// returns the next interface descriptor, optionally skipping alternate interfaces
+usb_interface_descriptor_t* usb_desc_iter_next_interface(usb_desc_iter_t* iter, bool skip_alt);
+
+// returns the next endpoint descriptor within the current interface
+usb_endpoint_descriptor_t* usb_desc_iter_next_endpoint(usb_desc_iter_t* iter);
+
+__END_CDECLS;
diff --git a/system/dev/lib/usb-old/include/usb/usb-request.h b/system/dev/lib/usb-old/include/usb/usb-request.h
new file mode 100644
index 0000000..895a0f1
--- /dev/null
+++ b/system/dev/lib/usb-old/include/usb/usb-request.h
@@ -0,0 +1,136 @@
+// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#pragma once
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <ddk/io-buffer.h>
+#include <ddk/phys-iter.h>
+#include <ddk/protocol/usb-old.h>
+#include <zircon/hw/usb.h>
+#include <zircon/listnode.h>
+
+#include <threads.h>
+
+__BEGIN_CDECLS;
+
+// cache maintenance ops
+#define USB_REQUEST_CACHE_INVALIDATE        ZX_VMO_OP_CACHE_INVALIDATE
+#define USB_REQUEST_CACHE_CLEAN             ZX_VMO_OP_CACHE_CLEAN
+#define USB_REQUEST_CACHE_CLEAN_INVALIDATE  ZX_VMO_OP_CACHE_CLEAN_INVALIDATE
+#define USB_REQUEST_CACHE_SYNC              ZX_VMO_OP_CACHE_SYNC
+
+typedef struct {
+    list_node_t free_reqs;
+    mtx_t lock;
+    //offset of the list_node_t* (used for queueing) in usb_request_t.
+    uint64_t node_offset;
+} usb_request_pool_t;
+
+typedef struct {
+    list_node_t node;
+} usb_req_internal_t;
+
+#define USB_REQ_TO_REQ_INTERNAL(req, size) \
+   ((usb_req_internal_t *)((uintptr_t)(req) + (size)))
+#define REQ_INTERNAL_TO_USB_REQ(ctx, size) ((usb_request_t *)((uintptr_t)(ctx) - (size)))
+
+// usb_request_alloc() creates a new usb request with payload space of data_size.
+zx_status_t usb_request_alloc(usb_request_t** out, uint64_t data_size,
+                              uint8_t ep_address, size_t req_size);
+
+// usb_request_alloc_vmo() creates a new usb request with the given VMO.
+zx_status_t usb_request_alloc_vmo(usb_request_t** out, zx_handle_t vmo_handle, uint64_t vmo_offset,
+                                  uint64_t length, uint8_t ep_address, size_t req_size);
+
+// usb_request_init() initializes the statically allocated usb request with the given VMO.
+// This will free any resources allocated by the usb request but not the usb request itself.
+zx_status_t usb_request_init(usb_request_t* req, zx_handle_t vmo_handle,
+                             uint64_t vmo_offset, uint64_t length, uint8_t ep_address);
+
+// usb_request_set_sg_list() copies the scatter gather list to the request.
+// Future transfers using this request will determine where in the VMO to store read / write data
+// using the scatter gather list.
+// This will free any existing scatter gather list stored in the request.
+zx_status_t usb_request_set_sg_list(usb_request_t* req, phys_iter_sg_entry_t* sg_list,
+                                    size_t sg_count);
+
+// usb_request_copy_from() copies data from the usb_request's vm object.
+// Out of range operations are ignored.
+ssize_t usb_request_copy_from(usb_request_t* req, void* data, size_t length, size_t offset);
+
+// usb_request_copy_to() copies data into a usb_request's vm object.
+// Out of range operations are ignored.
+ssize_t usb_request_copy_to(usb_request_t* req, const void* data, size_t length, size_t offset);
+
+// usb_request_mmap() maps the usb request's vm object. The 'data' field is set with the
+// mapped address if this function succeeds.
+zx_status_t usb_request_mmap(usb_request_t* req, void** data);
+
+// usb_request_cacheop() performs a cache maintenance op against the request's internal
+// buffer.
+zx_status_t usb_request_cacheop(usb_request_t* req, uint32_t op, size_t offset, size_t length);
+
+// usb_request_cache_flush() performs a cache flush on a range of memory in the request's buffer
+zx_status_t usb_request_cache_flush(usb_request_t* req, zx_off_t offset, size_t length);
+
+// usb_request_cache_flush_invalidate() performs a cache flush and invalidate on a range of memory
+// in the request's buffer
+zx_status_t usb_request_cache_flush_invalidate(usb_request_t* req, zx_off_t offset, size_t length);
+
+// Looks up the physical pages backing this request's vm object.
+zx_status_t usb_request_physmap(usb_request_t* req, zx_handle_t bti_handle);
+
+// usb_request_release() frees the message data -- should be called only by the entity that allocated it
+void usb_request_release(usb_request_t* req);
+
+// usb_request_complete() must be called by the processor when the request has
+// completed or failed and the request and any virtual or physical memory obtained
+// from it may not be touched again by the processor.
+//
+// The complete_cb() will be called as the last action of this method.
+void usb_request_complete(usb_request_t* req, zx_status_t status, zx_off_t actual,
+                          usb_request_complete_cb complete_cb, void* complete_cb_cookie);
+
+// The usb_request_complete_t will be called as the last action of this method.
+// TODO: remove old usb_request_complete() and rename this back to usb_request_complete().
+void usb_request_complete_new(usb_request_t* req, zx_status_t status, zx_off_t actual,
+                              const usb_request_complete_t* complete_cb);
+
+// initializes a phys_iter_t for a usb request
+// max_length is the maximum length of a range returned by usb_request_phys_iter_next()
+// max_length must be either a positive multiple of PAGE_SIZE, or zero for no limit.
+void usb_request_phys_iter_init(phys_iter_t* iter, usb_request_t* req, size_t max_length);
+
+// returns the next physical address and length for the iterator up to size max_length.
+// return value is length, or zero if iteration is done.
+size_t usb_request_phys_iter_next(phys_iter_t* iter, zx_paddr_t* out_paddr);
+
+// usb_request_pool_init() initializes the given pool. A driver may use
+// a pool for recycling their own usb requests.
+void usb_request_pool_init(usb_request_pool_t* pool, uint64_t node_offset);
+
+// usb_request_pool_add() adds the request to the pool.
+zx_status_t usb_request_pool_add(usb_request_pool_t* pool, usb_request_t* req);
+
+// returns a request from the pool that has a buffer of the given length,
+// or null if no such request exists.
+// The request is not re-initialized in any way and should be set accordingly by the user.
+usb_request_t* usb_request_pool_get(usb_request_pool_t* pool, size_t length);
+
+// releases all usb requests stored in the pool.
+void usb_request_pool_release(usb_request_pool_t* pool);
+
+// Assumes usb_req_internal_t struct is allocated at parent_req_size offset in a usb request.
+// Adds a request to the head of the list using the list_node_t pointer from that struct.
+zx_status_t usb_req_list_add_head(list_node_t* list, usb_request_t* req, size_t parent_req_size);
+// Assumes usb_req_internal_t is allocated at parent_req_size offset in a usb request. Adds a
+// request to the tail of the list using the list_node_t pointer from that internal struct.
+zx_status_t usb_req_list_add_tail(list_node_t* list, usb_request_t* req, size_t parent_req_size);
+// Assumes usb_req_internal_t is allocated at parent_req_size offset in a usb request. Removes a
+// request from the head of the list and returns the usb_request_t.
+usb_request_t* usb_req_list_remove_head(list_node_t* list, size_t parent_req_size);
+
+__END_CDECLS;
diff --git a/system/dev/lib/usb-old/rules.mk b/system/dev/lib/usb-old/rules.mk
new file mode 100644
index 0000000..ad7bc9e
--- /dev/null
+++ b/system/dev/lib/usb-old/rules.mk
@@ -0,0 +1,23 @@
+# Copyright 2016 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+MODULE := $(LOCAL_DIR)
+MODULE_TYPE := userlib
+
+MODULE_SRCS := \
+	$(LOCAL_DIR)/usb.c \
+	$(LOCAL_DIR)/usb-request.c \
+
+MODULE_STATIC_LIBS := system/ulib/ddk
+MODULE_LIBS := system/ulib/c
+
+MODULE_BANJO_LIBS := \
+    system/banjo/ddk-protocol-usb-composite \
+    system/banjo/ddk-protocol-usb-request \
+
+MODULE_PACKAGE := src
+
+include make/module.mk
diff --git a/system/dev/lib/usb-old/usb-request.c b/system/dev/lib/usb-old/usb-request.c
new file mode 100644
index 0000000..1c24288
--- /dev/null
+++ b/system/dev/lib/usb-old/usb-request.c
@@ -0,0 +1,413 @@
+// Copyright 2017 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <ddk/protocol/usb-old.h>
+#include <usb/usb-request.h>
+#include <ddk/debug.h>
+
+#include <zircon/process.h>
+#include <zircon/syscalls.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+
+static inline size_t req_buffer_size(usb_request_t* req, size_t offset) {
+    size_t remaining = req->size - req->offset - offset;
+    // May overflow.
+    if (remaining > req->size) {
+        remaining = 0;
+    }
+    return remaining;
+}
+
+static inline void* req_buffer_virt(usb_request_t* req) {
+    return (void*)(((uintptr_t)req->virt) + req->offset);
+}
+
+__EXPORT zx_status_t usb_request_alloc(usb_request_t** out, uint64_t data_size,
+                                       uint8_t ep_address, size_t req_size) {
+    if (req_size < sizeof(usb_request_t)) {
+        return ZX_ERR_INVALID_ARGS;
+    }
+    usb_request_t* req = calloc(1, req_size);
+    if (!req) {
+        return ZX_ERR_NO_MEMORY;
+    }
+    zx_status_t status = ZX_OK;
+    if (data_size > 0) {
+        status = zx_vmo_create(data_size, 0, &req->vmo_handle);
+        if (status != ZX_OK) {
+            zxlogf(ERROR, "usb_request_alloc: Failed to create vmo: %d\n", status);
+            free(req);
+            return status;
+        }
+
+        zx_vaddr_t mapped_addr;
+        status = zx_vmar_map(zx_vmar_root_self(), ZX_VM_PERM_READ | ZX_VM_PERM_WRITE,
+                             0, req->vmo_handle, 0, data_size, &mapped_addr);
+
+        if (status != ZX_OK) {
+            zxlogf(ERROR, "usb_request_alloc: Failed to map the vmo: %d\n", status);
+            free(req);
+            return status;
+        }
+
+        req->virt = mapped_addr;
+        req->offset = 0;
+        req->size = data_size;
+    }
+    req->alloc_size = req_size;
+    req->header.ep_address = ep_address;
+    req->header.length = data_size;
+    req->release_frees = true;
+    *out = req;
+    return ZX_OK;
+}
+
+// usb_request_alloc_vmo() creates a new usb request with the given VMO.
+__EXPORT zx_status_t usb_request_alloc_vmo(usb_request_t** out, zx_handle_t vmo_handle,
+                                           uint64_t vmo_offset, uint64_t length,
+                                           uint8_t ep_address, size_t req_size) {
+    usb_request_t* req = calloc(1, req_size);
+    if (!req) {
+        return ZX_ERR_NO_MEMORY;
+    }
+    zx_handle_t dup_handle;
+    zx_status_t status = zx_handle_duplicate(vmo_handle, ZX_RIGHT_SAME_RIGHTS, &dup_handle);
+    if (status != ZX_OK) {
+        zxlogf(ERROR, "usb_request_alloc_vmo: Failed to duplicate handle: %d\n", status);
+        free(req);
+        return status;
+    }
+
+    uint64_t size;
+    status = zx_vmo_get_size(dup_handle, &size);
+    if (status != ZX_OK) {
+        zx_handle_close(dup_handle);
+        free(req);
+        return status;
+    }
+
+    zx_vaddr_t mapped_addr;
+    status = zx_vmar_map(zx_vmar_root_self(), ZX_VM_PERM_READ | ZX_VM_PERM_WRITE,
+                         0, dup_handle, 0, size, &mapped_addr);
+    if (status != ZX_OK) {
+        zxlogf(ERROR, "usb_request_alloc_vmo: zx_vmar_map failed %d size: %zu\n", status, size);
+        zx_handle_close(dup_handle);
+        free(req);
+        return status;
+    }
+
+    req->alloc_size = req_size;
+    req->vmo_handle = dup_handle;
+    req->virt = mapped_addr;
+    req->offset = vmo_offset;
+    req->size = size;
+
+    req->pmt = ZX_HANDLE_INVALID;
+
+    req->header.ep_address = ep_address;
+    req->header.length = length;
+    req->release_frees = true;
+    *out = req;
+    return ZX_OK;
+}
+
+// usb_request_init() initializes the statically allocated usb request with the given VMO.
+// This will free any resources allocated by the usb request but not the usb request itself.
+__EXPORT zx_status_t usb_request_init(usb_request_t* req, zx_handle_t vmo_handle,
+                                      uint64_t vmo_offset, uint64_t length, uint8_t ep_address) {
+    memset(req, 0, req->alloc_size);
+
+    zx_handle_t dup_handle;
+    zx_status_t status = zx_handle_duplicate(vmo_handle, ZX_RIGHT_SAME_RIGHTS, &dup_handle);
+    if (status != ZX_OK) {
+        zxlogf(ERROR, "usb_request_init: Failed to duplicate handle: %d\n", status);
+        return status;
+    }
+
+    uint64_t size;
+    status = zx_vmo_get_size(dup_handle, &size);
+    if (status != ZX_OK) {
+        zx_handle_close(dup_handle);
+        return status;
+    }
+
+    //TODO(ravoorir): Do not map the entire vmo. Map only what is needed.
+    zx_vaddr_t mapped_addr;
+    status = zx_vmar_map(zx_vmar_root_self(), ZX_VM_PERM_READ | ZX_VM_PERM_WRITE,
+                         0, dup_handle, 0, size, &mapped_addr);
+    if (status != ZX_OK) {
+        zxlogf(ERROR, "usb_request_init: zx_vmar_map failed %d size: %zu\n", status, size);
+        zx_handle_close(dup_handle);
+        return status;
+    }
+
+    req->vmo_handle = dup_handle;
+    req->virt = mapped_addr;
+    req->offset = vmo_offset;
+    req->size = size;
+
+    req->pmt = ZX_HANDLE_INVALID;
+
+    req->header.ep_address = ep_address;
+    req->header.length = length;
+    req->release_frees = false;
+    return ZX_OK;
+}
+
+__EXPORT zx_status_t usb_request_set_sg_list(usb_request_t* req,
+                                             phys_iter_sg_entry_t* sg_list, size_t sg_count) {
+    if (req->sg_list) {
+        free(req->sg_list);
+        req->sg_list = NULL;
+        req->sg_count = 0;
+    }
+    size_t total_length = 0;
+    // TODO(jocelyndang): disallow overlapping entries?
+    for (size_t i = 0; i < sg_count; ++i) {
+        phys_iter_sg_entry_t* entry = &sg_list[i];
+        if (entry->length == 0 || (req_buffer_size(req, entry->offset) < entry->length)) {
+            return ZX_ERR_INVALID_ARGS;
+        }
+        total_length += entry->length;
+    }
+    size_t num_bytes = sg_count * sizeof(phys_iter_sg_entry_t);
+    req->sg_list = malloc(num_bytes);
+    if (req->sg_list == NULL) {
+        zxlogf(ERROR, "usb_request_set_sg_list: out of memory\n");
+        return ZX_ERR_NO_MEMORY;
+    }
+    memcpy(req->sg_list, sg_list, num_bytes);
+    req->sg_count = sg_count;
+    req->header.length = total_length;
+    return ZX_OK;
+}
+
+__EXPORT ssize_t usb_request_copy_from(usb_request_t* req, void* data, size_t length, size_t offset) {
+    length = MIN(req_buffer_size(req, offset), length);
+    memcpy(data, req_buffer_virt(req) + offset, length);
+    return length;
+}
+
+__EXPORT ssize_t usb_request_copy_to(usb_request_t* req, const void* data, size_t length, size_t offset) {
+    length = MIN(req_buffer_size(req, offset), length);
+    memcpy(req_buffer_virt(req) + offset, data, length);
+    return length;
+}
+
+__EXPORT zx_status_t usb_request_mmap(usb_request_t* req, void** data) {
+    *data = req_buffer_virt(req);
+    // TODO(jocelyndang): modify this once we start passing usb requests across process boundaries.
+    return ZX_OK;
+}
+
+__EXPORT zx_status_t usb_request_cacheop(usb_request_t* req, uint32_t op, size_t offset, size_t length) {
+    if (length > 0) {
+        return zx_vmo_op_range(req->vmo_handle, op, req->offset + offset, length, NULL, 0);
+    } else {
+        return ZX_OK;
+    }
+}
+
+__EXPORT zx_status_t usb_request_cache_flush(usb_request_t* req, zx_off_t offset, size_t length) {
+    if (offset + length < offset || offset + length > req->size) {
+        return ZX_ERR_OUT_OF_RANGE;
+    }
+    return zx_cache_flush(req_buffer_virt(req) + offset, length, ZX_CACHE_FLUSH_DATA);
+}
+
+__EXPORT zx_status_t usb_request_cache_flush_invalidate(usb_request_t* req, zx_off_t offset, size_t length) {
+    if (offset + length < offset || offset + length > req->size) {
+        return ZX_ERR_OUT_OF_RANGE;
+    }
+    return zx_cache_flush(req_buffer_virt(req) + offset, length,
+                          ZX_CACHE_FLUSH_DATA | ZX_CACHE_FLUSH_INVALIDATE);
+}
+
+zx_status_t usb_request_physmap(usb_request_t* req, zx_handle_t bti_handle) {
+    if (req->phys_count > 0) {
+        return ZX_OK;
+    }
+    // zx_bti_pin returns whole pages, so take into account unaligned vmo
+    // offset and length when calculating the amount of pages returned
+    uint64_t page_offset = ROUNDDOWN(req->offset, PAGE_SIZE);
+    // The buffer size is the vmo size from offset 0.
+    uint64_t page_length = req->size - page_offset;
+    uint64_t pages = ROUNDUP(page_length, PAGE_SIZE) / PAGE_SIZE;
+
+    zx_paddr_t* paddrs = malloc(pages * sizeof(zx_paddr_t));
+    if (paddrs == NULL) {
+        zxlogf(ERROR, "usb_request_physmap: out of memory\n");
+        return ZX_ERR_NO_MEMORY;
+    }
+    const size_t sub_offset = page_offset & (PAGE_SIZE - 1);
+    const size_t pin_offset = page_offset - sub_offset;
+    const size_t pin_length = ROUNDUP(page_length + sub_offset, PAGE_SIZE);
+
+    if (pin_length / PAGE_SIZE != pages) {
+        return ZX_ERR_INVALID_ARGS;
+    }
+    zx_handle_t pmt;
+    uint32_t options = ZX_BTI_PERM_READ | ZX_BTI_PERM_WRITE;
+    zx_status_t status = zx_bti_pin(bti_handle, options, req->vmo_handle,
+                                    pin_offset, pin_length, paddrs, pages, &pmt);
+    if (status != ZX_OK) {
+        zxlogf(ERROR, "usb_request_physmap: zx_bti_pin failed:%d\n", status);
+        free(paddrs);
+        return status;
+    }
+    // Account for the initial misalignment if any
+    paddrs[0] += sub_offset;
+    req->phys_list = paddrs;
+    req->phys_count = pages;
+    req->pmt = pmt;
+
+    return ZX_OK;
+}
+
+__EXPORT void usb_request_release(usb_request_t* req) {
+    if (req->vmo_handle != ZX_HANDLE_INVALID) {
+        if (req->pmt != ZX_HANDLE_INVALID) {
+            zx_status_t status = zx_pmt_unpin(req->pmt);
+            ZX_DEBUG_ASSERT(status == ZX_OK);
+            req->pmt = ZX_HANDLE_INVALID;
+        }
+
+        zx_vmar_unmap(zx_vmar_root_self(), (uintptr_t)req->virt, req->size);
+        zx_handle_close(req->vmo_handle);
+        req->vmo_handle = ZX_HANDLE_INVALID;
+    }
+    if (req->phys_list && req->pmt != ZX_HANDLE_INVALID) {
+        zx_status_t status = zx_pmt_unpin(req->pmt);
+        ZX_DEBUG_ASSERT(status == ZX_OK);
+        req->pmt = ZX_HANDLE_INVALID;
+    }
+    free(req->phys_list);
+    req->phys_list = NULL;
+    req->phys_count = 0;
+    free(req->sg_list);
+    req->sg_list = NULL;
+    req->sg_count = 0;
+    if (req->release_frees) {
+        free(req);
+    }
+}
+
+__EXPORT void usb_request_complete(usb_request_t* req, zx_status_t status, zx_off_t actual,
+                                   usb_request_complete_cb complete_cb, void* complete_cb_cookie) {
+    req->response.status = status;
+    req->response.actual = actual;
+
+    if (complete_cb) {
+        complete_cb(req, complete_cb_cookie);
+    }
+}
+
+__EXPORT void usb_request_complete_new(usb_request_t* req, zx_status_t status, zx_off_t actual,
+                                       const usb_request_complete_t* complete_cb) {
+    req->response.status = status;
+    req->response.actual = actual;
+
+    if (complete_cb) {
+        complete_cb->callback(complete_cb->ctx, req);
+    }
+}
+
+__EXPORT void usb_request_phys_iter_init(phys_iter_t* iter, usb_request_t* req, size_t max_length) {
+    phys_iter_buffer_t buf = {
+        .length = req->header.length,
+        .vmo_offset = req->offset,
+        .phys = req->phys_list,
+        .phys_count = req->phys_count,
+        .sg_list = req->sg_list,
+        .sg_count = req->sg_count
+    };
+    phys_iter_init(iter, &buf, max_length);
+}
+
+__EXPORT size_t usb_request_phys_iter_next(phys_iter_t* iter, zx_paddr_t* out_paddr) {
+    return phys_iter_next(iter, out_paddr);
+}
+
+__EXPORT void usb_request_pool_init(usb_request_pool_t* pool, uint64_t node_offset) {
+    mtx_init(&pool->lock, mtx_plain);
+    list_initialize(&pool->free_reqs);
+    pool->node_offset = node_offset;
+}
+
+__EXPORT zx_status_t usb_request_pool_add(usb_request_pool_t* pool, usb_request_t* req) {
+    mtx_lock(&pool->lock);
+    if (req->alloc_size < (pool->node_offset + sizeof(list_node_t))) {
+        mtx_unlock(&pool->lock);
+        return ZX_ERR_INVALID_ARGS;
+    }
+    list_add_tail(&pool->free_reqs, (list_node_t*)((uintptr_t)req + pool->node_offset));
+    mtx_unlock(&pool->lock);
+    return ZX_OK;
+}
+
+__EXPORT usb_request_t* usb_request_pool_get(usb_request_pool_t* pool, size_t length) {
+    usb_request_t* req = NULL;
+    bool found = false;
+
+    mtx_lock(&pool->lock);
+    list_node_t* node;
+    list_for_every(&pool->free_reqs, node) {
+        req = (usb_request_t*)((uintptr_t)node - pool->node_offset);
+        if (req->size == length) {
+            found = true;
+            break;
+        }
+    }
+    if (found) {
+        list_delete(node);
+    }
+    mtx_unlock(&pool->lock);
+
+    return found ? req : NULL;
+}
+
+__EXPORT void usb_request_pool_release(usb_request_pool_t* pool) {
+    mtx_lock(&pool->lock);
+
+    usb_request_t* req;
+    list_node_t* node;
+    while ((node = list_remove_tail(&pool->free_reqs)) != NULL) {
+        req =  (usb_request_t*)((uintptr_t)node - pool->node_offset);
+        usb_request_release(req);
+    }
+
+    mtx_unlock(&pool->lock);
+}
+
+__EXPORT zx_status_t usb_req_list_add_head(list_node_t* list, usb_request_t* req,
+                                           size_t parent_req_size) {
+   if (req->alloc_size < parent_req_size + sizeof(list_node_t)) {
+      return ZX_ERR_INVALID_ARGS;
+   }
+   usb_req_internal_t* req_int = USB_REQ_TO_REQ_INTERNAL(req, parent_req_size);
+   list_add_head(list, &req_int->node);
+   return ZX_OK;
+}
+
+__EXPORT zx_status_t usb_req_list_add_tail(list_node_t* list, usb_request_t* req,
+                                           size_t parent_req_size) {
+   if (req->alloc_size < parent_req_size + sizeof(list_node_t)) {
+      return ZX_ERR_INVALID_ARGS;
+   }
+   usb_req_internal_t* req_int = USB_REQ_TO_REQ_INTERNAL(req, parent_req_size);
+   list_add_tail(list, &req_int->node);
+   return ZX_OK;
+}
+
+__EXPORT usb_request_t* usb_req_list_remove_head(list_node_t* list, size_t parent_req_size) {
+   usb_req_internal_t* req_int = list_remove_head_type(list, usb_req_internal_t, node);
+   if (req_int) {
+       return REQ_INTERNAL_TO_USB_REQ(req_int, parent_req_size);
+   }
+   return NULL;
+}
diff --git a/system/dev/lib/usb-old/usb.c b/system/dev/lib/usb-old/usb.c
new file mode 100644
index 0000000..7ac38a8
--- /dev/null
+++ b/system/dev/lib/usb-old/usb.c
@@ -0,0 +1,146 @@
+// Copyright 2016 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <ddk/usb/usb.h>
+#include <zircon/compiler.h>
+#include <stdlib.h>
+#include <string.h>
+
+// initializes a usb_desc_iter_t for iterating on descriptors past the
+// interface's existing descriptors.
+static zx_status_t usb_desc_iter_additional_init(usb_composite_protocol_t* comp,
+                                                 usb_desc_iter_t* iter) {
+    memset(iter, 0, sizeof(*iter));
+
+    size_t length = usb_composite_get_additional_descriptor_length(comp);
+    uint8_t* descriptors = malloc(length);
+    if (!descriptors) {
+        return ZX_ERR_NO_MEMORY;
+    }
+    size_t actual;
+    zx_status_t status = usb_composite_get_additional_descriptor_list(comp, descriptors, length,
+                                                                      &actual);
+    if (status != ZX_OK) {
+        return status;
+    }
+
+    iter->desc = descriptors;
+    iter->desc_end = descriptors + length;
+    iter->current = descriptors;
+    return ZX_OK;
+}
+
+// helper function for claiming additional interfaces that satisfy the want_interface predicate,
+// want_interface will be passed the supplied arg
+__EXPORT zx_status_t usb_claim_additional_interfaces(usb_composite_protocol_t* comp,
+    bool (*want_interface)(usb_interface_descriptor_t*, void*),
+    void* arg) {
+    usb_desc_iter_t iter;
+    zx_status_t status = usb_desc_iter_additional_init(comp, &iter);
+    if (status != ZX_OK) {
+        return status;
+    }
+
+    usb_interface_descriptor_t* intf = usb_desc_iter_next_interface(&iter, true);
+    while (intf != NULL && want_interface(intf, arg)) {
+        // We need to find the start of the next interface to calculate the
+        // total length of the current one.
+        usb_interface_descriptor_t* next = usb_desc_iter_next_interface(&iter, true);
+        // If we're currently on the last interface, next will be NULL.
+        void* intf_end = next ? next : (void*)iter.desc_end;
+        size_t length = intf_end - (void*)intf;
+
+        status = usb_composite_claim_interface(comp, intf, length);
+        if (status != ZX_OK) {
+            break;
+        }
+        intf = next;
+    }
+    usb_desc_iter_release(&iter);
+    return status;
+}
+
+// initializes a usb_desc_iter_t
+__EXPORT zx_status_t usb_desc_iter_init(usb_protocol_t* usb, usb_desc_iter_t* iter) {
+    memset(iter, 0, sizeof(*iter));
+
+    void* descriptors;
+    size_t length;
+    zx_status_t status = usb_get_descriptor_list(usb, &descriptors, &length);
+    if (status != ZX_OK) {
+        return status;
+    }
+
+    iter->desc = descriptors;
+    iter->desc_end = descriptors + length;
+    iter->current = descriptors;
+    return ZX_OK;
+}
+
+// releases resources in a usb_desc_iter_t
+__EXPORT void usb_desc_iter_release(usb_desc_iter_t* iter) {
+    free(iter->desc);
+    iter->desc = NULL;
+}
+
+// resets iterator to the beginning
+__EXPORT void usb_desc_iter_reset(usb_desc_iter_t* iter) {
+    iter->current = iter->desc;
+}
+
+// returns the next descriptor
+__EXPORT usb_descriptor_header_t* usb_desc_iter_next(usb_desc_iter_t* iter) {
+    usb_descriptor_header_t* header = usb_desc_iter_peek(iter);
+    if (!header) return NULL;
+    iter->current += header->bLength;
+    return header;
+}
+
+// returns the next descriptor without incrementing the iterator
+__EXPORT usb_descriptor_header_t* usb_desc_iter_peek(usb_desc_iter_t* iter) {
+    if (iter->current + sizeof(usb_descriptor_header_t) > iter->desc_end) {
+        return NULL;
+    }
+    usb_descriptor_header_t* header = (usb_descriptor_header_t *)iter->current;
+    if (iter->current + header->bLength > iter->desc_end) {
+        return NULL;
+    }
+    return header;
+}
+
+// returns the next interface descriptor, optionally skipping alternate interfaces
+__EXPORT usb_interface_descriptor_t* usb_desc_iter_next_interface(usb_desc_iter_t* iter,
+                                                                  bool skip_alt) {
+    usb_descriptor_header_t* header = usb_desc_iter_next(iter);
+
+    while (header) {
+        if (header->bDescriptorType == USB_DT_INTERFACE) {
+            usb_interface_descriptor_t* desc = (usb_interface_descriptor_t *)header;
+            if (!skip_alt || desc->bAlternateSetting == 0) {
+                return desc;
+            }
+        }
+        header = usb_desc_iter_next(iter);
+    }
+    // not found
+    return NULL;
+}
+
+// returns the next endpoint descriptor within the current interface
+__EXPORT usb_endpoint_descriptor_t* usb_desc_iter_next_endpoint(usb_desc_iter_t* iter) {
+    usb_descriptor_header_t* header = usb_desc_iter_peek(iter);
+    while (header) {
+        if (header->bDescriptorType == USB_DT_INTERFACE) {
+            // we are at end of previous interface
+            return NULL;
+        }
+        iter->current += header->bLength;
+        if (header->bDescriptorType == USB_DT_ENDPOINT) {
+            return (usb_endpoint_descriptor_t *)header;
+        }
+        header = usb_desc_iter_peek(iter);
+    }
+    // not found
+    return NULL;
+}
diff --git a/system/dev/serial/ftdi/rules.mk b/system/dev/serial/ftdi/rules.mk
index 7e7893c..b738a9c 100644
--- a/system/dev/serial/ftdi/rules.mk
+++ b/system/dev/serial/ftdi/rules.mk
@@ -9,7 +9,7 @@
 
 MODULE_SRCS := $(LOCAL_DIR)/ftdi.c
 
-MODULE_STATIC_LIBS := system/ulib/ddk system/dev/lib/usb
+MODULE_STATIC_LIBS := system/ulib/ddk system/dev/lib/usb-old
 
 MODULE_LIBS := system/ulib/driver system/ulib/zircon system/ulib/c
 
diff --git a/system/dev/test/ddk-test/rules.mk b/system/dev/test/ddk-test/rules.mk
index 6657ffe..11e4fde 100644
--- a/system/dev/test/ddk-test/rules.mk
+++ b/system/dev/test/ddk-test/rules.mk
@@ -17,7 +17,7 @@
 MODULE_STATIC_LIBS := \
     system/ulib/ddk \
     system/ulib/sync \
-    system/dev/lib/usb \
+    system/dev/lib/usb-old \
 
 MODULE_LIBS := \
     system/ulib/unittest \
diff --git a/system/dev/usb/dwc3/rules.mk b/system/dev/usb/dwc3/rules.mk
index cb98567..63d6cd2 100644
--- a/system/dev/usb/dwc3/rules.mk
+++ b/system/dev/usb/dwc3/rules.mk
@@ -22,7 +22,7 @@
     system/ulib/hwreg \
     system/ulib/sync   \
     system/ulib/pretty \
-    system/dev/lib/usb \
+    system/dev/lib/usb-old \
     system/ulib/zx \
     system/ulib/zxcpp \
 
diff --git a/system/dev/usb/mt-musb-peripheral/rules.mk b/system/dev/usb/mt-musb-peripheral/rules.mk
index c7c14c0..b96b650 100644
--- a/system/dev/usb/mt-musb-peripheral/rules.mk
+++ b/system/dev/usb/mt-musb-peripheral/rules.mk
@@ -12,7 +12,7 @@
     $(LOCAL_DIR)/mt-usb.cpp \
 
 MODULE_STATIC_LIBS := \
-    system/dev/lib/usb \
+    system/dev/lib/usb-old \
     system/ulib/ddk \
     system/ulib/ddktl \
     system/ulib/fbl \
diff --git a/system/dev/usb/usb-bus/rules.mk b/system/dev/usb/usb-bus/rules.mk
index 4f63edc..7e17d70 100644
--- a/system/dev/usb/usb-bus/rules.mk
+++ b/system/dev/usb/usb-bus/rules.mk
@@ -14,12 +14,11 @@
     $(LOCAL_DIR)/util.c \
 
 MODULE_STATIC_LIBS := \
-    system/dev/lib/usb \
     system/ulib/ddk \
     system/ulib/fidl \
     system/ulib/sync \
     system/ulib/utf_conversion \
-    system/dev/lib/usb \
+    system/dev/lib/usb-old \
 
 MODULE_LIBS := \
     system/ulib/driver \
diff --git a/system/dev/usb/usb-composite/rules.mk b/system/dev/usb/usb-composite/rules.mk
index c8d5f07..a44befb 100644
--- a/system/dev/usb/usb-composite/rules.mk
+++ b/system/dev/usb/usb-composite/rules.mk
@@ -14,7 +14,7 @@
 
 MODULE_STATIC_LIBS := \
     system/ulib/ddk \
-    system/dev/lib/usb \
+    system/dev/lib/usb-old \
     system/ulib/sync \
 
 MODULE_LIBS := \
diff --git a/system/dev/usb/usb-dfu/rules.mk b/system/dev/usb/usb-dfu/rules.mk
index 4fdc791..55e2f7b 100644
--- a/system/dev/usb/usb-dfu/rules.mk
+++ b/system/dev/usb/usb-dfu/rules.mk
@@ -12,7 +12,7 @@
     $(LOCAL_DIR)/usb-dfu.cpp \
 
 MODULE_STATIC_LIBS := \
-    system/dev/lib/usb \
+    system/dev/lib/usb-old \
     system/ulib/ddk \
     system/ulib/ddktl \
     system/ulib/fbl \
diff --git a/system/dev/usb/usb-hub/rules.mk b/system/dev/usb/usb-hub/rules.mk
index fac4ed4..2d51a1a 100644
--- a/system/dev/usb/usb-hub/rules.mk
+++ b/system/dev/usb/usb-hub/rules.mk
@@ -12,8 +12,7 @@
 
 MODULE_STATIC_LIBS := \
     system/ulib/ddk \
-    system/dev/lib/usb \
-    system/dev/lib/usb \
+    system/dev/lib/usb-old \
     system/ulib/sync \
 
 MODULE_LIBS := \
diff --git a/system/dev/usb/usb-peripheral-test/rules.mk b/system/dev/usb/usb-peripheral-test/rules.mk
index 50d94c0..e86f60a 100644
--- a/system/dev/usb/usb-peripheral-test/rules.mk
+++ b/system/dev/usb/usb-peripheral-test/rules.mk
@@ -15,7 +15,7 @@
     system/ulib/ddk \
     system/ulib/fbl \
     system/ulib/sync \
-    system/dev/lib/usb \
+    system/dev/lib/usb-old \
 
 MODULE_LIBS := \
     system/ulib/driver \
diff --git a/system/dev/usb/usb-peripheral/rules.mk b/system/dev/usb/usb-peripheral/rules.mk
index 960cd5b..2ece3d5 100644
--- a/system/dev/usb/usb-peripheral/rules.mk
+++ b/system/dev/usb/usb-peripheral/rules.mk
@@ -14,7 +14,7 @@
 MODULE_STATIC_LIBS := \
     system/ulib/ddk \
     system/ulib/fidl \
-    system/dev/lib/usb \
+    system/dev/lib/usb-old \
 
 MODULE_LIBS := \
     system/ulib/driver \
diff --git a/system/dev/usb/usb-test/flash-programmer/rules.mk b/system/dev/usb/usb-test/flash-programmer/rules.mk
index 851bb54..250d9cc 100644
--- a/system/dev/usb/usb-test/flash-programmer/rules.mk
+++ b/system/dev/usb/usb-test/flash-programmer/rules.mk
@@ -12,7 +12,7 @@
     $(LOCAL_DIR)/flash-programmer.cpp \
 
 MODULE_STATIC_LIBS := \
-    system/dev/lib/usb \
+    system/dev/lib/usb-old \
     system/ulib/ddk \
     system/ulib/ddktl \
     system/ulib/fbl \
diff --git a/system/dev/usb/usb-test/fx3/rules.mk b/system/dev/usb/usb-test/fx3/rules.mk
index 404fcb8..eb9ec1f 100644
--- a/system/dev/usb/usb-test/fx3/rules.mk
+++ b/system/dev/usb/usb-test/fx3/rules.mk
@@ -11,7 +11,7 @@
 MODULE_SRCS += \
     $(LOCAL_DIR)/fx3.c \
 
-MODULE_STATIC_LIBS := system/ulib/ddk system/ulib/fidl system/dev/lib/usb
+MODULE_STATIC_LIBS := system/ulib/ddk system/ulib/fidl system/dev/lib/usb-old
 
 MODULE_LIBS := system/ulib/driver system/ulib/c system/ulib/zircon
 
diff --git a/system/dev/usb/usb-test/usb-tester/rules.mk b/system/dev/usb/usb-test/usb-tester/rules.mk
index 3429da9..6c99c5a 100644
--- a/system/dev/usb/usb-test/usb-tester/rules.mk
+++ b/system/dev/usb/usb-test/usb-tester/rules.mk
@@ -17,7 +17,7 @@
     system/ulib/fbl \
     system/ulib/fidl \
     system/ulib/sync \
-    system/dev/lib/usb \
+    system/dev/lib/usb-old \
     system/ulib/zxcpp \
 
 MODULE_FIDL_LIBS := system/fidl/zircon-usb-tester
diff --git a/system/dev/usb/xhci/rules.mk b/system/dev/usb/xhci/rules.mk
index 662b31a..9456668 100644
--- a/system/dev/usb/xhci/rules.mk
+++ b/system/dev/usb/xhci/rules.mk
@@ -29,7 +29,7 @@
     system/ulib/sync \
     system/ulib/xdc-server-utils \
     system/ulib/zx \
-    system/dev/lib/usb \
+    system/dev/lib/usb-old \
 
 MODULE_LIBS := \
     system/ulib/driver \