icE1usb fw: Add multi-port support in USB code

Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
Change-Id: I134410b542461c34339baa8d9120a5c86fc35d46
diff --git a/firmware/ice40-riscv/icE1usb/fw_app.c b/firmware/ice40-riscv/icE1usb/fw_app.c
index 3340f4a..55218b8 100644
--- a/firmware/ice40-riscv/icE1usb/fw_app.c
+++ b/firmware/ice40-riscv/icE1usb/fw_app.c
@@ -102,6 +102,7 @@
 
 	/* Start */
 	e1_init(0, 0, 0);
+	e1_init(1, 0, 0);
 	led_state(true);
 	usb_connect();
 
@@ -151,7 +152,9 @@
 		usb_poll();
 
 		/* E1 poll */
-		e1_poll(0);
-		usb_e1_run();
+		for (int port=0; port<2; port++) {
+			e1_poll(port);
+			usb_e1_run(port);
+		}
 	}
 }
diff --git a/firmware/ice40-riscv/icE1usb/usb_desc_app.c b/firmware/ice40-riscv/icE1usb/usb_desc_app.c
index 663be0b..22a81d3 100644
--- a/firmware/ice40-riscv/icE1usb/usb_desc_app.c
+++ b/firmware/ice40-riscv/icE1usb/usb_desc_app.c
@@ -39,7 +39,7 @@
 			struct usb_ep_desc ep_fb;
 			struct usb_ep_desc ep_interrupt;
 		} __attribute__ ((packed)) on;
-	} __attribute__ ((packed)) e1;
+	} __attribute__ ((packed)) e1[2];
 
 	/* CDC */
 #if 0
@@ -71,7 +71,7 @@
 		.bmAttributes           = 0x80,
 		.bMaxPower              = 0x32, /* 100 mA */
 	},
