laforge has submitted this change. ( https://gerrit.osmocom.org/c/osmo-e1-hardware/+/29948 )
Change subject: fw/e1-tracer: Additional USB configuration for "osmo-e1d compatible mode" ......................................................................
fw/e1-tracer: Additional USB configuration for "osmo-e1d compatible mode"
This adds a second USB configuration to the e1-tracer firmware. This configuration is closer to the USB configuration of an icE1usb and hence paves the way for using osmo-e1d with the tracer.
The main conceptual difference between the existing "legacy" configuration and this new "e1d compatible" configuration is to have two USB interfaces, one for each direction of the traced E1 interface. Each interface has its own separate two altsettings, one for the disabled and one for the enabled state.
Unmodified osmo-e1d will not work straight away with this, as it expects ISO OUT and ISU Feedback endpoints, which a pure rx-only tracing device of course doesn't have.
Related: OS#5733 Change-Id: I97062b9f12317b1b9b3855409c2380108cb921ff --- M firmware/ice40-riscv/e1-tracer/usb_desc_app.c M firmware/ice40-riscv/e1-tracer/usb_e1.c M firmware/ice40-riscv/e1-tracer/usb_str_app.txt 3 files changed, 220 insertions(+), 67 deletions(-)
Approvals: Jenkins Builder: Verified laforge: Looks good to me, approved
diff --git a/firmware/ice40-riscv/e1-tracer/usb_desc_app.c b/firmware/ice40-riscv/e1-tracer/usb_desc_app.c index 5109000..e9aa9d6 100644 --- a/firmware/ice40-riscv/e1-tracer/usb_desc_app.c +++ b/firmware/ice40-riscv/e1-tracer/usb_desc_app.c @@ -13,10 +13,9 @@ #define num_elem(a) (sizeof(a) / sizeof(a[0]))
+/* Legacy Configuration */ static const struct { - /* Configuration */ struct usb_conf_desc conf; - /* E1 */ struct { struct { @@ -30,7 +29,6 @@ struct usb_ep_desc ep_data_in1; } __attribute__ ((packed)) on; } __attribute__ ((packed)) e1; - /* DFU Runtime */ struct { struct usb_intf_desc intf; @@ -130,8 +128,117 @@ }, };
+/* "icE1usb" compatible Configuration */ +static const struct { + struct usb_conf_desc conf; + /* Interface / Direction A */ + struct { + struct { + struct usb_intf_desc intf; + } __attribute__ ((packed)) off; + struct { + struct usb_intf_desc intf; + struct usb_ep_desc ep_data_in0; + } __attribute__ ((packed)) on; + } __attribute__ ((packed)) a; + /* Interface / Direction B */ + struct { + struct { + struct usb_intf_desc intf; + } __attribute__ ((packed)) off; + struct { + struct usb_intf_desc intf; + struct usb_ep_desc ep_data_in1; + } __attribute__ ((packed)) on; + } __attribute__ ((packed)) b; +} __attribute__ ((packed)) _app_conf_desc_e1d = { + .conf = { + .bLength = sizeof(struct usb_conf_desc), + .bDescriptorType = USB_DT_CONF, + .wTotalLength = sizeof(_app_conf_desc_e1d), + .bNumInterfaces = 3, + .bConfigurationValue = 2, + .iConfiguration = 7, + .bmAttributes = 0x80, + .bMaxPower = 0x32, /* 100 mA */ + }, + .a = { + .off = { + .intf = { + .bLength = sizeof(struct usb_intf_desc), + .bDescriptorType = USB_DT_INTF, + .bInterfaceNumber = 0, + .bAlternateSetting = 0, + .bNumEndpoints = 0, + .bInterfaceClass = 0xff, + .bInterfaceSubClass = 0xe1, + .bInterfaceProtocol = 0x00, + .iInterface = 8, + }, + }, + .on = { + .intf = { + .bLength = sizeof(struct usb_intf_desc), + .bDescriptorType = USB_DT_INTF, + .bInterfaceNumber = 0, + .bAlternateSetting = 1, + .bNumEndpoints = 1, + .bInterfaceClass = 0xff, + .bInterfaceSubClass = 0xe1, + .bInterfaceProtocol = 0x00, + .iInterface = 8, + }, + .ep_data_in0 = { + .bLength = sizeof(struct usb_ep_desc), + .bDescriptorType = USB_DT_EP, + .bEndpointAddress = 0x81, + .bmAttributes = 0x05, + .wMaxPacketSize = 388, + .bInterval = 1, + }, + }, + }, + .b = { + .off = { + .intf = { + .bLength = sizeof(struct usb_intf_desc), + .bDescriptorType = USB_DT_INTF, + .bInterfaceNumber = 1, + .bAlternateSetting = 0, + .bNumEndpoints = 0, + .bInterfaceClass = 0xff, + .bInterfaceSubClass = 0xe1, + .bInterfaceProtocol = 0x00, + .iInterface = 9, + }, + }, + .on = { + .intf = { + .bLength = sizeof(struct usb_intf_desc), + .bDescriptorType = USB_DT_INTF, + .bInterfaceNumber = 1, + .bAlternateSetting = 1, + .bNumEndpoints = 1, + .bInterfaceClass = 0xff, + .bInterfaceSubClass = 0xe1, + .bInterfaceProtocol = 0x00, + .iInterface = 9, + }, + .ep_data_in1 = { + .bLength = sizeof(struct usb_ep_desc), + .bDescriptorType = USB_DT_EP, + .bEndpointAddress = 0x82, + .bmAttributes = 0x05, + .wMaxPacketSize = 388, + .bInterval = 1, + }, + }, + }, +}; + static const struct usb_conf_desc * const _conf_desc_array[] = { &_app_conf_desc.conf, + &_app_conf_desc_e1d.conf, };
static const struct usb_dev_desc _dev_desc = { diff --git a/firmware/ice40-riscv/e1-tracer/usb_e1.c b/firmware/ice40-riscv/e1-tracer/usb_e1.c index 80522e2..f3f1538 100644 --- a/firmware/ice40-riscv/e1-tracer/usb_e1.c +++ b/firmware/ice40-riscv/e1-tracer/usb_e1.c @@ -2,6 +2,7 @@ * usb_e1.c * * Copyright (C) 2019-2020 Sylvain Munaut tnt@246tNt.com + * Copyright (C) 2022 Harald Welte laforge@osmocom.org * SPDX-License-Identifier: GPL-3.0-or-later */
@@ -17,7 +18,7 @@ #include "misc.h"
struct { - bool running; + bool running[2]; int in_bdi[2]; } g_usb_e1;
@@ -35,12 +36,12 @@ int chan; int bdi;
- if (!g_usb_e1.running) - return; - /* EP[1-2] IN */ for (chan=0; chan<2; chan++) { + if (!g_usb_e1.running[chan]) + continue; + bdi = g_usb_e1.in_bdi[chan];
while ((usb_ep_regs[1+chan].in.bd[bdi].csr & USB_BD_STATE_MSK) != USB_BD_STATE_RDY_DATA) @@ -112,12 +113,17 @@
return NULL; } + +static const struct usb_conf_desc *last_conf; + enum usb_fnd_resp _e1_set_conf(const struct usb_conf_desc *conf) { const struct usb_intf_desc *intf;
printf("e1 set_conf %08x\n", conf); + + last_conf = conf; if (!conf) return USB_FND_SUCCESS;
@@ -133,81 +139,118 @@ return USB_FND_SUCCESS; }
+static void +disable_chan(int chan) +{ + /* Already stopped ? */ + if (!g_usb_e1.running[chan]) + return; + + /* Update state */ + g_usb_e1.running[chan] = false; + + /* Stop E1 */ + e1_stop(chan); + + /* Disable end-points */ + usb_ep_regs[chan+1].in.status = 0; +} + +static void +enable_chan(int chan) +{ + /* Already running ? */ + if (g_usb_e1.running[chan]) + return; + + /* Update state */ + g_usb_e1.running[chan] = true; + + /* Reset buffer pointers */ + g_usb_e1.in_bdi[chan] = 0; + + /* Configure EP1 IN / EP2 IN */ + usb_ep_regs[chan+1].in.status = USB_EP_TYPE_ISOC | USB_EP_BD_DUAL; /* Type=Isochronous, dual buffered */ + + /* EP1 IN: Prepare two buffers */ + usb_ep_regs[chan+1].in.bd[0].ptr = 256 + (chan * 2 + 0) * 388; + usb_ep_regs[chan+1].in.bd[0].csr = 0; + + usb_ep_regs[chan+1].in.bd[1].ptr = 256 + (chan * 2 + 1) * 388; + usb_ep_regs[chan+1].in.bd[1].csr = 0; + + /* Start E1 */ + e1_start(chan); +} + enum usb_fnd_resp _e1_set_intf(const struct usb_intf_desc *base, const struct usb_intf_desc *sel) { - if (base->bInterfaceNumber != 0) - return USB_FND_CONTINUE; + if (!last_conf || last_conf->bConfigurationValue == 1) { + /* Legacy Configuration */
- if (sel->bAlternateSetting == 0) - { - /* Already stopped ? */ - if (!g_usb_e1.running) - return USB_FND_SUCCESS; + if (base->bInterfaceNumber != 0) + return USB_FND_CONTINUE;
- /* Update state */ - g_usb_e1.running = false; + if (sel->bAlternateSetting == 0) { + disable_chan(0); + disable_chan(1); + } else if (sel->bAlternateSetting == 1) { + enable_chan(0); + enable_chan(1); + } else { + /* Unknown */ + return USB_FND_ERROR; + } + } else if (last_conf && last_conf->bConfigurationValue == 2) { + /* e1d compatible configuration */
- /* Stop E1 */ - e1_stop(0); - e1_stop(1); - - /* Disable end-points */ - usb_ep_regs[1].in.status = 0; - usb_ep_regs[2].in.status = 0; - } - else if (sel->bAlternateSetting == 1) - { - /* Already running ? */ - if (g_usb_e1.running) - return USB_FND_SUCCESS; - - /* Update state */ - g_usb_e1.running = true; - - /* Reset buffer pointers */ - g_usb_e1.in_bdi[0] = 0; - g_usb_e1.in_bdi[1] = 0; - - /* Configure EP1 IN / EP2 IN */ - usb_ep_regs[1].in.status = USB_EP_TYPE_ISOC | USB_EP_BD_DUAL; /* Type=Isochronous, dual buffered */ - usb_ep_regs[2].in.status = USB_EP_TYPE_ISOC | USB_EP_BD_DUAL; /* Type=Isochronous, dual buffered */ - - /* EP1 IN: Prepare two buffers */ - usb_ep_regs[1].in.bd[0].ptr = 256 + 0 * 388; - usb_ep_regs[1].in.bd[0].csr = 0; - - usb_ep_regs[1].in.bd[1].ptr = 256 + 1 * 388; - usb_ep_regs[1].in.bd[1].csr = 0; - - /* EP2 IN: Prepare two buffers */ - usb_ep_regs[2].in.bd[0].ptr = 256 + 2 * 388; - usb_ep_regs[2].in.bd[0].csr = 0; - - usb_ep_regs[2].in.bd[1].ptr = 256 + 3 * 388; - usb_ep_regs[2].in.bd[1].csr = 0; - - /* Start E1 */ - e1_start(0); - e1_start(1); - } - else - { - /* Unknown */ + switch (base->bInterfaceNumber) { + case 0: + case 1: + switch (sel->bAlternateSetting) { + case 0: + disable_chan(base->bInterfaceNumber); + break; + case 1: + enable_chan(base->bInterfaceNumber); + break; + default: + /* Unknown */ + return USB_FND_ERROR; + } + break; + default: + return USB_FND_CONTINUE; + } + } else { return USB_FND_ERROR; }
- return USB_FND_SUCCESS; }
enum usb_fnd_resp _e1_get_intf(const struct usb_intf_desc *base, uint8_t *alt) { - if (base->bInterfaceNumber != 0) - return USB_FND_CONTINUE; + if (!last_conf || last_conf->bConfigurationValue == 1) { + /* Legacy configuration */ + if (base->bInterfaceNumber != 0) + return USB_FND_CONTINUE;
- *alt = g_usb_e1.running ? 1 : 0; + *alt = g_usb_e1.running[0] && g_usb_e1.running[1] ? 1 : 0; + } else if (last_conf && last_conf->bConfigurationValue == 2) { + /* e1d compatible configuration */ + switch (base->bInterfaceNumber) { + case 0: + case 1: + *alt = g_usb_e1.running[base->bInterfaceNumber] ? 1 : 0; + break; + default: + return USB_FND_CONTINUE; + } + } else + return USB_FND_CONTINUE;
return USB_FND_SUCCESS; } diff --git a/firmware/ice40-riscv/e1-tracer/usb_str_app.txt b/firmware/ice40-riscv/e1-tracer/usb_str_app.txt index 0482e91..45ac005 100644 --- a/firmware/ice40-riscv/e1-tracer/usb_str_app.txt +++ b/firmware/ice40-riscv/e1-tracer/usb_str_app.txt @@ -1,6 +1,9 @@ 0000000000000000 osmocom e1-tracer -Main +Legacy E1 DFU runtime +osmo-e1d compatible +E1 Direction A +E1 Direction B