[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 \