laforge has uploaded this change for review. ( 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, 269 insertions(+), 67 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/osmo-e1-hardware refs/changes/48/29948/1
diff --git a/firmware/ice40-riscv/e1-tracer/usb_desc_app.c b/firmware/ice40-riscv/e1-tracer/usb_desc_app.c index 5109000..8178a41 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,161 @@ }, };
+/* "icE1usb" compatible Configuration */ +static const struct { + struct usb_conf_desc conf; + /* Interface / Direction A */ + struct { + struct { + struct usb_intf_desc intf; + struct usb_ep_desc ep_data_in0; + } __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; + struct usb_ep_desc ep_data_in1; + } __attribute__ ((packed)) off; + struct { + struct usb_intf_desc intf; + struct usb_ep_desc ep_data_in1; + } __attribute__ ((packed)) on; + } __attribute__ ((packed)) b; + /* DFU Runtime */ + struct { + struct usb_intf_desc intf; + struct usb_dfu_func_desc func; + } __attribute__ ((packed)) dfu; +} __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 = 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 = 0, + .bInterval = 1, + }, + }, + .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 = 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 = 0, + .bInterval = 1, + }, + }, + .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, + }, + }, + }, + .dfu = { + .intf = { + .bLength = sizeof(struct usb_intf_desc), + .bDescriptorType = USB_DT_INTF, + .bInterfaceNumber = 2, + .bAlternateSetting = 0, + .bNumEndpoints = 0, + .bInterfaceClass = 0xfe, + .bInterfaceSubClass = 0x01, + .bInterfaceProtocol = 0x01, + .iInterface = 6, + }, + .func = { + .bLength = sizeof(struct usb_dfu_func_desc), + .bDescriptorType = USB_DFU_DT_FUNC, + .bmAttributes = 0x0d, + .wDetachTimeOut = 1000, + .wTransferSize = 4096, + .bcdDFUVersion = 0x0101, + }, + }, +}; + 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 12c3906..728dc3a 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,123 @@ return USB_FND_SUCCESS; }
+static void +disable_chan(uint8_t chan) +{ + /* Already stopped ? */ + if (!g_usb_e1.running[chan]) + return; + + /* Update state */ + g_usb_e1.running[chan] = false; + + /* Stop E1 */ + e1_stop_one(chan); + + /* Disable end-points */ + usb_ep_regs[chan+1].in.status = 0; +} + +static void +enable_chan(uint8_t 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_one(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_one(0); - e1_stop_one(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_one(0); - e1_start_one(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