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 @@ static const struct { 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 @@ static const struct { }, }; +/* "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 + * Copyright (C) 2022 Harald Welte * 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 @@ usb_e1_run(void) 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 @@ _find_intf(const struct usb_conf_desc *conf, uint8_t idx) 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 @@ _e1_set_conf(const struct usb_conf_desc *conf) 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