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
This commit is contained in:
Harald Welte 2022-11-01 21:58:34 +01:00
parent 326a08fe63
commit f9280b0de1
3 changed files with 220 additions and 67 deletions

View File

@ -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 = {

View File

@ -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 @@ 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;
}

View File

@ -1,6 +1,9 @@
0000000000000000
osmocom
e1-tracer
Main
Legacy
E1
DFU runtime
osmo-e1d compatible
E1 Direction A
E1 Direction B