From a742f055325981da87fb4379fbf47df07d235a28 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Fri, 14 May 2021 22:47:43 +0200 Subject: [PATCH] usb/hv: add second CDC ACM interface for virtualized UART Signed-off-by: Janne Grunau --- proxyclient/hv.py | 2 +- proxyclient/proxy.py | 6 +- src/hv.h | 3 +- src/hv_vuart.c | 16 +-- src/iodev.c | 8 +- src/iodev.h | 10 +- src/proxy.c | 2 +- src/usb.c | 63 ++++++++++- src/usb_dwc3.c | 262 +++++++++++++++++++++++++++++++++++-------- src/usb_dwc3.h | 18 ++- 10 files changed, 313 insertions(+), 77 deletions(-) diff --git a/proxyclient/hv.py b/proxyclient/hv.py index 7e294c72..f123cd43 100644 --- a/proxyclient/hv.py +++ b/proxyclient/hv.py @@ -443,7 +443,7 @@ class HV: self.u.msr(APVMKEYHI_EL2, 0x697665596F755570) self.u.msr(APSTS_EL12, 1) - #self.p.hv_map_vuart(0x2_35200000) + #self.p.hv_map_vuart(0x2_35200000, getattr(IODEV, self.iodev.name + "_SEC")) actlr = ACTLR(self.u.mrs(ACTLR_EL12)) actlr.EnMDSB = 1 diff --git a/proxyclient/proxy.py b/proxyclient/proxy.py index 866f882d..dacce173 100755 --- a/proxyclient/proxy.py +++ b/proxyclient/proxy.py @@ -370,6 +370,8 @@ class IODEV(IntEnum): FB = 1 USB0 = 2 USB1 = 3 + USB0_SEC = 4 + USB1_SEC = 5 class USAGE(IntFlag): CONSOLE = (1 << 0) @@ -850,8 +852,8 @@ class M1N1Proxy: return self.request(self.P_HV_TRANSLATE, addr, s1, w) def hv_pt_walk(self, addr): return self.request(self.P_HV_PT_WALK, addr) - def hv_map_vuart(self, base): - return self.request(self.P_HV_MAP_VUART, base) + def hv_map_vuart(self, base, iodev): + return self.request(self.P_HV_MAP_VUART, base, iodev) def fb_init(self): return self.request(self.P_FB_INIT) diff --git a/src/hv.h b/src/hv.h index 23c8ad22..459657ee 100644 --- a/src/hv.h +++ b/src/hv.h @@ -3,6 +3,7 @@ #ifndef HV_H #define HV_H +#include "iodev.h" #include "types.h" typedef bool(hv_hook_t)(u64 addr, u64 *val, bool write, int width); @@ -19,7 +20,7 @@ u64 hv_pt_walk(u64 addr); bool hv_handle_dabort(u64 *regs); /* Virtual peripherals */ -void hv_map_vuart(u64 base); +void hv_map_vuart(u64 base, iodev_id_t iodev); /* HV main */ void hv_init(void); diff --git a/src/hv_vuart.c b/src/hv_vuart.c index b4315555..af94c1de 100644 --- a/src/hv_vuart.c +++ b/src/hv_vuart.c @@ -1,26 +1,21 @@ /* SPDX-License-Identifier: MIT */ #include "hv.h" -#include "iodev.h" #include "uart_regs.h" +static iodev_id_t vuart_iodev; + bool handle_vuart(u64 addr, u64 *val, bool write, int width) { UNUSED(width); - static bool newline = true; addr &= 0xfff; if (write) { switch (addr) { case UTXH: { uint8_t b = *val; - if (newline) { - iodev_console_write("EL1> ", 5); - newline = false; - } - if (b == '\n') - newline = true; - iodev_console_write(&b, 1); + if (iodev_can_write(vuart_iodev)) + iodev_write(vuart_iodev, &b, 1); break; } } @@ -40,7 +35,8 @@ bool handle_vuart(u64 addr, u64 *val, bool write, int width) return true; } -void hv_map_vuart(u64 base) +void hv_map_vuart(u64 base, iodev_id_t iodev) { hv_map_hook(base, handle_vuart, 0x1000); + vuart_iodev = iodev; } diff --git a/src/iodev.c b/src/iodev.c index f32c0ceb..52f0590b 100644 --- a/src/iodev.c +++ b/src/iodev.c @@ -18,12 +18,12 @@ extern struct iodev iodev_uart; extern struct iodev iodev_fb; extern struct iodev iodev_usb[]; +extern struct iodev iodev_usb_sec[]; struct iodev *iodevs[IODEV_MAX] = { - &iodev_uart, - &iodev_fb, - &iodev_usb[0], - &iodev_usb[1], + [IODEV_UART] = &iodev_uart, [IODEV_FB] = &iodev_fb, + [IODEV_USB0] = &iodev_usb[0], [IODEV_USB1] = &iodev_usb[1], + [IODEV_USB0_SEC] = &iodev_usb_sec[0], [IODEV_USB1_SEC] = &iodev_usb_sec[1], }; char con_buf[CONSOLE_BUFFER_SIZE]; diff --git a/src/iodev.h b/src/iodev.h index 2bcfa069..7cee8b15 100644 --- a/src/iodev.h +++ b/src/iodev.h @@ -6,7 +6,15 @@ #include "types.h" #include "utils.h" -typedef enum _iodev_id_t { IODEV_UART, IODEV_FB, IODEV_USB0, IODEV_USB1, IODEV_MAX } iodev_id_t; +typedef enum _iodev_id_t { + IODEV_UART, + IODEV_FB, + IODEV_USB0, + IODEV_USB1, + IODEV_USB0_SEC, + IODEV_USB1_SEC, + IODEV_MAX, +} iodev_id_t; typedef enum _iodev_usage_t { USAGE_CONSOLE = BIT(0), diff --git a/src/proxy.c b/src/proxy.c index 207e3999..69137239 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -416,7 +416,7 @@ int proxy_process(ProxyRequest *request, ProxyReply *reply) reply->retval = hv_pt_walk(request->args[0]); break; case P_HV_MAP_VUART: - hv_map_vuart(request->args[0]); + hv_map_vuart(request->args[0], request->args[1]); break; case P_FB_INIT: diff --git a/src/usb.c b/src/usb.c index 66246f98..f10f3737 100644 --- a/src/usb.c +++ b/src/usb.c @@ -149,12 +149,49 @@ dwc3_dev_t *usb_bringup(u32 idx) return usb_dwc3_init(usb_regs.drd_regs, usb_dart); } +#define USB_IODEV_WRAPPER(name, pipe) \ + static bool usb_##name##_can_read(void *dev) \ + { \ + return usb_dwc3_can_read(dev, pipe); \ + } \ + \ + static bool usb_##name##_can_write(void *dev) \ + { \ + return usb_dwc3_can_write(dev, pipe); \ + } \ + \ + static ssize_t usb_##name##_read(void *dev, void *buf, size_t count) \ + { \ + return usb_dwc3_read(dev, pipe, buf, count); \ + } \ + \ + static ssize_t usb_##name##_write(void *dev, const void *buf, size_t count) \ + { \ + return usb_dwc3_write(dev, pipe, buf, count); \ + } \ + \ + static void usb_##name##_handle_events(void *dev) \ + { \ + usb_dwc3_handle_events(dev); \ + } + +USB_IODEV_WRAPPER(0, CDC_ACM_PIPE_0) +USB_IODEV_WRAPPER(1, CDC_ACM_PIPE_1) + static struct iodev_ops iodev_usb_ops = { - .can_read = (bool (*)(void *))usb_dwc3_can_read, - .can_write = (bool (*)(void *))usb_dwc3_can_write, - .read = (ssize_t(*)(void *, void *, size_t))usb_dwc3_read, - .write = (ssize_t(*)(void *, const void *, size_t))usb_dwc3_write, - .handle_events = (void (*)(void *))usb_dwc3_handle_events, + .can_read = usb_0_can_read, + .can_write = usb_0_can_write, + .read = usb_0_read, + .write = usb_0_write, + .handle_events = usb_0_handle_events, +}; + +static struct iodev_ops iodev_usb_sec_ops = { + .can_read = usb_1_can_read, + .can_write = usb_1_can_write, + .read = usb_1_read, + .write = usb_1_write, + .handle_events = usb_1_handle_events, }; struct iodev iodev_usb[USB_INSTANCES] = { @@ -168,6 +205,17 @@ struct iodev iodev_usb[USB_INSTANCES] = { }, }; +struct iodev iodev_usb_sec[USB_INSTANCES] = { + { + .ops = &iodev_usb_sec_ops, + .usage = 0, + }, + { + .ops = &iodev_usb_sec_ops, + .usage = 0, + }, +}; + void usb_init(void) { for (int i = 0; i < USB_INSTANCES; i++) { @@ -175,6 +223,8 @@ void usb_init(void) if (!iodev_usb[i].opaque) continue; + iodev_usb_sec[i].opaque = iodev_usb[i].opaque; + printf("USB%d: initialized at %p\n", i, iodev_usb[i].opaque); } } @@ -187,5 +237,8 @@ void usb_shutdown(void) printf("USB%d: shutdown\n", i); usb_dwc3_shutdown(iodev_usb[i].opaque); + + iodev_usb[i].opaque = NULL; + iodev_usb_sec[i].opaque = NULL; } } diff --git a/src/usb_dwc3.c b/src/usb_dwc3.c index b7b54cd8..1741cb1b 100644 --- a/src/usb_dwc3.c +++ b/src/usb_dwc3.c @@ -65,6 +65,13 @@ #define USB_LEP_CDC_BULK_OUT 4 #define USB_LEP_CDC_BULK_IN 5 +/* maps to interrupt endpoint 0x83 */ +#define USB_LEP_CDC_INTR_IN_2 7 + +/* these map to physical endpoints 0x04 and 0x84 */ +#define USB_LEP_CDC_BULK_OUT_2 8 +#define USB_LEP_CDC_BULK_IN_2 9 + /* content doesn't matter at all, this is the setting linux writes by default */ static const u8 cdc_default_line_coding[] = {0x80, 0x25, 0x00, 0x00, 0x00, 0x00, 0x08}; @@ -112,8 +119,13 @@ typedef struct dwc3_dev { /* USB ACM CDC serial */ u8 cdc_line_coding[7]; - ringbuffer_t *host2device; - ringbuffer_t *device2host; + struct { + ringbuffer_t *host2device; + ringbuffer_t *device2host; + u8 ep_intr; + u8 ep_in; + u8 ep_out; + } pipe[CDC_ACM_PIPE_MAX]; bool ready; } dwc3_dev_t; @@ -138,6 +150,12 @@ struct cdc_dev_desc { const struct usb_interface_descriptor interface_data; const struct usb_endpoint_descriptor endpoint_data_in; const struct usb_endpoint_descriptor endpoint_data_out; + const struct usb_interface_descriptor sec_interface_management; + const struct cdc_union_functional_descriptor sec_cdc_union_func; + const struct usb_endpoint_descriptor sec_endpoint_notification; + const struct usb_interface_descriptor sec_interface_data; + const struct usb_endpoint_descriptor sec_endpoint_data_in; + const struct usb_endpoint_descriptor sec_endpoint_data_out; } PACKED; static const struct usb_device_descriptor usb_cdc_device_descriptor = { @@ -163,7 +181,7 @@ static const struct cdc_dev_desc cdc_configuration_descriptor = { .bLength = sizeof(cdc_configuration_descriptor.configuration), .bDescriptorType = USB_CONFIGURATION_DESCRIPTOR, .wTotalLength = sizeof(cdc_configuration_descriptor), - .bNumInterfaces = 2, + .bNumInterfaces = 4, .bConfigurationValue = 1, .iConfiguration = 0, .bmAttributes = USB_CONFIGURATION_ATTRIBUTE_RES1 | USB_CONFIGURATION_SELF_POWERED, @@ -236,6 +254,77 @@ static const struct cdc_dev_desc cdc_configuration_descriptor = { .wMaxPacketSize = 512, .bInterval = 10, }, + + /* + * CDC ACM interface for virtual uart + */ + + .sec_interface_management = + { + .bLength = sizeof(cdc_configuration_descriptor.sec_interface_management), + .bDescriptorType = USB_INTERFACE_DESCRIPTOR, + .bInterfaceNumber = 2, + .bAlternateSetting = 0, + .bNumEndpoints = 1, + .bInterfaceClass = CDC_INTERFACE_CLASS, + .bInterfaceSubClass = CDC_INTERFACE_SUBCLASS_ACM, + .bInterfaceProtocol = CDC_INTERFACE_PROTOCOL_NONE, + .iInterface = 0, + + }, + .sec_cdc_union_func = + { + .bFunctionLength = sizeof(cdc_configuration_descriptor.sec_cdc_union_func), + .bDescriptorType = USB_CDC_INTERFACE_FUNCTIONAL_DESCRIPTOR, + .bDescriptorSubtype = USB_CDC_UNION_SUBTYPE, + .bControlInterface = 2, + .bDataInterface = 3, + }, + /* + * we never use this endpoint, but it should exist and always be idle. + * it needs to exist in the descriptor though to make hosts correctly recognize + * us as a ACM CDC device. + */ + .sec_endpoint_notification = + { + .bLength = sizeof(cdc_configuration_descriptor.sec_endpoint_notification), + .bDescriptorType = USB_ENDPOINT_DESCRIPTOR, + .bEndpointAddress = USB_ENDPOINT_ADDR_IN(3), + .bmAttributes = USB_ENDPOINT_ATTR_TYPE_INTERRUPT, + .wMaxPacketSize = 64, + .bInterval = 10, + + }, + .sec_interface_data = + { + .bLength = sizeof(cdc_configuration_descriptor.sec_interface_data), + .bDescriptorType = USB_INTERFACE_DESCRIPTOR, + .bInterfaceNumber = 3, + .bAlternateSetting = 0, + .bNumEndpoints = 2, + .bInterfaceClass = CDC_INTERFACE_CLASS_DATA, + .bInterfaceSubClass = 0, // unused + .bInterfaceProtocol = 0, // unused + .iInterface = 0, + }, + .sec_endpoint_data_in = + { + .bLength = sizeof(cdc_configuration_descriptor.sec_endpoint_data_in), + .bDescriptorType = USB_ENDPOINT_DESCRIPTOR, + .bEndpointAddress = USB_ENDPOINT_ADDR_OUT(4), + .bmAttributes = USB_ENDPOINT_ATTR_TYPE_BULK, + .wMaxPacketSize = 512, + .bInterval = 10, + }, + .sec_endpoint_data_out = + { + .bLength = sizeof(cdc_configuration_descriptor.sec_endpoint_data_out), + .bDescriptorType = USB_ENDPOINT_DESCRIPTOR, + .bEndpointAddress = USB_ENDPOINT_ADDR_IN(4), + .bmAttributes = USB_ENDPOINT_ATTR_TYPE_BULK, + .wMaxPacketSize = 512, + .bInterval = 10, + }, }; static const struct usb_device_qualifier_descriptor usb_cdc_device_qualifier_descriptor = { @@ -508,6 +597,9 @@ static void usb_dwc3_ep0_handle_standard_device(dwc3_dev_t *dev, clear32(dev->regs + DWC3_DALEPENA, DWC3_DALEPENA_EP(USB_LEP_CDC_BULK_OUT)); clear32(dev->regs + DWC3_DALEPENA, DWC3_DALEPENA_EP(USB_LEP_CDC_BULK_IN)); clear32(dev->regs + DWC3_DALEPENA, DWC3_DALEPENA_EP(USB_LEP_CDC_INTR_IN)); + clear32(dev->regs + DWC3_DALEPENA, DWC3_DALEPENA_EP(USB_LEP_CDC_BULK_OUT_2)); + clear32(dev->regs + DWC3_DALEPENA, DWC3_DALEPENA_EP(USB_LEP_CDC_BULK_IN_2)); + clear32(dev->regs + DWC3_DALEPENA, DWC3_DALEPENA_EP(USB_LEP_CDC_INTR_IN_2)); dev->ep0_state = USB_DWC3_EP0_STATE_DATA_SEND_STATUS; dev->ready = false; break; @@ -517,6 +609,9 @@ static void usb_dwc3_ep0_handle_standard_device(dwc3_dev_t *dev, set32(dev->regs + DWC3_DALEPENA, DWC3_DALEPENA_EP(USB_LEP_CDC_BULK_OUT)); set32(dev->regs + DWC3_DALEPENA, DWC3_DALEPENA_EP(USB_LEP_CDC_BULK_IN)); set32(dev->regs + DWC3_DALEPENA, DWC3_DALEPENA_EP(USB_LEP_CDC_INTR_IN)); + set32(dev->regs + DWC3_DALEPENA, DWC3_DALEPENA_EP(USB_LEP_CDC_BULK_OUT_2)); + set32(dev->regs + DWC3_DALEPENA, DWC3_DALEPENA_EP(USB_LEP_CDC_BULK_IN_2)); + set32(dev->regs + DWC3_DALEPENA, DWC3_DALEPENA_EP(USB_LEP_CDC_INTR_IN_2)); dev->ep0_state = USB_DWC3_EP0_STATE_DATA_SEND_STATUS; break; default: @@ -733,6 +828,22 @@ static void usb_dwc3_ep0_handle_xfer_not_ready(dwc3_dev_t *dev, } } +ringbuffer_t *usb_dwc3_cdc_get_ringbuffer(dwc3_dev_t *dev, u8 endpoint_number) +{ + switch (endpoint_number) { + case USB_LEP_CDC_BULK_IN: + return dev->pipe[CDC_ACM_PIPE_0].device2host; + case USB_LEP_CDC_BULK_OUT: + return dev->pipe[CDC_ACM_PIPE_0].host2device; + case USB_LEP_CDC_BULK_IN_2: + return dev->pipe[CDC_ACM_PIPE_1].device2host; + case USB_LEP_CDC_BULK_OUT_2: + return dev->pipe[CDC_ACM_PIPE_1].host2device; + default: + return NULL; + } +} + static void usb_dwc3_cdc_start_bulk_out_xfer(dwc3_dev_t *dev, u8 endpoint_number) { struct dwc3_trb *trb; @@ -741,7 +852,11 @@ static void usb_dwc3_cdc_start_bulk_out_xfer(dwc3_dev_t *dev, u8 endpoint_number if (dev->endpoints[endpoint_number].xfer_in_progress) return; - if (ringbuffer_get_free(dev->host2device) < 512) + ringbuffer_t *host2device = usb_dwc3_cdc_get_ringbuffer(dev, endpoint_number); + if (!host2device) + return; + + if (ringbuffer_get_free(host2device) < 512) return; memset(dev->endpoints[endpoint_number].xfer_buffer, 0xaa, 512); @@ -761,8 +876,11 @@ static void usb_dwc3_cdc_start_bulk_in_xfer(dwc3_dev_t *dev, u8 endpoint_number) if (dev->endpoints[endpoint_number].xfer_in_progress) return; - size_t len = - ringbuffer_read(dev->endpoints[endpoint_number].xfer_buffer, 512, dev->device2host); + ringbuffer_t *device2host = usb_dwc3_cdc_get_ringbuffer(dev, endpoint_number); + if (!device2host) + return; + + size_t len = ringbuffer_read(dev->endpoints[endpoint_number].xfer_buffer, 512, device2host); if (!len) return; @@ -778,9 +896,12 @@ static void usb_dwc3_cdc_start_bulk_in_xfer(dwc3_dev_t *dev, u8 endpoint_number) static void usb_dwc3_cdc_handle_bulk_out_xfer_done(dwc3_dev_t *dev, const struct dwc3_event_depevt event) { - size_t len = min(512, ringbuffer_get_free(dev->host2device)); + ringbuffer_t *host2device = usb_dwc3_cdc_get_ringbuffer(dev, event.endpoint_number); + if (!host2device) + return; + size_t len = min(512, ringbuffer_get_free(host2device)); ringbuffer_write(dev->endpoints[event.endpoint_number].xfer_buffer, - len - dev->endpoints[event.endpoint_number].trb->size, dev->host2device); + len - dev->endpoints[event.endpoint_number].trb->size, host2device); } static void usb_dwc3_handle_event_ep(dwc3_dev_t *dev, const struct dwc3_event_depevt event) @@ -792,11 +913,14 @@ static void usb_dwc3_handle_event_ep(dwc3_dev_t *dev, const struct dwc3_event_de case USB_LEP_CTRL_IN: case USB_LEP_CTRL_OUT: return usb_dwc3_ep0_handle_xfer_done(dev, event); - case USB_LEP_CDC_INTR_IN: + case USB_LEP_CDC_INTR_IN: // [[fallthrough]] + case USB_LEP_CDC_INTR_IN_2: return; - case USB_LEP_CDC_BULK_IN: + case USB_LEP_CDC_BULK_IN: // [[fallthrough]] + case USB_LEP_CDC_BULK_IN_2: return; - case USB_LEP_CDC_BULK_OUT: + case USB_LEP_CDC_BULK_OUT: // [[fallthrough]] + case USB_LEP_CDC_BULK_OUT_2: return usb_dwc3_cdc_handle_bulk_out_xfer_done(dev, event); } } else if (event.endpoint_event == DWC3_DEPEVT_XFERNOTREADY) { @@ -811,11 +935,14 @@ static void usb_dwc3_handle_event_ep(dwc3_dev_t *dev, const struct dwc3_event_de case USB_LEP_CTRL_IN: case USB_LEP_CTRL_OUT: return usb_dwc3_ep0_handle_xfer_not_ready(dev, event); - case USB_LEP_CDC_INTR_IN: + case USB_LEP_CDC_INTR_IN: // [[fallthrough]] + case USB_LEP_CDC_INTR_IN_2: return; - case USB_LEP_CDC_BULK_IN: + case USB_LEP_CDC_BULK_IN: // [[fallthrough]] + case USB_LEP_CDC_BULK_IN_2: return usb_dwc3_cdc_start_bulk_in_xfer(dev, event.endpoint_number); - case USB_LEP_CDC_BULK_OUT: + case USB_LEP_CDC_BULK_OUT: // [[fallthrough]] + case USB_LEP_CDC_BULK_OUT_2: return usb_dwc3_cdc_start_bulk_out_xfer(dev, event.endpoint_number); } } @@ -924,13 +1051,6 @@ dwc3_dev_t *usb_dwc3_init(uintptr_t regs, dart_dev_t *dart) dev->regs = regs; dev->dart = dart; - dev->host2device = ringbuffer_alloc(CDC_BUFFER_SIZE); - if (!dev->host2device) - goto error; - dev->device2host = ringbuffer_alloc(CDC_BUFFER_SIZE); - if (!dev->device2host) - goto error; - /* allocate and map dma buffers */ dev->evtbuffer = memalign(SZ_16K, max(DWC3_EVENT_BUFFERS_SIZE, SZ_16K)); if (!dev->evtbuffer) @@ -1033,15 +1153,34 @@ dwc3_dev_t *usb_dwc3_init(uintptr_t regs, dart_dev_t *dart) if (usb_dwc3_ep_configure(dev, USB_LEP_CTRL_IN, DWC3_DEPCMD_TYPE_CONTROL, 64)) goto error; - /* prepare INTR endpoint so that we don't have to reconfigure this device later */ - if (usb_dwc3_ep_configure(dev, USB_LEP_CDC_INTR_IN, DWC3_DEPCMD_TYPE_INTR, 64)) - goto error; + /* prepare CDC ACM interfaces */ - /* prepare BULK endpoints so that we don't have to reconfigure this device later */ - if (usb_dwc3_ep_configure(dev, USB_LEP_CDC_BULK_OUT, DWC3_DEPCMD_TYPE_BULK, 512)) - goto error; - if (usb_dwc3_ep_configure(dev, USB_LEP_CDC_BULK_IN, DWC3_DEPCMD_TYPE_BULK, 512)) - goto error; + dev->pipe[CDC_ACM_PIPE_0].ep_intr = USB_LEP_CDC_INTR_IN; + dev->pipe[CDC_ACM_PIPE_0].ep_in = USB_LEP_CDC_BULK_IN; + dev->pipe[CDC_ACM_PIPE_0].ep_out = USB_LEP_CDC_BULK_OUT; + + dev->pipe[CDC_ACM_PIPE_1].ep_intr = USB_LEP_CDC_INTR_IN_2; + dev->pipe[CDC_ACM_PIPE_1].ep_in = USB_LEP_CDC_BULK_IN_2; + dev->pipe[CDC_ACM_PIPE_1].ep_out = USB_LEP_CDC_BULK_OUT_2; + + for (int i = 0; i < CDC_ACM_PIPE_MAX; i++) { + dev->pipe[i].host2device = ringbuffer_alloc(CDC_BUFFER_SIZE); + if (!dev->pipe[i].host2device) + goto error; + dev->pipe[i].device2host = ringbuffer_alloc(CDC_BUFFER_SIZE); + if (!dev->pipe[i].device2host) + goto error; + + /* prepare INTR endpoint so that we don't have to reconfigure this device later */ + if (usb_dwc3_ep_configure(dev, dev->pipe[i].ep_intr, DWC3_DEPCMD_TYPE_INTR, 64)) + goto error; + + /* prepare BULK endpoints so that we don't have to reconfigure this device later */ + if (usb_dwc3_ep_configure(dev, dev->pipe[i].ep_in, DWC3_DEPCMD_TYPE_BULK, 512)) + goto error; + if (usb_dwc3_ep_configure(dev, dev->pipe[i].ep_out, DWC3_DEPCMD_TYPE_BULK, 512)) + goto error; + } /* prepare first control transfer */ dev->ep0_state = USB_DWC3_EP0_STATE_IDLE; @@ -1097,30 +1236,44 @@ void usb_dwc3_shutdown(dwc3_dev_t *dev) free(dev->scratchpad); free(dev->xferbuffer); free(dev->trbs); - ringbuffer_free(dev->host2device); - ringbuffer_free(dev->device2host); + for (int i = 0; i < CDC_ACM_PIPE_MAX; i++) { + ringbuffer_free(dev->pipe[i].device2host); + ringbuffer_free(dev->pipe[i].host2device); + } free(dev); } -u8 usb_dwc3_getbyte(dwc3_dev_t *dev) +u8 usb_dwc3_getbyte(dwc3_dev_t *dev, cdc_acm_pipe_id_t pipe) { + ringbuffer_t *host2device = dev->pipe[pipe].host2device; + if (!host2device) + return 0; + + u8 ep = dev->pipe[pipe].ep_out; + u8 c; - while (ringbuffer_read(&c, 1, dev->host2device) < 1) { + while (ringbuffer_read(&c, 1, host2device) < 1) { usb_dwc3_handle_events(dev); - usb_dwc3_cdc_start_bulk_out_xfer(dev, USB_LEP_CDC_BULK_OUT); + usb_dwc3_cdc_start_bulk_out_xfer(dev, ep); } return c; } -void usb_dwc3_putbyte(dwc3_dev_t *dev, u8 byte) +void usb_dwc3_putbyte(dwc3_dev_t *dev, cdc_acm_pipe_id_t pipe, u8 byte) { - while (ringbuffer_write(&byte, 1, dev->device2host) < 1) { + ringbuffer_t *device2host = dev->pipe[pipe].device2host; + if (!device2host) + return; + + u8 ep = dev->pipe[pipe].ep_in; + + while (ringbuffer_write(&byte, 1, device2host) < 1) { usb_dwc3_handle_events(dev); - usb_dwc3_cdc_start_bulk_in_xfer(dev, USB_LEP_CDC_BULK_IN); + usb_dwc3_cdc_start_bulk_in_xfer(dev, ep); } } -size_t usb_dwc3_write(dwc3_dev_t *dev, const void *buf, size_t count) +size_t usb_dwc3_write(dwc3_dev_t *dev, cdc_acm_pipe_id_t pipe, const void *buf, size_t count) { const u8 *p = buf; size_t wrote, sent = 0; @@ -1128,19 +1281,25 @@ size_t usb_dwc3_write(dwc3_dev_t *dev, const void *buf, size_t count) if (!dev || !dev->ready) return 0; + ringbuffer_t *device2host = dev->pipe[pipe].device2host; + if (!device2host) + return 0; + + u8 ep = dev->pipe[pipe].ep_in; + while (count) { - wrote = ringbuffer_write(p, count, dev->device2host); + wrote = ringbuffer_write(p, count, device2host); count -= wrote; p += wrote; sent += wrote; usb_dwc3_handle_events(dev); - usb_dwc3_cdc_start_bulk_in_xfer(dev, USB_LEP_CDC_BULK_IN); + usb_dwc3_cdc_start_bulk_in_xfer(dev, ep); } return sent; } -size_t usb_dwc3_read(dwc3_dev_t *dev, void *buf, size_t count) +size_t usb_dwc3_read(dwc3_dev_t *dev, cdc_acm_pipe_id_t pipe, void *buf, size_t count) { u8 *p = buf; size_t read, recvd = 0; @@ -1148,28 +1307,39 @@ size_t usb_dwc3_read(dwc3_dev_t *dev, void *buf, size_t count) if (!dev || !dev->ready) return 0; + ringbuffer_t *host2device = dev->pipe[pipe].host2device; + if (!host2device) + return 0; + + u8 ep = dev->pipe[pipe].ep_out; + while (count) { - read = ringbuffer_read(p, count, dev->host2device); + read = ringbuffer_read(p, count, host2device); count -= read; p += read; recvd += read; usb_dwc3_handle_events(dev); - usb_dwc3_cdc_start_bulk_out_xfer(dev, USB_LEP_CDC_BULK_OUT); + usb_dwc3_cdc_start_bulk_out_xfer(dev, ep); } return recvd; } -bool usb_dwc3_can_read(dwc3_dev_t *dev) +bool usb_dwc3_can_read(dwc3_dev_t *dev, cdc_acm_pipe_id_t pipe) { if (!dev || !dev->ready) return false; - return ringbuffer_get_used(dev->host2device); + ringbuffer_t *host2device = dev->pipe[pipe].host2device; + if (!host2device) + return false; + + return ringbuffer_get_used(host2device); } -bool usb_dwc3_can_write(dwc3_dev_t *dev) +bool usb_dwc3_can_write(dwc3_dev_t *dev, cdc_acm_pipe_id_t pipe) { + (void)pipe; if (!dev) return false; diff --git a/src/usb_dwc3.h b/src/usb_dwc3.h index a233639d..dc19da95 100644 --- a/src/usb_dwc3.h +++ b/src/usb_dwc3.h @@ -8,18 +8,24 @@ typedef struct dwc3_dev dwc3_dev_t; +typedef enum _cdc_acm_pipe_id_t { + CDC_ACM_PIPE_0, + CDC_ACM_PIPE_1, + CDC_ACM_PIPE_MAX +} cdc_acm_pipe_id_t; + dwc3_dev_t *usb_dwc3_init(uintptr_t regs, dart_dev_t *dart); void usb_dwc3_shutdown(dwc3_dev_t *dev); void usb_dwc3_handle_events(dwc3_dev_t *dev); -bool usb_dwc3_can_read(dwc3_dev_t *dev); -bool usb_dwc3_can_write(dwc3_dev_t *dev); +bool usb_dwc3_can_read(dwc3_dev_t *dev, cdc_acm_pipe_id_t pipe); +bool usb_dwc3_can_write(dwc3_dev_t *dev, cdc_acm_pipe_id_t pipe); -u8 usb_dwc3_getbyte(dwc3_dev_t *dev); -void usb_dwc3_putbyte(dwc3_dev_t *dev, u8 byte); +u8 usb_dwc3_getbyte(dwc3_dev_t *dev, cdc_acm_pipe_id_t pipe); +void usb_dwc3_putbyte(dwc3_dev_t *dev, cdc_acm_pipe_id_t pipe, u8 byte); -size_t usb_dwc3_write(dwc3_dev_t *dev, const void *buf, size_t count); -size_t usb_dwc3_read(dwc3_dev_t *dev, void *buf, size_t count); +size_t usb_dwc3_write(dwc3_dev_t *dev, cdc_acm_pipe_id_t pipe, const void *buf, size_t count); +size_t usb_dwc3_read(dwc3_dev_t *dev, cdc_acm_pipe_id_t pipe, void *buf, size_t count); #endif