[usb-virtual-bus] Use C++ usb::Request library.
Tested: Ran following in QEMu:
usbctl virtual enable
usbctl init-ums
usbctl virtual connect
mkfs /dev/class/block/000 minfs
mkdir /tmp/mnt
mount /dev/class/block/000 /tmp/mnt
kilo /tmp/mnt/foo
(type some text, save and quit)
cat /tmp/mnt/foo
Change-Id: If0f49e6ee8e437776a64428e3f730bbb414b7449
diff --git a/system/dev/lib/usb/include/usb/request-cpp.h b/system/dev/lib/usb/include/usb/request-cpp.h
index 1ef9194..3d2c321 100644
--- a/system/dev/lib/usb/include/usb/request-cpp.h
+++ b/system/dev/lib/usb/include/usb/request-cpp.h
@@ -500,6 +500,13 @@
__UNUSED auto dummy = req.take();
}
+ void push_next(ReqType req) {
+ fbl::AutoLock al(&lock_);
+ auto* node = req.node();
+ queue_.push_back(node);
+ __UNUSED auto dummy = req.take();
+ }
+
std::optional<ReqType> pop() {
fbl::AutoLock al(&lock_);
auto* node = queue_.pop_back();
@@ -509,6 +516,11 @@
return std::nullopt;
}
+ bool is_empty() {
+ fbl::AutoLock al(&lock_);
+ return queue_.is_empty();
+ }
+
// Releases all usb requests stored in the queue.
void release() {
fbl::AutoLock al(&lock_);
diff --git a/system/dev/usb/usb-virtual-bus/usb-virtual-bus.cpp b/system/dev/usb/usb-virtual-bus/usb-virtual-bus.cpp
index 5a04d44..669a158 100644
--- a/system/dev/usb/usb-virtual-bus/usb-virtual-bus.cpp
+++ b/system/dev/usb/usb-virtual-bus/usb-virtual-bus.cpp
@@ -17,7 +17,6 @@
#include <fbl/auto_lock.h>
#include <fbl/unique_ptr.h>
#include <fuchsia/usb/virtualbus/c/fidl.h>
-#include <usb/usb-request.h>
namespace usb_virtual_bus {
@@ -28,18 +27,6 @@
}
static constexpr uint8_t IN_EP_START = 17;
-// Internal context for USB requests, used for both host and peripheral side.
-struct UsbReqInternal {
- // Callback to the upper layer.
- usb_request_complete_t complete_cb;
- // For queueing requests internally.
- list_node_t node;
-};
-
-#define USB_REQ_TO_INTERNAL(req) \
- ((UsbReqInternal *)((uintptr_t)(req) + sizeof(usb_request_t)))
-#define INTERNAL_TO_USB_REQ(ctx) ((usb_request_t *)((uintptr_t)(ctx) - sizeof(usb_request_t)))
-
#define DEVICE_SLOT_ID 0
#define DEVICE_HUB_ID 0
#define DEVICE_SPEED USB_SPEED_HIGH
@@ -94,12 +81,6 @@
}
zx_status_t UsbVirtualBus::Init() {
- for (unsigned i = 0; i < USB_MAX_EPS; i++) {
- usb_virtual_ep_t* ep = &eps_[i];
- list_initialize(&ep->host_reqs);
- list_initialize(&ep->device_reqs);
- }
-
auto status = DdkAdd("usb-virtual-bus", DEVICE_ADD_NON_BINDABLE);
if (status != ZX_OK) {
return status;
@@ -120,123 +101,84 @@
int UsbVirtualBus::Thread() {
while (1) {
- UsbReqInternal* req_int;
- list_node_t completed = LIST_INITIAL_VALUE(completed);
-
sync_completion_wait(&thread_signal_, ZX_TIME_INFINITE);
sync_completion_reset(&thread_signal_);
- lock_.Acquire();
-
- if (unbinding_) {
+ bool unbinding;
+ {
+ fbl::AutoLock al(&lock_);
+ unbinding = unbinding_;
+ }
+ if (unbinding) {
for (unsigned i = 0; i < USB_MAX_EPS; i++) {
usb_virtual_ep_t* ep = &eps_[i];
- while ((req_int = list_remove_head_type(&ep->host_reqs, UsbReqInternal,
- node)) != nullptr) {
- list_add_tail(&completed, &req_int->node);
+ for (auto req = ep->host_reqs.pop(); req; req = ep->host_reqs.pop()) {
+ req->Complete(ZX_ERR_IO_NOT_PRESENT, 0);
}
- while ((req_int = list_remove_head_type(&ep->device_reqs, UsbReqInternal,
- node)) != nullptr) {
- list_add_tail(&completed, &req_int->node);
+ for (auto req = ep->device_reqs.pop(); req; req = ep->device_reqs.pop()) {
+ req->Complete(ZX_ERR_IO_NOT_PRESENT, 0);
}
}
- lock_.Release();
-
- // Complete requests outside of the lock to avoid deadlock.
- while ((req_int = list_remove_head_type(&completed, UsbReqInternal, node))
- != nullptr) {
- usb_request_t* req = INTERNAL_TO_USB_REQ(req_int);
- usb_request_complete(req, ZX_ERR_IO_NOT_PRESENT, 0, &req_int->complete_cb);
- }
-
return 0;
}
// special case endpoint zero
- while ((req_int = list_remove_head_type(&eps_[0].host_reqs, UsbReqInternal, node))
- != nullptr) {
- lock_.Release();
+ for (auto request = eps_[0].host_reqs.pop(); request; request = eps_[0].host_reqs.pop()) {
// Handle control requests outside of the lock to avoid deadlock.
- HandleControl(INTERNAL_TO_USB_REQ(req_int));
- lock_.Acquire();
+ HandleControl(std::move(*request));
}
for (unsigned i = 1; i < USB_MAX_EPS; i++) {
usb_virtual_ep_t* ep = &eps_[i];
bool out = (i < IN_EP_START);
- while ((req_int = list_peek_head_type(&ep->host_reqs, UsbReqInternal, node))
- != nullptr) {
- UsbReqInternal* device_req_int;
- device_req_int = list_remove_head_type(&ep->device_reqs, UsbReqInternal, node);
+ while (!ep->host_reqs.is_empty() && !ep->device_reqs.is_empty()) {
+ auto device_req = ep->device_reqs.pop();
+ auto req = ep->host_reqs.pop();
- if (device_req_int) {
- usb_request_t* req = INTERNAL_TO_USB_REQ(req_int);
- usb_request_t* device_req = INTERNAL_TO_USB_REQ(device_req_int);
- zx_off_t offset = ep->req_offset;
- size_t length = req->header.length - offset;
- if (length > device_req->header.length) {
- length = device_req->header.length;
- }
-
- void* device_buffer;
- auto status = usb_request_mmap(device_req, &device_buffer);
- if (status != ZX_OK) {
- zxlogf(ERROR, "%s: usb_request_mmap failed: %d\n", __func__, status);
- req->response.status = status;
- device_req->response.status = status;
- list_add_tail(&completed, &device_req_int->node);
- list_add_tail(&completed, &req_int->node);
- continue;
- }
-
- if (out) {
- usb_request_copy_from(req, device_buffer, length, offset);
- } else {
- usb_request_copy_to(req, device_buffer, length, offset);
- }
-
- device_req->response.status = ZX_OK;
- device_req->response.actual = length;
- list_add_tail(&completed, &device_req_int->node);
-
- offset += length;
- if (offset == req->header.length ||
- // Short packet in the IN direction signals end of transfer.
- (!out && device_req->header.length < ep->max_packet_size)) {
- list_delete(&req_int->node);
- usb_request_t* req = INTERNAL_TO_USB_REQ(req_int);
- req->response.status = ZX_OK;
- req->response.actual = length;
- list_add_tail(&completed, &req_int->node);
- ep->req_offset = 0;
- } else {
- ep->req_offset = offset;
- }
- } else {
- break;
+ zx_off_t offset = ep->req_offset;
+ size_t length = req->request()->header.length - offset;
+ if (length > device_req->request()->header.length) {
+ length = device_req->request()->header.length;
}
+
+ void* device_buffer;
+ auto status = device_req->Mmap(&device_buffer);
+ if (status != ZX_OK) {
+ zxlogf(ERROR, "%s: usb_request_mmap failed: %d\n", __func__, status);
+ req->Complete(status, 0);
+ device_req->Complete(status, 0);
+ continue;
+ }
+
+ if (out) {
+ req->CopyFrom(device_buffer, length, offset);
+ } else {
+ req->CopyTo(device_buffer, length, offset);
+ }
+
+ offset += length;
+ if (offset == req->request()->header.length ||
+ // Short packet in the IN direction signals end of transfer.
+ (!out && device_req->request()->header.length < ep->max_packet_size)) {
+ req->Complete(ZX_OK, length);
+ ep->req_offset = 0;
+ } else {
+ ep->req_offset = offset;
+ ep->host_reqs.push_next(std::move(*req));
+ }
+
+ device_req->Complete(ZX_OK, length);
}
}
-
- lock_.Release();
-
- // Complete requests outside of the lock to avoid deadlock.
- while ((req_int = list_remove_head_type(&completed, UsbReqInternal, node))
- != nullptr) {
- usb_request_t* req = INTERNAL_TO_USB_REQ(req_int);
- usb_request_complete(req, req->response.status, req->response.actual,
- &req_int->complete_cb);
- }
}
return 0;
}
-void UsbVirtualBus::HandleControl(usb_request_t* req) {
- const usb_setup_t* setup = &req->setup;
- auto* req_int = USB_REQ_TO_INTERNAL(req);
+void UsbVirtualBus::HandleControl(Request request) {
+ const usb_setup_t* setup = &request.request()->setup;
zx_status_t status;
size_t length = le16toh(setup->wLength);
size_t actual = 0;
@@ -249,10 +191,10 @@
void* buffer = nullptr;
if (length > 0) {
- auto status = usb_request_mmap(req, &buffer);
+ auto status = request.Mmap(&buffer);
if (status != ZX_OK) {
zxlogf(ERROR, "%s: usb_request_mmap failed: %d\n", __func__, status);
- usb_request_complete(req, status, 0, &req_int->complete_cb);
+ request.Complete(status, 0);
return;
}
}
@@ -266,7 +208,7 @@
status = ZX_ERR_UNAVAILABLE;
}
- usb_request_complete(req, status, actual, &req_int->complete_cb);
+ request.Complete(status, actual);
}
void UsbVirtualBus::SetConnected(bool connected) {
@@ -291,30 +233,16 @@
dci_intf_.SetConnected(false);
}
- UsbReqInternal* req_int;
- list_node_t completed = LIST_INITIAL_VALUE(completed);
- {
- fbl::AutoLock lock(&lock_);
+ for (unsigned i = 0; i < USB_MAX_EPS; i++) {
+ usb_virtual_ep_t* ep = &eps_[i];
- for (unsigned i = 0; i < USB_MAX_EPS; i++) {
- usb_virtual_ep_t* ep = &eps_[i];
-
- while ((req_int = list_remove_head_type(&ep->host_reqs, UsbReqInternal,
- node)) != nullptr) {
- list_add_tail(&completed, &req_int->node);
- }
- while ((req_int = list_remove_head_type(&ep->device_reqs, UsbReqInternal,
- node)) != nullptr) {
- list_add_tail(&completed, &req_int->node);
- }
+ for (auto req = ep->host_reqs.pop(); req; req = ep->host_reqs.pop()) {
+ req->Complete(ZX_ERR_IO_NOT_PRESENT, 0);
}
- }
-
- while ((req_int = list_remove_head_type(&completed, UsbReqInternal, node))
- != nullptr) {
- usb_request_t* req = INTERNAL_TO_USB_REQ(req_int);
- usb_request_complete(req, ZX_ERR_IO_NOT_PRESENT, 0, &req_int->complete_cb);
+ for (auto req = ep->device_reqs.pop(); req; req = ep->device_reqs.pop()) {
+ req->Complete(ZX_ERR_IO_NOT_PRESENT, 0);
+ }
}
}
}
@@ -325,7 +253,7 @@
return ZX_ERR_INVALID_ARGS;
}
- UsbReqInternal* req_int = nullptr;
+ std::optional<Request> req = std::nullopt;
{
fbl::AutoLock lock(&lock_);
@@ -333,13 +261,12 @@
ep->stalled = stall;
if (stall) {
- req_int = list_remove_head_type(&ep->host_reqs, UsbReqInternal, node);
+ req = ep->host_reqs.pop();
}
}
- if (req_int) {
- usb_request_t* req = INTERNAL_TO_USB_REQ(req_int);
- usb_request_complete(req, ZX_ERR_IO_REFUSED, 0, &req_int->complete_cb);
+ if (req) {
+ req->Complete(ZX_ERR_IO_REFUSED, 0);
}
return ZX_OK;
@@ -384,24 +311,25 @@
void UsbVirtualBus::UsbDciRequestQueue(usb_request_t* req,
const usb_request_complete_t* complete_cb) {
- auto* req_int = USB_REQ_TO_INTERNAL(req);
- req_int->complete_cb = *complete_cb;
+ Request request(req, *complete_cb, sizeof(usb_request_t));
- uint8_t index = EpAddressToIndex(req->header.ep_address);
+ uint8_t index = EpAddressToIndex(request.request()->header.ep_address);
if (index == 0 || index >= USB_MAX_EPS) {
- printf("%s: bad endpoint %u\n", __func__, req->header.ep_address);
- usb_request_complete(req, ZX_ERR_INVALID_ARGS, 0, complete_cb);
+ printf("%s: bad endpoint %u\n", __func__, request.request()->header.ep_address);
+ request.Complete(ZX_ERR_INVALID_ARGS, 0);
return;
}
- lock_.Acquire();
- if (!connected_) {
- lock_.Release();
- usb_request_complete(req, ZX_ERR_IO_NOT_PRESENT, 0, complete_cb);
+ bool connected;
+ {
+ fbl::AutoLock al(&lock_);
+ connected = connected_;
+ }
+ if (!connected) {
+ request.Complete(ZX_ERR_IO_NOT_PRESENT, 0);
return;
}
- list_add_tail(&eps_[index].device_reqs, &req_int->node);
- lock_.Release();
+ eps_[index].device_reqs.push(std::move(request));
sync_completion_signal(&thread_signal_);
}
@@ -440,37 +368,38 @@
}
size_t UsbVirtualBus::UsbDciGetRequestSize() {
- return sizeof(usb_request_t) + sizeof(UsbReqInternal);
+ return Request::RequestSize(sizeof(usb_request_t));
}
void UsbVirtualBus::UsbHciRequestQueue(usb_request_t* req,
const usb_request_complete_t* complete_cb) {
- auto* req_int = USB_REQ_TO_INTERNAL(req);
- req_int->complete_cb = *complete_cb;
+ Request request(req, *complete_cb, sizeof(usb_request_t));
- uint8_t index = EpAddressToIndex(req->header.ep_address);
+ uint8_t index = EpAddressToIndex(request.request()->header.ep_address);
if (index >= USB_MAX_EPS) {
- printf("usb_virtual_bus_host_queue bad endpoint %u\n", req->header.ep_address);
- usb_request_complete(req, ZX_ERR_INVALID_ARGS, 0, complete_cb);
+ printf("usb_virtual_bus_host_queue bad endpoint %u\n",
+ request.request()->header.ep_address);
+ request.Complete(ZX_ERR_INVALID_ARGS, 0);
return;
}
- lock_.Acquire();
- if (!connected_) {
- lock_.Release();
- usb_request_complete(req, ZX_ERR_IO_NOT_PRESENT, 0, complete_cb);
+ bool connected;
+ {
+ fbl::AutoLock al(&lock_);
+ connected = connected_;
+ }
+ if (!connected) {
+ request.Complete(ZX_ERR_IO_NOT_PRESENT, 0);
return;
}
usb_virtual_ep_t* ep = &eps_[index];
if (ep->stalled) {
- lock_.Release();
- usb_request_complete(req, ZX_ERR_IO_REFUSED, 0, complete_cb);
+ request.Complete(ZX_ERR_IO_REFUSED, 0);
return;
}
- list_add_tail(&ep->host_reqs, &req_int->node);
- lock_.Release();
+ ep->host_reqs.push(std::move(request));
sync_completion_signal(&thread_signal_);
}
@@ -479,9 +408,11 @@
if (bus_intf) {
bus_intf_ = ddk::UsbBusInterfaceClient(bus_intf);
- lock_.Acquire();
- bool connected = connected_;
- lock_.Release();
+ bool connected;
+ {
+ fbl::AutoLock al(&lock_);
+ connected = connected_;
+ }
if (connected) {
bus_intf_.AddDevice(DEVICE_SLOT_ID, DEVICE_HUB_ID, DEVICE_SPEED);
@@ -541,7 +472,7 @@
}
size_t UsbVirtualBus::UsbHciGetRequestSize() {
- return sizeof(usb_request_t) + sizeof(UsbReqInternal);
+ return Request::RequestSize(sizeof(usb_request_t));
}
zx_status_t UsbVirtualBus::MsgEnable(fidl_txn_t* txn) {
diff --git a/system/dev/usb/usb-virtual-bus/usb-virtual-bus.h b/system/dev/usb/usb-virtual-bus/usb-virtual-bus.h
index d4e7399..fe8bc6a 100644
--- a/system/dev/usb/usb-virtual-bus/usb-virtual-bus.h
+++ b/system/dev/usb/usb-virtual-bus/usb-virtual-bus.h
@@ -12,6 +12,7 @@
#include <fbl/mutex.h>
#include <fbl/unique_ptr.h>
#include <lib/sync/completion.h>
+#include <usb/request-cpp.h>
#include <threads.h>
@@ -75,10 +76,13 @@
private:
DISALLOW_COPY_ASSIGN_AND_MOVE(UsbVirtualBus);
+ using Request = usb::UnownedRequest<void>;
+ using RequestQueue = usb::UnownedRequestQueue<void>;
+
// This struct represents an endpoint on the virtual device.
struct usb_virtual_ep_t {
- list_node_t host_reqs __TA_GUARDED(lock_);
- list_node_t device_reqs __TA_GUARDED(lock_);
+ RequestQueue host_reqs;
+ RequestQueue device_reqs;
uint16_t max_packet_size = 0;
// Offset into current host req, for dealing with host reqs that are bigger than
// their matching device req.
@@ -91,7 +95,7 @@
zx_status_t CreateHost();
void SetConnected(bool connected);
int Thread();
- void HandleControl(usb_request_t* req);
+ void HandleControl(Request req);
zx_status_t SetStall(uint8_t ep_address, bool stall);
// Reference to class that implements the virtual device controller protocol.