fix wip
Change-Id: I96bb816209e1196ba3e93bc5c594ea751d7af3d6
diff --git a/system/dev/usb/usb-peripheral/usb-function.cpp b/system/dev/usb/usb-peripheral/usb-function.cpp
index d26df9c..58bb517 100644
--- a/system/dev/usb/usb-peripheral/usb-function.cpp
+++ b/system/dev/usb/usb-peripheral/usb-function.cpp
@@ -6,11 +6,13 @@
#include "usb-peripheral.h"
#include <ddk/debug.h>
+#include <fbl/array.h>
namespace usb_peripheral {
void UsbFunction::DdkRelease() {
- // Do nothing here. This object is owned by the UsbPeripheral class so we don't delete ourself.
+ // Release the reference how that devmgr no longer has a pointer to the function.
+ __UNUSED bool dummy = Release();
}
// UsbFunctionProtocol implementation.
@@ -32,30 +34,31 @@
function_intf_.GetDescriptors(descriptors, length, &actual);
if (actual != length) {
zxlogf(ERROR, "UsbFunctionInterfaceClient::GetDescriptors() failed\n");
+ delete[] descriptors;
return ZX_ERR_INTERNAL;
}
- auto status = peripheral_->ValidateFunction(this, descriptors, length, &num_interfaces_);
+ auto status = peripheral_->ValidateFunction(fbl::RefPtr<UsbFunction>(this), descriptors, length,
+ &num_interfaces_);
if (status != ZX_OK) {
+ delete[] descriptors;
return status;
}
- descriptors_ = static_cast<usb_descriptor_header_t*>(malloc(length));
- if (!descriptors_) {
+ descriptors_.reset(descriptors, length);
+ if (!ac.check()) {
return ZX_ERR_NO_MEMORY;
}
- memcpy(descriptors_, descriptors, length);
- descriptors_length_ = length;
return peripheral_->FunctionRegistered();
}
zx_status_t UsbFunction::UsbFunctionAllocInterface(uint8_t* out_intf_num) {
- return peripheral_->AllocInterface(this, out_intf_num);
+ return peripheral_->AllocInterface(fbl::RefPtr<UsbFunction>(this), out_intf_num);
}
zx_status_t UsbFunction::UsbFunctionAllocEp(uint8_t direction, uint8_t* out_address) {
- return peripheral_->AllocEndpoint(this, direction, out_address);
+ return peripheral_->AllocEndpoint(fbl::RefPtr<UsbFunction>(this), direction, out_address);
}
zx_status_t UsbFunction::UsbFunctionConfigEp(const usb_endpoint_descriptor_t* ep_desc,
@@ -67,8 +70,8 @@
return peripheral_->dci().DisableEp(address);
}
-zx_status_t UsbFunction::UsbFunctionAllocStringDesc(const char* string, uint8_t* out_index) {
- return peripheral_->AllocStringDesc(string, out_index);
+zx_status_t UsbFunction::UsbFunctionAllocStringDesc(const char* str, uint8_t* out_index) {
+ return peripheral_->AllocStringDesc(str, out_index);
}
void UsbFunction::UsbFunctionRequestQueue(usb_request_t* usb_request,
diff --git a/system/dev/usb/usb-peripheral/usb-function.h b/system/dev/usb/usb-peripheral/usb-function.h
index 72738e1..4d777c2 100644
--- a/system/dev/usb/usb-peripheral/usb-function.h
+++ b/system/dev/usb/usb-peripheral/usb-function.h
@@ -7,6 +7,8 @@
#include <ddktl/device.h>
#include <ddktl/protocol/usb/dci.h>
#include <ddktl/protocol/usb/function.h>
+#include <fbl/array.h>
+#include <fbl/ref_counted.h>
#include <fuchsia/hardware/usb/peripheral/c/fidl.h>
#include "usb-peripheral.h"
@@ -19,15 +21,12 @@
// This class represents a USB function in the peripheral role configurations.
// USB function drivers bind to this.
class UsbFunction : public UsbFunctionType,
- public ddk::UsbFunctionProtocol<UsbFunction, ddk::base_protocol> {
+ public ddk::UsbFunctionProtocol<UsbFunction, ddk::base_protocol>,
+ public fbl::RefCounted<UsbFunction> {
public:
UsbFunction(zx_device_t* parent, UsbPeripheral* peripheral, const FunctionDescriptor* desc)
: UsbFunctionType(parent), peripheral_(peripheral), function_descriptor_(*desc) {}
- ~UsbFunction() {
- delete[] descriptors_;
- }
-
// Device protocol implementation.
void DdkRelease();
@@ -38,7 +37,7 @@
zx_status_t UsbFunctionConfigEp(const usb_endpoint_descriptor_t* ep_desc,
const usb_ss_ep_comp_descriptor_t* ss_comp_desc);
zx_status_t UsbFunctionDisableEp(uint8_t address);
- zx_status_t UsbFunctionAllocStringDesc(const char* string, uint8_t* out_index);
+ zx_status_t UsbFunctionAllocStringDesc(const char* str, uint8_t* out_index);
void UsbFunctionRequestQueue(usb_request_t* usb_request,
const usb_request_complete_t* complete_cb);
zx_status_t UsbFunctionEpSetStall(uint8_t ep_address);
@@ -51,8 +50,8 @@
void* read_buffer, size_t read_size, size_t* out_read_actual);
inline const usb_descriptor_header_t* GetDescriptors(size_t* out_length) const {
- *out_length = descriptors_length_;
- return descriptors_;
+ *out_length = descriptors_.size();
+ return reinterpret_cast<usb_descriptor_header_t*>(descriptors_.get());
}
inline const FunctionDescriptor& GetFunctionDescriptor() const { return function_descriptor_; }
@@ -69,8 +68,7 @@
const FunctionDescriptor function_descriptor_;
uint8_t num_interfaces_ = 0;
- usb_descriptor_header_t* descriptors_ = nullptr;
- size_t descriptors_length_ = 0;
+ fbl::Array<uint8_t> descriptors_;
};
} // namespace usb_peripheral
diff --git a/system/dev/usb/usb-peripheral/usb-peripheral.cpp b/system/dev/usb/usb-peripheral/usb-peripheral.cpp
index 1aa4e5a..7b2f9cc 100644
--- a/system/dev/usb/usb-peripheral/usb-peripheral.cpp
+++ b/system/dev/usb/usb-peripheral/usb-peripheral.cpp
@@ -21,6 +21,7 @@
#include <ddk/protocol/usb/modeswitch.h>
#include <fbl/alloc_checker.h>
#include <fbl/auto_lock.h>
+#include <fbl/unique_ptr.h>
#include <zircon/device/usb-peripheral.h>
#include <zircon/hw/usb.h>
#include <zircon/hw/usb/cdc.h>
@@ -30,20 +31,20 @@
namespace usb_peripheral {
-zx_status_t UsbPeripheral::Create(zx_device_t* parent) {
+zx_status_t UsbPeripheral::Create(void* ctx, zx_device_t* parent) {
fbl::AllocChecker ac;
- auto bus = fbl::make_unique_checked<UsbPeripheral>(&ac, parent);
+ auto device = fbl::make_unique_checked<UsbPeripheral>(&ac, parent);
if (!ac.check()) {
return ZX_ERR_NO_MEMORY;
}
- auto status = bus->Init();
+ auto status = device->Init();
if (status != ZX_OK) {
return status;
}
// devmgr is now in charge of the device.
- __UNUSED auto* dummy = bus.release();
+ __UNUSED auto* dummy = device.release();
return ZX_OK;
}
@@ -72,8 +73,7 @@
}
parent_request_size_ = dci_.GetRequestSize();
- status = DdkAdd("usb-peripheral", DEVICE_ADD_NON_BINDABLE, nullptr, 0,
- ZX_PROTOCOL_USB_PERIPHERAL);
+ status = DdkAdd("usb-peripheral", DEVICE_ADD_NON_BINDABLE);
if (status != ZX_OK) {
return status;
}
@@ -106,8 +106,8 @@
return ZX_OK;
}
-zx_status_t UsbPeripheral::ValidateFunction(UsbFunction* function, void* descriptors, size_t length,
- uint8_t* out_num_interfaces) {
+zx_status_t UsbPeripheral::ValidateFunction(fbl::RefPtr<UsbFunction> function, void* descriptors,
+ size_t length, uint8_t* out_num_interfaces) {
auto* intf_desc = static_cast<usb_interface_descriptor_t*>(descriptors);
if (intf_desc->bDescriptorType != USB_DT_INTERFACE ||
intf_desc->bLength != sizeof(usb_interface_descriptor_t)) {
@@ -159,7 +159,7 @@
zx_status_t UsbPeripheral::FunctionRegistered() {
fbl::AutoLock lock(&lock_);
- if (config_desc_) {
+ if (config_desc_.size() == 0) {
zxlogf(ERROR, "usb_device_function_registered: already have configuration descriptor!\n");
return ZX_ERR_BAD_STATE;
}
@@ -180,11 +180,11 @@
// build our configuration descriptor
fbl::AllocChecker ac;
- auto* config_desc = reinterpret_cast<usb_configuration_descriptor_t*>(
- new (&ac) uint8_t[length]);
+ auto* config_desc_bytes = new (&ac) uint8_t[length];
if (!ac.check()) {
return ZX_ERR_NO_MEMORY;
}
+ auto* config_desc = reinterpret_cast<usb_configuration_descriptor_t*>(config_desc_bytes);
config_desc->bLength = sizeof(*config_desc);
config_desc->bDescriptorType = USB_DT_CONFIG;
@@ -206,7 +206,7 @@
config_desc->bNumInterfaces = static_cast<uint8_t>(config_desc->bNumInterfaces +
function->GetNumInterfaces());
}
- config_desc_ = config_desc;
+ config_desc_.reset(config_desc_bytes, length);
zxlogf(TRACE, "usb_device_function_registered functions_registered = true\n");
functions_registered_ = true;
@@ -214,7 +214,8 @@
return DeviceStateChanged();
}
-zx_status_t UsbPeripheral::AllocInterface(UsbFunction* function, uint8_t* out_intf_num) {
+zx_status_t UsbPeripheral::AllocInterface(fbl::RefPtr<UsbFunction> function,
+ uint8_t* out_intf_num) {
fbl::AutoLock lock(&lock_);
for (uint8_t i = 0; i < countof(interface_map_); i++) {
@@ -228,7 +229,7 @@
return ZX_ERR_NO_RESOURCES;
}
-zx_status_t UsbPeripheral::AllocEndpoint(UsbFunction* function, uint8_t direction,
+zx_status_t UsbPeripheral::AllocEndpoint(fbl::RefPtr<UsbFunction> function, uint8_t direction,
uint8_t* out_address) {
uint8_t start, end;
@@ -258,64 +259,68 @@
void* buffer, size_t length, size_t* out_actual) {
uint8_t type = request_type & USB_TYPE_MASK;
- if (type == USB_TYPE_STANDARD) {
- auto desc_type = static_cast<uint8_t>(value >> 8);
- if (desc_type == USB_DT_DEVICE && index == 0) {
- if (device_desc_.bLength == 0) {
- zxlogf(ERROR, "%s: device descriptor not set\n", __func__);
- return ZX_ERR_INTERNAL;
- }
- if (length > sizeof(device_desc_)) length = sizeof(device_desc_);
- memcpy(buffer, &device_desc_, length);
- *out_actual = length;
- return ZX_OK;
- } else if (desc_type == USB_DT_CONFIG && index == 0) {
- const usb_configuration_descriptor_t* desc = config_desc_;
- if (!desc) {
- zxlogf(ERROR, "%s: configuration descriptor not set\n", __func__);
- return ZX_ERR_INTERNAL;
- }
- uint16_t desc_length = letoh16(desc->wTotalLength);
- if (length > desc_length) length =desc_length;
- memcpy(buffer, desc, length);
- *out_actual = length;
- return ZX_OK;
+ if (type != USB_TYPE_STANDARD) {
+ zxlogf(ERROR, "%s unsupported value: %d index: %d\n", __func__, value, index);
+ return ZX_ERR_NOT_SUPPORTED;
+ }
+
+ auto desc_type = static_cast<uint8_t>(value >> 8);
+ if (desc_type == USB_DT_DEVICE && index == 0) {
+ if (device_desc_.bLength == 0) {
+ zxlogf(ERROR, "%s: device descriptor not set\n", __func__);
+ return ZX_ERR_INTERNAL;
}
- else if (value >> 8 == USB_DT_STRING) {
- uint8_t desc[255];
- auto* header = reinterpret_cast<usb_descriptor_header_t*>(desc);
- header->bDescriptorType = USB_DT_STRING;
-
- auto string_index = static_cast<uint8_t>(value & 0xFF);
- if (string_index == 0) {
- // special case - return language list
- header->bLength = 4;
- desc[2] = 0x09; // language ID
- desc[3] = 0x04;
- } else {
- // String indices are 1-based.
- string_index--;
- if (string_index >= strings_.size()) {
- return ZX_ERR_INVALID_ARGS;
- }
- const char* string = strings_[string_index].c_str();
- unsigned index = 2;
-
- // convert ASCII to Unicode
- if (string) {
- while (*string && index < sizeof(desc) - 2) {
- desc[index++] = *string++;
- desc[index++] = 0;
- }
- }
- header->bLength = static_cast<uint8_t>(index);
- }
-
- if (header->bLength < length) length = header->bLength;
- memcpy(buffer, desc, length);
- *out_actual = length;
- return ZX_OK;
+ if (length > sizeof(device_desc_)) length = sizeof(device_desc_);
+ memcpy(buffer, &device_desc_, length);
+ *out_actual = length;
+ return ZX_OK;
+ } else if (desc_type == USB_DT_CONFIG && index == 0) {
+ if (config_desc_.size() == 0) {
+ zxlogf(ERROR, "%s: configuration descriptor not set\n", __func__);
+ return ZX_ERR_INTERNAL;
}
+ auto desc_length = config_desc_.size();
+ if (length > desc_length) {
+ length = desc_length;
+ }
+ memcpy(buffer, config_desc_.get(), length);
+ *out_actual = length;
+ return ZX_OK;
+ }
+ else if (value >> 8 == USB_DT_STRING) {
+ uint8_t desc[255];
+ auto* header = reinterpret_cast<usb_descriptor_header_t*>(desc);
+ header->bDescriptorType = USB_DT_STRING;
+
+ auto string_index = static_cast<uint8_t>(value & 0xFF);
+ if (string_index == 0) {
+ // special case - return language list
+ header->bLength = 4;
+ desc[2] = 0x09; // language ID
+ desc[3] = 0x04;
+ } else {
+ // String indices are 1-based.
+ string_index--;
+ if (string_index >= strings_.size()) {
+ return ZX_ERR_INVALID_ARGS;
+ }
+ const char* string = strings_[string_index].c_str();
+ unsigned index = 2;
+
+ // convert ASCII to UTF16
+ if (string) {
+ while (*string && index < sizeof(desc) - 2) {
+ desc[index++] = *string++;
+ desc[index++] = 0;
+ }
+ }
+ header->bLength = static_cast<uint8_t>(index);
+ }
+
+ if (header->bLength < length) length = header->bLength;
+ memcpy(buffer, desc, length);
+ *out_actual = length;
+ return ZX_OK;
}
zxlogf(ERROR, "%s unsupported value: %d index: %d\n", __func__, value, index);
@@ -345,8 +350,8 @@
return ZX_ERR_OUT_OF_RANGE;
}
- auto* function = interface_map_[interface];
- if (function) {
+ auto function = interface_map_[interface];
+ if (function != nullptr) {
return function->SetInterface(interface, alt_setting);
}
return ZX_ERR_NOT_SUPPORTED;
@@ -358,12 +363,12 @@
}
fbl::AllocChecker ac;
- auto function = fbl::make_unique_checked<UsbFunction>(&ac, zxdev(), this, desc);
+ auto function = fbl::MakeRefCountedChecked<UsbFunction>(&ac, zxdev(), this, desc);
if (!ac.check()) {
return ZX_ERR_NO_MEMORY;
}
- functions_.push_back(std::move(function));
+ functions_.push_back(function);
return ZX_OK;
}
@@ -400,14 +405,16 @@
}
}
functions_.reset();
-
- delete[] config_desc_;
- config_desc_ = nullptr;
+ config_desc_.reset();
functions_bound_ = false;
functions_registered_ = false;
- memset(interface_map_, 0, sizeof(interface_map_));
- memset(endpoint_map_, 0, sizeof(endpoint_map_));
+ for (size_t i = 0; i < countof(interface_map_); i++) {
+ interface_map_[i].reset();
+ }
+ for (size_t i = 0; i < countof(endpoint_map_); i++) {
+ endpoint_map_[i].reset();
+ }
strings_.reset();
return DeviceStateChanged();
@@ -420,7 +427,7 @@
}
for (unsigned i = 0; i < functions_.size(); i++) {
- auto* function = functions_[i].get();
+ auto function = functions_[i];
char name[16];
snprintf(name, sizeof(name), "function-%03u", i);
@@ -440,6 +447,8 @@
zxlogf(ERROR, "usb_dev_bind_functions add_device failed %d\n", status);
return status;
}
+ // Hold a reference while devmgr has a pointer to the function.
+ function->AddRef();
}
function_devs_added_ = true;
@@ -456,8 +465,7 @@
function->DdkRemove();
}
- delete[] config_desc_;
- config_desc_ = NULL;
+ config_desc_.reset();
functions_registered_ = false;
function_devs_added_ = false;
}
@@ -557,8 +565,8 @@
return ZX_ERR_OUT_OF_RANGE;
}
// delegate to the function driver for the interface
- auto* function = interface_map_[index];
- if (function) {
+ auto function = interface_map_[index];
+ if (function != nullptr) {
return function->Control(setup, write_buffer, write_size, read_buffer, read_size,
out_read_actual);
}
@@ -574,8 +582,8 @@
if (index >= countof(endpoint_map_)) {
return ZX_ERR_OUT_OF_RANGE;
}
- auto* function = endpoint_map_[index];
- if (function ) {
+ auto function = endpoint_map_[index];
+ if (function != nullptr) {
return function->Control(setup, write_buffer, write_size, read_buffer, read_size,
out_read_actual);
}
@@ -703,7 +711,6 @@
void UsbPeripheral::DdkRelease() {
zxlogf(TRACE, "%s\n", __func__);
- delete[] config_desc_;
delete this;
}
@@ -764,14 +771,10 @@
}
#endif // defined(USB_DEVICE_VID) && defined(USB_DEVICE_PID) && defined(USB_DEVICE_FUNCTIONS)
-zx_status_t usb_peripheral_bind(void* ctx, zx_device_t* parent) {
- return UsbPeripheral::Create(parent);
-}
-
static zx_driver_ops_t ops = [](){
zx_driver_ops_t ops = {};
ops.version = DRIVER_OPS_VERSION;
- ops.bind = usb_peripheral_bind;
+ ops.bind = UsbPeripheral::Create;
return ops;
}();
diff --git a/system/dev/usb/usb-peripheral/usb-peripheral.h b/system/dev/usb/usb-peripheral/usb-peripheral.h
index 5ffa2d5..cc72f08 100644
--- a/system/dev/usb/usb-peripheral/usb-peripheral.h
+++ b/system/dev/usb/usb-peripheral/usb-peripheral.h
@@ -5,12 +5,14 @@
#pragma once
#include <ddktl/device.h>
+#include <ddktl/protocol/empty-protocol.h>
#include <ddktl/protocol/usb/dci.h>
#include <ddktl/protocol/usb/function.h>
#include <ddktl/protocol/usb/modeswitch.h>
+#include <fbl/array.h>
#include <fbl/mutex.h>
+#include <fbl/ref_ptr.h>
#include <fbl/string.h>
-#include <fbl/unique_ptr.h>
#include <fbl/vector.h>
#include <fuchsia/hardware/usb/peripheral/c/fidl.h>
@@ -75,12 +77,14 @@
// This is the main class for the USB peripheral role driver.
// It binds against the USB DCI driver device and manages a list of UsbFunction devices,
// one for each USB function in the peripheral role configuration.
-class UsbPeripheral : public UsbPeripheralType, public ddk::UsbDciInterface<UsbPeripheral> {
+class UsbPeripheral : public UsbPeripheralType,
+ public ddk::EmptyProtocol<ZX_PROTOCOL_USB_PERIPHERAL>,
+ public ddk::UsbDciInterface<UsbPeripheral> {
public:
UsbPeripheral(zx_device_t* parent)
: UsbPeripheralType(parent), dci_(parent), ums_(parent) {}
- static zx_status_t Create(zx_device_t* parent);
+ static zx_status_t Create(void* ctx, zx_device_t* parent);
// Device protocol implementation.
zx_status_t DdkMessage(fidl_msg_t* msg, fidl_txn_t* txn);
@@ -103,12 +107,13 @@
zx_status_t MsgGetMode(fidl_txn_t* txn);
zx_status_t MsgSetMode(uint32_t mode, fidl_txn_t* txn);
- zx_status_t SetFunctionInterface(UsbFunction* function,
+ zx_status_t SetFunctionInterface(fbl::RefPtr<UsbFunction> function,
const usb_function_interface_t* interface);
- zx_status_t AllocInterface(UsbFunction* function, uint8_t* out_intf_num);
- zx_status_t AllocEndpoint(UsbFunction* function, uint8_t direction, uint8_t* out_address);
+ zx_status_t AllocInterface(fbl::RefPtr<UsbFunction> function, uint8_t* out_intf_num);
+ zx_status_t AllocEndpoint(fbl::RefPtr<UsbFunction> function, uint8_t direction,
+ uint8_t* out_address);
zx_status_t AllocStringDesc(const char* string, uint8_t* out_index);
- zx_status_t ValidateFunction(UsbFunction* function, void* descriptors, size_t length,
+ zx_status_t ValidateFunction(fbl::RefPtr<UsbFunction> function, void* descriptors, size_t length,
uint8_t* out_num_interfaces);
zx_status_t FunctionRegistered();
@@ -159,21 +164,21 @@
// USB device descriptor set via ioctl_usb_peripheral_set_device_desc()
usb_device_descriptor_t device_desc_ = {};
// USB configuration descriptor, synthesized from our functions' descriptors.
- usb_configuration_descriptor_t* config_desc_ = nullptr;
+ fbl::Array<uint8_t> config_desc_;
// Map from interface number to function.
- UsbFunction* interface_map_[MAX_INTERFACES] = {};
+ fbl::RefPtr<UsbFunction> interface_map_[MAX_INTERFACES];
// Map from endpoint index to function.
- UsbFunction* endpoint_map_[USB_MAX_EPS] = {};
+ fbl::RefPtr<UsbFunction> endpoint_map_[USB_MAX_EPS];
// Strings for USB string descriptors.
fbl::Vector<fbl::String> strings_;
// List of usb_function_t.
- fbl::Vector<fbl::unique_ptr<UsbFunction>> functions_;
+ fbl::Vector<fbl::RefPtr<UsbFunction>> functions_;
// mutex for protecting our state
fbl::Mutex lock_;
// Current USB mode set via ioctl_usb_peripheral_set_mode()
usb_mode_t usb_mode_ = USB_MODE_NONE;
// Our parent's USB mode.
- usb_mode_t dci_usb_mode_ = USB_MODE_NONE;
+ usb_mode_t dci_usb_mode_ = USB_MODE_NONE;
// Set if ioctl_usb_peripheral_bind_functions() has been called
// and we have a complete list of our function.
bool functions_bound_ = false;