-	.e1 = {
+	.e1[0] = {
 		.off = {
 			.intf = {
 				.bLength		= sizeof(struct usb_intf_desc),
@@ -103,7 +103,7 @@
 				.bInterfaceClass	= 0xff,
 				.bInterfaceSubClass	= 0xe1,
 				.bInterfaceProtocol	= 0x00,
-				.iInterface		= 5,
+				.iInterface		= 6,
 			},
 			.ep_data_in = {
 				.bLength		= sizeof(struct usb_ep_desc),
@@ -139,6 +139,74 @@
 			},
 		},
 	},
+	.e1[1] = {
+		.off = {
+			.intf = {
+				.bLength		= sizeof(struct usb_intf_desc),
+				.bDescriptorType	= USB_DT_INTF,
+				.bInterfaceNumber	= USB_INTF_E1(1),
+				.bAlternateSetting	= 0,
+				.bNumEndpoints		= 1,
+				.bInterfaceClass	= 0xff,
+				.bInterfaceSubClass	= 0xe1,
+				.bInterfaceProtocol	= 0x00,
+				.iInterface		= 7,
+			},
+			.ep_interrupt = {
+				.bLength		= sizeof(struct usb_ep_desc),
+				.bDescriptorType	= USB_DT_EP,
+				.bEndpointAddress	= USB_EP_E1_INT(1),
+				.bmAttributes		= 0x03,
+				.wMaxPacketSize		= 10,
+				.bInterval		= 4,	/* every 4 ms */
+			},
+		},
+		.on = {
+			.intf = {
+				.bLength		= sizeof(struct usb_intf_desc),
+				.bDescriptorType	= USB_DT_INTF,
+				.bInterfaceNumber	= USB_INTF_E1(1),
+				.bAlternateSetting	= 1,
+				.bNumEndpoints		= 4,
+				.bInterfaceClass	= 0xff,
+				.bInterfaceSubClass	= 0xe1,
+				.bInterfaceProtocol	= 0x00,
+				.iInterface		= 8,
+			},
+			.ep_data_in = {
+				.bLength		= sizeof(struct usb_ep_desc),
+				.bDescriptorType	= USB_DT_EP,
+				.bEndpointAddress	= USB_EP_E1_IN(1),
+				.bmAttributes		= 0x05,
+				.wMaxPacketSize		= 292,
+				.bInterval		= 1,
+			},
+			.ep_data_out = {
+				.bLength		= sizeof(struct usb_ep_desc),
+				.bDescriptorType	= USB_DT_EP,
+				.bEndpointAddress	= USB_EP_E1_OUT(1),
+				.bmAttributes		= 0x05,
+				.wMaxPacketSize		= 292,
+				.bInterval		= 1,
+			},
+			.ep_fb = {
+				.bLength		= sizeof(struct usb_ep_desc),
+				.bDescriptorType	= USB_DT_EP,
+				.bEndpointAddress	= USB_EP_E1_FB(1),
+				.bmAttributes		= 0x11,
+				.wMaxPacketSize		= 3,
+				.bInterval		= 3,	/* every 2^(3-1) = 4 ms */
+			},
+			.ep_interrupt = {
+				.bLength		= sizeof(struct usb_ep_desc),
+				.bDescriptorType	= USB_DT_EP,
+				.bEndpointAddress	= USB_EP_E1_INT(1),
+				.bmAttributes		= 0x03,
+				.wMaxPacketSize		= 10,
+				.bInterval		= 4,	/* every 4 ms */
+			},
+		},
+	},
 #if 0
 	.cdc = {
 		.intf_ctl = {
@@ -150,7 +218,7 @@
 			.bInterfaceClass	= USB_CLS_CDC_CONTROL,
 			.bInterfaceSubClass	= USB_CDC_SCLS_ACM,
 			.bInterfaceProtocol	= 0x00,
-			.iInterface		= 6,
+			.iInterface		= 9,
 		},
 		.cdc_hdr = {
 			.bLength		= sizeof(struct usb_cdc_hdr_desc),
@@ -188,7 +256,7 @@
 			.bInterfaceClass	= USB_CLS_CDC_DATA,
 			.bInterfaceSubClass	= 0x00,
 			.bInterfaceProtocol	= 0x00,
-			.iInterface		= 7,
+			.iInterface		= 10,
 		},
 		.ep_data_out = {
 			.bLength		= sizeof(struct usb_ep_desc),
@@ -218,7 +286,7 @@
 			.bInterfaceClass	= 0xfe,
 			.bInterfaceSubClass	= 0x01,
 			.bInterfaceProtocol	= 0x01,
-			.iInterface		= 8,
+			.iInterface		= 11,
 		},
 		.func = {
 			.bLength		= sizeof(struct usb_dfu_func_desc),
diff --git a/firmware/ice40-riscv/icE1usb/usb_desc_ids.h b/firmware/ice40-riscv/icE1usb/usb_desc_ids.h
index 2247f84..00dbb34 100644
--- a/firmware/ice40-riscv/icE1usb/usb_desc_ids.h
+++ b/firmware/ice40-riscv/icE1usb/usb_desc_ids.h
@@ -8,8 +8,8 @@
 #pragma once
 
 #define USB_INTF_E1(p)		(0 + (p))
-#define USB_INTF_DFU		1
-#define USB_INTF_NUM		2
+#define USB_INTF_DFU		2
+#define USB_INTF_NUM		3
 
 #define USB_EP_E1_IN(p)		(0x82 + (3 * (p)))
 #define USB_EP_E1_OUT(p)	(0x01 + (3 * (p)))
diff --git a/firmware/ice40-riscv/icE1usb/usb_e1.c b/firmware/ice40-riscv/icE1usb/usb_e1.c
index 75811c2..a18ebe4 100644
--- a/firmware/ice40-riscv/icE1usb/usb_e1.c
+++ b/firmware/ice40-riscv/icE1usb/usb_e1.c
@@ -16,17 +16,20 @@
 #include "e1.h"
 #include "misc.h"
 #include "usb_desc_ids.h"
+#include "utils.h"
 
 #include "ice1usb_proto.h"
 
-struct {
+struct usb_e1_state {
 	bool running;		/* are we running (transceiving USB data)? */
 	int out_bdi;		/* buffer descriptor index for OUT EP */
 	int in_bdi;		/* buffer descriptor index for IN EP */
 	struct ice1usb_tx_config tx_cfg;
 	struct ice1usb_rx_config rx_cfg;
 	struct e1_error_count last_err;
-} g_usb_e1;
+};
+
+static struct usb_e1_state g_usb_e1[2];
 
 /* default configuration at power-up */
 static const struct ice1usb_tx_config tx_cfg_default = {
@@ -47,8 +50,29 @@
 	return (ep & 0x80) ? &usb_ep_regs[ep & 0x1f].in : &usb_ep_regs[ep & 0x1f].out;
 }
 
+static struct usb_e1_state *
+_get_state(int port)
+{
+	if ((port < 0) || (port > 1))
+		panic("_get_state invalid port %d", port);
+	return &g_usb_e1[port];
+}
+
+static int
+_ifnum2port(uint8_t bInterfaceNumber)
+{
+	switch (bInterfaceNumber) {
+	case USB_INTF_E1(0): return 0;
+	case USB_INTF_E1(1): return 1;
+	default:
+		/* Don't panic since this will be handled as USB STALL */
+		return -1;
+	}
+}
+
+
 static void
-_usb_fill_feedback_ep(void)
+_usb_fill_feedback_ep(int port)
 {
 	static uint16_t ticks_prev = 0;
 	uint16_t ticks;
@@ -57,41 +81,42 @@
 	volatile struct usb_ep *ep_regs;
 
 	/* Compute real E1 tick count (with safety against bad values) */
-	ticks = e1_tick_read(0);
+	ticks = e1_tick_read(port);
 	val = (ticks - ticks_prev) & 0xffff;
 	ticks_prev = ticks;
 	if ((val < 7168) | (val > 9216))
 		val = 8192;
 
 	/* Bias depending on TX fifo level */
-	level = e1_tx_level(0);
+	level = e1_tx_level(port);
 	if (level < (3 * 16))
 		val += 256;
 	else if (level > (8 * 16))
 		val -= 256;
 
 	/* Prepare buffer */
-	ep_regs = _get_ep_regs(USB_EP_E1_FB(0));
+	ep_regs = _get_ep_regs(USB_EP_E1_FB(port));
 	usb_data_write(ep_regs->bd[0].ptr, &val, 4);
 	ep_regs->bd[0].csr = USB_BD_STATE_RDY_DATA | USB_BD_LEN(3);
 }
 
 
 void
-usb_e1_run(void)
+usb_e1_run(int port)
 {
+	struct usb_e1_state *usb_e1 = _get_state(port);
 	volatile struct usb_ep *ep_regs;
 	int bdi;
 
-	if (!g_usb_e1.running)
+	if (!usb_e1->running)
 		return;
 
 	/* Interrupt endpoint */
-	ep_regs = _get_ep_regs(USB_EP_E1_INT(0));
+	ep_regs = _get_ep_regs(USB_EP_E1_INT(port));
 
 	if ((ep_regs->bd[0].csr & USB_BD_STATE_MSK) != USB_BD_STATE_RDY_DATA) {
-		const struct e1_error_count *cur_err = e1_get_error_count(0);
-		if (memcmp(cur_err, &g_usb_e1.last_err, sizeof(*cur_err))) {
+		const struct e1_error_count *cur_err = e1_get_error_count(port);
+		if (memcmp(cur_err, &usb_e1->last_err, sizeof(*cur_err))) {
 			struct ice1usb_irq errmsg = {
 				.type = ICE1USB_IRQ_T_ERRCNT,
 				.u = {
@@ -107,13 +132,13 @@
 			printf("E");
 			usb_data_write(ep_regs->bd[0].ptr, &errmsg, sizeof(errmsg));
 			ep_regs->bd[0].csr = USB_BD_STATE_RDY_DATA | USB_BD_LEN(sizeof(errmsg));
-			g_usb_e1.last_err = *cur_err;
+			usb_e1->last_err = *cur_err;
 		}
 	}
 
 	/* Data IN endpoint */
-	ep_regs = _get_ep_regs(USB_EP_E1_IN(0));
-	bdi = g_usb_e1.in_bdi;
+	ep_regs = _get_ep_regs(USB_EP_E1_IN(port));
+	bdi = usb_e1->in_bdi;
 
 	while ((ep_regs->bd[bdi].csr & USB_BD_STATE_MSK) != USB_BD_STATE_RDY_DATA)
 	{
@@ -126,7 +151,7 @@
 			puts("Err EP IN\n");
 
 		/* Get some data from E1 */
-		int n = e1_rx_level(0);
+		int n = e1_rx_level(port);
 
 		if (n > 32)
 			n = 9;
@@ -135,7 +160,7 @@
 		else if (!n)
 			break;
 
-		n = e1_rx_need_data(0, (ptr >> 2) + 1, n, &pos);
+		n = e1_rx_need_data(port, (ptr >> 2) + 1, n, &pos);
 
 		/* Write header: currently version and pos (mfr/fr number) */
 		hdr = (0 << 28) | (pos & 0xff);
@@ -146,12 +171,12 @@
 
 		/* Next BDI */
 		bdi ^= 1;
-		g_usb_e1.in_bdi = bdi;
+		usb_e1->in_bdi = bdi;
 	}
 
 	/* Data OUT endpoint */
-	ep_regs = _get_ep_regs(USB_EP_E1_OUT(0));
-	bdi = g_usb_e1.out_bdi;
+	ep_regs = _get_ep_regs(USB_EP_E1_OUT(port));
+	bdi = usb_e1->out_bdi;
 
 	while ((ep_regs->bd[bdi].csr & USB_BD_STATE_MSK) != USB_BD_STATE_RDY_DATA)
 	{
@@ -171,7 +196,7 @@
 		/* Empty data into the FIFO */
 		int n = ((int)(csr & USB_BD_LEN_MSK) - 6) / 32;
 		if (n > 0)
-			e1_tx_feed_data(0, (ptr >> 2) + 1, n);
+			e1_tx_feed_data(port, (ptr >> 2) + 1, n);
 
 refill:
 		/* Refill it */
@@ -179,7 +204,7 @@
 
 		/* Next BDI */
 		bdi ^= 1;
-		g_usb_e1.out_bdi = bdi;
+		usb_e1->out_bdi = bdi;
 
 		static int x = 0;
 		if ((x++ & 0xff) == 0xff)
@@ -187,11 +212,11 @@
 	}
 
 	/* Feedback endpoint */
-	ep_regs = _get_ep_regs(USB_EP_E1_FB(0));
+	ep_regs = _get_ep_regs(USB_EP_E1_FB(port));
 
 	if ((ep_regs->bd[0].csr & USB_BD_STATE_MSK) != USB_BD_STATE_RDY_DATA)
 	{
-		_usb_fill_feedback_ep();
+		_usb_fill_feedback_ep(port);
 	}
 }
 
@@ -204,24 +229,28 @@
 	if (!conf)
 		return USB_FND_SUCCESS;
 
-	intf = usb_desc_find_intf(conf, USB_INTF_E1(0), 0, NULL);
-	if (!intf)
-		return USB_FND_ERROR;
+	for (int port=0; port<2; port++)
+	{
+		intf = usb_desc_find_intf(conf, USB_INTF_E1(port), 0, NULL);
+		if (!intf)
+			return USB_FND_ERROR;
 
-	printf("e1 set_conf %08x\n", intf);
+		printf("e1 set_conf[%d] %08x\n", port, intf);
 
-	usb_ep_boot(intf, USB_EP_E1_IN(0),  true);
-	usb_ep_boot(intf, USB_EP_E1_OUT(0), true);
-	usb_ep_boot(intf, USB_EP_E1_FB(0),  false);
-	usb_ep_boot(intf, USB_EP_E1_INT(0), false);
+		usb_ep_boot(intf, USB_EP_E1_IN(port),  true);
+		usb_ep_boot(intf, USB_EP_E1_OUT(port), true);
+		usb_ep_boot(intf, USB_EP_E1_FB(port),  false);
+		usb_ep_boot(intf, USB_EP_E1_INT(port), false);
+	}
 
 	return USB_FND_SUCCESS;
 }
 
-static void _perform_tx_config(void)
+static void _perform_tx_config(int port)
 {
-	const struct ice1usb_tx_config *cfg = &g_usb_e1.tx_cfg;
-	e1_tx_config(0,
+	struct usb_e1_state *usb_e1 = _get_state(port);
+	const struct ice1usb_tx_config *cfg = &usb_e1->tx_cfg;
+	e1_tx_config(port,
 		((cfg->mode & 3) << 1) |
 		((cfg->timing & 1) << 3) |
 		((cfg->alarm & 1) << 4) |
@@ -229,10 +258,11 @@
 	);
 }
 
-static void _perform_rx_config(void)
+static void _perform_rx_config(int port)
 {
-	const struct ice1usb_rx_config *cfg = &g_usb_e1.rx_cfg;
-	e1_rx_config(0,
+	struct usb_e1_state *usb_e1 = _get_state(port);
+	const struct ice1usb_rx_config *cfg = &usb_e1->rx_cfg;
+	e1_rx_config(port,
 		(cfg->mode << 1)
 	);
 }
@@ -241,50 +271,60 @@
 _e1_set_intf(const struct usb_intf_desc *base, const struct usb_intf_desc *sel)
 {
 	volatile struct usb_ep *ep_regs;
+	struct usb_e1_state *usb_e1;
+	int port;
 
-	/* Validity checks */
+	/* Is it for E1 interface ? */
 	if ((base->bInterfaceClass != 0xff) || (base->bInterfaceSubClass != 0xe1))
 		return USB_FND_CONTINUE;
 
+	/* Get matching port (if any) */
+	port = _ifnum2port(base->bInterfaceNumber);
+	if (port < 0)
+		return USB_FND_ERROR;
+
+	usb_e1 = _get_state(port);
+
+	/* Valid setting ? */
 	if (sel->bAlternateSetting > 1)
 		return USB_FND_ERROR;
 
 	/* Don't do anything if no change */
-	if (g_usb_e1.running == (sel->bAlternateSetting != 0))
+	if (usb_e1->running == (sel->bAlternateSetting != 0))
 		return USB_FND_SUCCESS;
 
-	g_usb_e1.running = (sel->bAlternateSetting != 0);
+	usb_e1->running = (sel->bAlternateSetting != 0);
 
 	/* Reconfigure the endpoints */
-	usb_ep_reconf(sel, USB_EP_E1_IN(0));
-	usb_ep_reconf(sel, USB_EP_E1_OUT(0));
-	usb_ep_reconf(sel, USB_EP_E1_FB(0));
-	usb_ep_reconf(sel, USB_EP_E1_INT(0));
+	usb_ep_reconf(sel, USB_EP_E1_IN(port));
+	usb_ep_reconf(sel, USB_EP_E1_OUT(port));
+	usb_ep_reconf(sel, USB_EP_E1_FB(port));
+	usb_ep_reconf(sel, USB_EP_E1_INT(port));
 
 	/* Update E1 and USB state */
-	switch (g_usb_e1.running) {
+	switch (usb_e1->running) {
 	case false:
 		/* Disable E1 rx/tx */
-		e1_init(0, 0, 0);
+		e1_init(port, 0, 0);
 		break;
 
 	case true:
 		/* Reset and Re-Enable E1 */
-		e1_init(0, 0, 0);
-		_perform_rx_config();
-		_perform_tx_config();
+		e1_init(port, 0, 0);
+		_perform_rx_config(port);
+		_perform_tx_config(port);
 
 		/* Reset BDI */
-		g_usb_e1.in_bdi = 0;
-		g_usb_e1.out_bdi = 0;
+		usb_e1->in_bdi = 0;
+		usb_e1->out_bdi = 0;
 
 		/* EP OUT: Queue two buffers */
-		ep_regs = _get_ep_regs(USB_EP_E1_FB(0));
+		ep_regs = _get_ep_regs(USB_EP_E1_OUT(port));
 		ep_regs->bd[0].csr = USB_BD_STATE_RDY_DATA | USB_BD_LEN(292);
 		ep_regs->bd[1].csr = USB_BD_STATE_RDY_DATA | USB_BD_LEN(292);
 
 		/* EP Feedback: Pre-fill */
-		_usb_fill_feedback_ep();
+		_usb_fill_feedback_ep(port);
 
 		break;
 	}
@@ -295,10 +335,22 @@
 static enum usb_fnd_resp
 _e1_get_intf(const struct usb_intf_desc *base, uint8_t *alt)
 {
+	struct usb_e1_state *usb_e1;
+	int port;
+
+	/* Is it for E1 interface ? */
 	if ((base->bInterfaceClass != 0xff) || (base->bInterfaceSubClass != 0xe1))
 		return USB_FND_CONTINUE;
 
-	*alt = g_usb_e1.running ? 1 : 0;
+	/* Get matching port (if any) */
+	port = _ifnum2port(base->bInterfaceNumber);
+	if (port < 0)
+		return USB_FND_ERROR;
+
+	usb_e1 = _get_state(port);
+
+	/* Return current alt-setting */
+	*alt = usb_e1->running ? 1 : 0;
 
 	return USB_FND_SUCCESS;
 }
@@ -307,10 +359,13 @@
 _set_tx_mode_done(struct usb_xfer *xfer)
 {
 	const struct ice1usb_tx_config *cfg = (const struct ice1usb_tx_config *) xfer->data;
-	printf("set_tx_mode %02x%02x%02x%02x\r\n",
+	struct usb_ctrl_req *req = xfer->cb_ctx;
+	int port = _ifnum2port(req->wIndex);
+	struct usb_e1_state *usb_e1 = _get_state(port);
+	printf("set_tx_mode[%d] %02x%02x%02x%02x\r\n", port,
 		xfer->data[0], xfer->data[1], xfer->data[2], xfer->data[3]);
-	g_usb_e1.tx_cfg = *cfg;
-	_perform_tx_config();
+	usb_e1->tx_cfg = *cfg;
+	_perform_tx_config(port);
 	return true;
 }
 
@@ -318,9 +373,12 @@
 _set_rx_mode_done(struct usb_xfer *xfer)
 {
 	const struct ice1usb_rx_config *cfg = (const struct ice1usb_rx_config *) xfer->data;
-	printf("set_rx_mode %02x\r\n", xfer->data[0]);
-	g_usb_e1.rx_cfg = *cfg;
-	_perform_rx_config();
+	struct usb_ctrl_req *req = xfer->cb_ctx;
+	int port = _ifnum2port(req->wIndex);
+	struct usb_e1_state *usb_e1 = _get_state(port);
+	printf("set_rx_mode[%d] %02x\r\n", port, xfer->data[0]);
+	usb_e1->rx_cfg = *cfg;
+	_perform_rx_config(port);
 	return true;
 }
 
@@ -328,8 +386,17 @@
 static enum usb_fnd_resp
 _e1_ctrl_req_intf(struct usb_ctrl_req *req, struct usb_xfer *xfer)
 {
-	unsigned int i;
+	struct usb_e1_state *usb_e1;
+	int port;
 
+	/* Get matching port (if any) */
+	port = _ifnum2port(req->wIndex);
+	if (port < 0)
+		return USB_FND_CONTINUE;
+
+	usb_e1 = _get_state(port);
+
+	/* Process request */
 	switch (req->bRequest) {
 	case ICE1USB_INTF_GET_CAPABILITIES:
 		/* no optional capabilities yet */
@@ -345,7 +412,7 @@
 	case ICE1USB_INTF_GET_TX_CFG:
 		if (req->wLength < sizeof(struct ice1usb_tx_config))
 			return USB_FND_ERROR;
-		memcpy(xfer->data, &g_usb_e1.tx_cfg, sizeof(struct ice1usb_tx_config));
+		memcpy(xfer->data, &usb_e1->tx_cfg, sizeof(struct ice1usb_tx_config));
 		xfer->len = sizeof(struct ice1usb_tx_config);
 		break;
 	case ICE1USB_INTF_SET_RX_CFG:
@@ -358,7 +425,7 @@
 	case ICE1USB_INTF_GET_RX_CFG:
 		if (req->wLength < sizeof(struct ice1usb_rx_config))
 			return USB_FND_ERROR;
-		memcpy(xfer->data, &g_usb_e1.rx_cfg, sizeof(struct ice1usb_rx_config));
+		memcpy(xfer->data, &usb_e1->rx_cfg, sizeof(struct ice1usb_rx_config));
 		xfer->len = sizeof(struct ice1usb_rx_config);
 		break;
 	default:
@@ -396,8 +463,6 @@
 	case USB_REQ_RCPT_DEV:
 		return _e1_ctrl_req_dev(req, xfer);
 	case USB_REQ_RCPT_INTF:
-		if (req->wIndex != USB_INTF_E1(0))
-			return USB_FND_CONTINUE;
 		return _e1_ctrl_req_intf(req, xfer);
 	case USB_REQ_RCPT_EP:
 	case USB_REQ_RCPT_OTHER:
@@ -417,8 +482,12 @@
 void
 usb_e1_init(void)
 {
-	memset(&g_usb_e1, 0x00, sizeof(g_usb_e1));
-	g_usb_e1.tx_cfg = tx_cfg_default;
-	g_usb_e1.rx_cfg = rx_cfg_default;
+	for (int i=0; i<2; i++) {
+		struct usb_e1_state *usb_e1 = _get_state(i);
+		memset(usb_e1, 0x00, sizeof(struct usb_e1_state));
+		usb_e1->tx_cfg = tx_cfg_default;
+		usb_e1->rx_cfg = rx_cfg_default;
+	}
+
 	usb_register_function_driver(&_e1_drv);
 }
diff --git a/firmware/ice40-riscv/icE1usb/usb_e1.h b/firmware/ice40-riscv/icE1usb/usb_e1.h
index a573b38..06723ea 100644
--- a/firmware/ice40-riscv/icE1usb/usb_e1.h
+++ b/firmware/ice40-riscv/icE1usb/usb_e1.h
@@ -7,5 +7,5 @@
 
 #pragma once
 
-void usb_e1_run(void);
+void usb_e1_run(int port);
 void usb_e1_init(void);
diff --git a/firmware/ice40-riscv/icE1usb/usb_str_app.txt b/firmware/ice40-riscv/icE1usb/usb_str_app.txt
index 10887d3..3aa6b4a 100644
--- a/firmware/ice40-riscv/icE1usb/usb_str_app.txt
+++ b/firmware/ice40-riscv/icE1usb/usb_str_app.txt
@@ -2,7 +2,10 @@
 osmocom
 icE1usb
 Main
-E1
-Console (control)
-Console (data)
+E1 port 0 (disabled)
+E1 port 0
+E1 port 1 (disabled)
+E1 port 1
+GPS (CDC control)
+GPS (CDC data)
 DFU runtime