usb: allow more flexible endpoint allocation

the capabilities of endpoint of several devices such as dwc2 change during
runtime, so they cannot be determined during driver initialization.
therefore, allocation using ep_specs is inappropriate.

to support these devices, add functions to the driver that determine whether
endpoints are available and make allocation more flexible.

tested with ipodvideo(arc) and erosqnative(designware)

Change-Id: I8005c17f3d763cd17306bf49918e1cd8084bdeff
This commit is contained in:
mojyack 2025-12-28 15:48:53 +09:00 committed by Solomon Peachy
parent 42841d493f
commit 41caf678fe
14 changed files with 348 additions and 283 deletions

View file

@ -626,18 +626,17 @@ void usb_drv_cancel_all_transfers(void)
endpoints[i].halt[0] = endpoints[i].halt[1] = 1; endpoints[i].halt[0] = endpoints[i].halt[1] = 1;
} }
int usb_drv_init_endpoint(int endpoint, int type, int max_packet_size) void usb_drv_ep_init(const struct usb_drv_ep_alloc_ctx* ctx, int ep)
{ {
(void)max_packet_size; /* FIXME: support max packet size override */ /* FIXME: support max packet size override */
(void)type; (void)ctx;
(void)endpoint; (void)ep;
return 0;
} }
int usb_drv_deinit_endpoint(int endpoint) void usb_drv_ep_deinit(const struct usb_drv_ep_alloc_ctx* ctx, int ep)
{ {
(void)endpoint; (void)ctx;
return 0; (void)ep;
} }
static void bus_reset(void) static void bus_reset(void)

View file

@ -640,8 +640,11 @@ void usb_drv_set_test_mode(int mode) {
M66591_TESTMODE |= mode; M66591_TESTMODE |= mode;
} }
int usb_drv_init_endpoint(int endpoint, int type, int max_packet_size) { void usb_drv_ep_init(const struct usb_drv_ep_alloc_ctx* ctx, int ep) {
(void)max_packet_size; /* FIXME: support max packet size override */ /* FIXME: support max packet size override */
const int epnum = EP_NUM(ep);
const int epdir = EP_DIR(ep);
const int type = ctx->type[epnum][epdir];
int pipecfg = 0; int pipecfg = 0;
@ -651,41 +654,38 @@ int usb_drv_init_endpoint(int endpoint, int type, int max_packet_size) {
} else if(type == USB_ENDPOINT_XFER_BULK) { } else if(type == USB_ENDPOINT_XFER_BULK) {
pipecfg |= 1<<13; pipecfg |= 1<<13;
} else { } else {
/* Not a supported type */ panicf("mxx: unsupported type %d", type);
return -1;
} }
int num = endpoint & USB_ENDPOINT_NUMBER_MASK; if (epdir == DIR_IN) {
int dir = endpoint & USB_ENDPOINT_DIR_MASK;
if (dir == USB_DIR_IN) {
pipecfg |= (1<<4); pipecfg |= (1<<4);
} }
M66591_eps[num].dir = dir; M66591_eps[epnum].dir = epdir == DIR_IN ? USB_DIR_IN : USB_DIR_OUT;
M66591_PIPE_CFGSEL=num; M66591_PIPE_CFGSEL = epnum;
/* Enable pipe (15) */ /* Enable pipe (15) */
pipecfg |= 1<<15; pipecfg |= 1<<15;
pipe_handshake(num, PIPE_SHAKE_NAK); pipe_handshake(epnum, PIPE_SHAKE_NAK);
/* Setup the flags */ /* Setup the flags */
M66591_PIPE_CFGWND=pipecfg; M66591_PIPE_CFGWND=pipecfg;
pipe_init(num); pipe_init(epnum);
logf("mxx: ep req ep#: %d config: 0x%04x", num, M66591_PIPE_CFGWND); logf("mxx: ep req ep#: %d config: 0x%04x", epnum, M66591_PIPE_CFGWND);
return 0;
} }
/* Used by stack to tell the helper functions that the pipe is not in use */ /* Used by stack to tell the helper functions that the pipe is not in use */
int usb_drv_deinit_endpoint(int endpoint) { void usb_drv_ep_deinit(const struct usb_drv_ep_alloc_ctx* ctx, int ep) {
int num = endpoint & USB_ENDPOINT_NUMBER_MASK; (void)ctx;
int num = ep & USB_ENDPOINT_NUMBER_MASK;
if (num < 1 || num > USB_NUM_ENDPOINTS) { if (num < 1 || num > USB_NUM_ENDPOINTS) {
return -1; return;
} }
int flags = disable_irq_save(); int flags = disable_irq_save();
@ -695,8 +695,6 @@ int usb_drv_deinit_endpoint(int endpoint) {
M66591_eps[num].dir = -1; M66591_eps[num].dir = -1;
restore_irq(flags); restore_irq(flags);
return 0;
} }
/* Periodically called to check if a cable was plugged into the device */ /* Periodically called to check if a cable was plugged into the device */

View file

@ -24,6 +24,8 @@
#include <inttypes.h> #include <inttypes.h>
#include <string.h> #include <string.h>
#include "usb-designware.h"
#include "config.h" #include "config.h"
#include "cpu.h" #include "cpu.h"
#include "system.h" #include "system.h"
@ -35,8 +37,6 @@
#include "usb_ch9.h" #include "usb_ch9.h"
#include "usb_core.h" #include "usb_core.h"
#include "usb-designware.h"
/* Define LOGF_ENABLE to enable logf output in this file */ /* Define LOGF_ENABLE to enable logf output in this file */
/*#define LOGF_ENABLE*/ /*#define LOGF_ENABLE*/
#include "logf.h" #include "logf.h"
@ -155,9 +155,6 @@ struct usb_dw_ep0
struct usb_ctrlrequest pending_req; struct usb_ctrlrequest pending_req;
}; };
struct usb_drv_ep_spec usb_drv_ep_specs[USB_NUM_ENDPOINTS]; /* filled in usb_drv_init */
uint8_t usb_drv_ep_specs_flags = 0;
static const char* const dw_dir_str[USB_DW_NUM_DIRS] = static const char* const dw_dir_str[USB_DW_NUM_DIRS] =
{ {
[USB_DW_EPDIR_IN] = "IN", [USB_DW_EPDIR_IN] = "IN",
@ -195,7 +192,6 @@ static uint32_t usb_endpoints; /* available EPs mask */
(usually 1), otherwise it is the number of dedicated Tx FIFOs (usually 1), otherwise it is the number of dedicated Tx FIFOs
(not counting NPTX FIFO that is always dedicated for IN0). */ (not counting NPTX FIFO that is always dedicated for IN0). */
static int n_ptxfifos; static int n_ptxfifos;
static uint16_t ptxfifo_usage;
static uint32_t hw_maxbytes; static uint32_t hw_maxbytes;
static uint32_t hw_maxpackets; static uint32_t hw_maxpackets;
@ -672,47 +668,28 @@ static void usb_dw_unconfigure_ep(int epnum, enum usb_dw_epdir epdir)
#endif #endif
ep_periodic_msk &= ~(1 << epnum); ep_periodic_msk &= ~(1 << epnum);
#endif #endif
ptxfifo_usage &= ~(1 << GET_DTXFNUM(epnum));
} }
usb_dw_flush_endpoint(epnum, epdir); usb_dw_flush_endpoint(epnum, epdir);
DWC_EPCTL(epnum, epdir) = epctl; DWC_EPCTL(epnum, epdir) = epctl;
} }
static int usb_dw_configure_ep(int epnum, static void usb_dw_configure_ep(const struct usb_drv_ep_alloc_ctx* ctx, int epnum, enum usb_dw_epdir epdir, int type, int maxpktsize)
enum usb_dw_epdir epdir, int type, int maxpktsize)
{ {
uint32_t epctl = SETD0PIDEF|EPTYP(type)|USBAEP|maxpktsize; uint32_t epctl = SETD0PIDEF|EPTYP(type)|USBAEP|maxpktsize;
if (epdir == USB_DW_EPDIR_IN) if (epdir == USB_DW_EPDIR_IN && ctx->assigned_txfifos[epnum] > 0)
{ {
/*
* If the hardware has dedicated fifos, we must give each
* IN EP a unique tx-fifo even if it is non-periodic.
*/
#ifdef USB_DW_SHARED_FIFO #ifdef USB_DW_SHARED_FIFO
ep_periodic_msk |= (1 << epnum);
#ifndef USB_DW_ARCH_SLAVE #ifndef USB_DW_ARCH_SLAVE
epctl |= DWC_DIEPCTL(epnum) & NEXTEP(0xf); epctl |= DWC_DIEPCTL(epnum) & NEXTEP(0xf);
#endif #endif
if (type == USB_ENDPOINT_XFER_INT)
#endif #endif
{ epctl |= DTXFNUM(ctx->assigned_txfifos[epnum]);
int fnum;
for (fnum = 1; fnum <= n_ptxfifos; fnum++)
if (~ptxfifo_usage & (1 << fnum))
break;
if (fnum > n_ptxfifos)
return -1; /* no available fifos */
ptxfifo_usage |= (1 << fnum);
epctl |= DTXFNUM(fnum);
#ifdef USB_DW_SHARED_FIFO
ep_periodic_msk |= (1 << epnum);
#endif
}
} }
DWC_EPCTL(epnum, epdir) = epctl; DWC_EPCTL(epnum, epdir) = epctl;
return 0; /* ok */
} }
static void usb_dw_reset_endpoints(void) static void usb_dw_reset_endpoints(void)
@ -753,7 +730,6 @@ static void usb_dw_reset_endpoints(void)
usb_dw_unconfigure_ep(ep, USB_DW_EPDIR_IN); usb_dw_unconfigure_ep(ep, USB_DW_EPDIR_IN);
} }
ptxfifo_usage = 0;
#ifdef USB_DW_SHARED_FIFO #ifdef USB_DW_SHARED_FIFO
ep_periodic_msk = 0; ep_periodic_msk = 0;
#endif #endif
@ -1509,17 +1485,6 @@ static void usb_dw_init(void)
/* Soft reconnect */ /* Soft reconnect */
udelay(3000); udelay(3000);
DWC_DCTL &= ~SDIS; DWC_DCTL &= ~SDIS;
/* Fill endpoint spec table FIXME: should be done in usb_drv_startup() */
usb_drv_ep_specs[0].type[DIR_OUT] = USB_ENDPOINT_XFER_CONTROL;
usb_drv_ep_specs[0].type[DIR_IN] = USB_ENDPOINT_XFER_CONTROL;
for(int i = 1; i < USB_NUM_ENDPOINTS; i += 1) {
bool out_avail = usb_endpoints & (1 << (i + USB_DW_DIR_OFF(USB_DW_EPDIR_OUT)));
usb_drv_ep_specs[i].type[DIR_OUT] = out_avail ? USB_ENDPOINT_TYPE_ANY : USB_ENDPOINT_TYPE_NONE;
bool in_avail = usb_endpoints & (1 << (i + USB_DW_DIR_OFF(USB_DW_EPDIR_IN)));
usb_drv_ep_specs[i].type[DIR_IN] = in_avail ? USB_ENDPOINT_TYPE_ANY : USB_ENDPOINT_TYPE_NONE;
}
} }
static void usb_dw_exit(void) static void usb_dw_exit(void)
@ -1617,12 +1582,65 @@ void INT_USB_FUNC(void)
usb_dw_irq(); usb_dw_irq();
} }
int usb_drv_init_endpoint(int endpoint, int type, int max_packet_size) void usb_drv_ep_reset_alloc_ctx(struct usb_drv_ep_alloc_ctx* ctx)
{
memset(ctx, 0, sizeof(*ctx));
}
bool usb_drv_ep_allocate(struct usb_drv_ep_alloc_ctx* ctx, int ep, int type, int max_packet_size)
{ {
(void)max_packet_size; /* FIXME: support max packet size override */ (void)max_packet_size; /* FIXME: support max packet size override */
enum usb_dw_epdir epdir = (EP_DIR(endpoint) == DIR_IN) ? USB_DW_EPDIR_IN : USB_DW_EPDIR_OUT; const uint8_t epnum = EP_NUM(ep);
struct usb_dw_ep* dw_ep = usb_dw_get_ep(EP_NUM(endpoint), epdir); const uint8_t epdir = EP_DIR(ep);
if(ep == EP_CONTROL)
{
return false;
}
enum usb_dw_epdir dwdir = epdir == DIR_IN ? USB_DW_EPDIR_IN : USB_DW_EPDIR_OUT;
if(!(usb_endpoints & (1 << (epnum + USB_DW_DIR_OFF(dwdir)))))
{
return false;
}
bool need_fifo = epdir == DIR_IN;
#ifdef USB_DW_SHARED_FIFO
/* in shared fifo mode, only periodic endpoints need dedicated fifo */
need_fifo &= type == USB_ENDPOINT_XFER_ISOC || type == USB_ENDPOINT_XFER_INT;
#endif
if(!need_fifo)
{
goto ok;
}
for (int fnum = 1; fnum <= n_ptxfifos; fnum++)
{
if (~ctx->txfifo_usage & (1 << fnum))
{
ctx->txfifo_usage |= 1 << fnum;
ctx->assigned_txfifos[epnum] = fnum;
goto ok;
}
}
return false;
ok:
ctx->type[epnum][epdir] = type;
return true;
}
void usb_drv_ep_init(const struct usb_drv_ep_alloc_ctx* ctx, int ep)
{
/* FIXME: support max packet size override */
const int epnum = EP_NUM(ep);
const int epdir_ = EP_DIR(ep);
const int type = ctx->type[epnum][epdir_];
enum usb_dw_epdir epdir = (epdir_ == DIR_IN) ? USB_DW_EPDIR_IN : USB_DW_EPDIR_OUT;
struct usb_dw_ep* dw_ep = usb_dw_get_ep(EP_NUM(ep), epdir);
int maxpktsize; int maxpktsize;
if(type == EPTYP_ISOCHRONOUS) if(type == EPTYP_ISOCHRONOUS)
@ -1635,32 +1653,23 @@ int usb_drv_init_endpoint(int endpoint, int type, int max_packet_size)
} }
usb_dw_target_disable_irq(); usb_dw_target_disable_irq();
int res = usb_dw_configure_ep(EP_NUM(endpoint), epdir, type, maxpktsize); usb_dw_configure_ep(ctx, epnum, epdir, type, maxpktsize);
usb_dw_target_enable_irq(); usb_dw_target_enable_irq();
if(res >= 0) dw_ep->active = true;
{
dw_ep->active = true;
return 0;
}
else
{
return -1;
}
} }
int usb_drv_deinit_endpoint(int endpoint) void usb_drv_ep_deinit(const struct usb_drv_ep_alloc_ctx* ctx, int ep)
{ {
enum usb_dw_epdir epdir = (EP_DIR(endpoint) == DIR_IN) ? USB_DW_EPDIR_IN : USB_DW_EPDIR_OUT; (void)ctx;
struct usb_dw_ep* dw_ep = usb_dw_get_ep(EP_NUM(endpoint), epdir); enum usb_dw_epdir epdir = (EP_DIR(ep) == DIR_IN) ? USB_DW_EPDIR_IN : USB_DW_EPDIR_OUT;
struct usb_dw_ep* dw_ep = usb_dw_get_ep(EP_NUM(ep), epdir);
usb_dw_target_disable_irq(); usb_dw_target_disable_irq();
usb_dw_unconfigure_ep(EP_NUM(endpoint), epdir); usb_dw_unconfigure_ep(EP_NUM(ep), epdir);
usb_dw_target_enable_irq(); usb_dw_target_enable_irq();
dw_ep->active = false; dw_ep->active = false;
return 0;
} }
int usb_drv_recv_nonblocking(int endpoint, void* ptr, int length) int usb_drv_recv_nonblocking(int endpoint, void* ptr, int length)

View file

@ -25,6 +25,7 @@
#include <inttypes.h> #include <inttypes.h>
#include "config.h" #include "config.h"
#include "cpu.h"
#ifndef REG32_PTR_T #ifndef REG32_PTR_T
#define REG32_PTR_T volatile uint32_t * #define REG32_PTR_T volatile uint32_t *
@ -288,4 +289,13 @@ extern void usb_dw_target_enable_irq(void);
extern void usb_dw_target_disable_irq(void); extern void usb_dw_target_disable_irq(void);
extern void usb_dw_target_clear_irq(void); extern void usb_dw_target_clear_irq(void);
/* endpoint allocation */
struct usb_drv_ep_alloc_ctx_dw
{
int8_t type[USB_NUM_ENDPOINTS][2];
uint16_t txfifo_usage;
uint8_t assigned_txfifos[USB_NUM_ENDPOINTS];
};
#define usb_drv_ep_alloc_ctx usb_drv_ep_alloc_ctx_dw
#endif /* __USB_DESIGNWARE_H__ */ #endif /* __USB_DESIGNWARE_H__ */

View file

@ -62,19 +62,42 @@ enum usb_control_response {
USB_CONTROL_RECEIVE, USB_CONTROL_RECEIVE,
}; };
/* endpoint allocation:
* there are two ways to implement endpoint allocation.
* 1. define usb_drv_ep_specs and usb_drv_ep_specs_flags in the driver.
* this is the simplest option when the types accepted by each endpoint are mutually independent.
* these variables are set only once during driver initialization and should not be modified afterward.
* 2. define usb_drv_ep_alloc_ctx and implement usb_drv_ep_reset_alloc_ctx and usb_drv_ep_allocate in the driver.
* if the available endpoint types change based on allocation status,
* these functions can be overridden to allow the driver to track the endpoint state.
* */
#ifndef usb_drv_ep_alloc_ctx
/* option 1 */
#define USB_ENDPOINT_TYPE_ANY (-1) #define USB_ENDPOINT_TYPE_ANY (-1)
#define USB_ENDPOINT_TYPE_NONE (-2) #define USB_ENDPOINT_TYPE_NONE (-2)
struct usb_drv_ep_spec { struct usb_drv_ep_spec {
int8_t type[2]; /* USB_ENDPOINT_TYPE_{ANY,NONE} USB_ENDPOINT_XFER_* */ int8_t type[2]; /* USB_ENDPOINT_TYPE_{ANY,NONE} USB_ENDPOINT_XFER_* */
}; };
extern struct usb_drv_ep_spec usb_drv_ep_specs[USB_NUM_ENDPOINTS]; extern struct usb_drv_ep_spec usb_drv_ep_specs[USB_NUM_ENDPOINTS];
#define USB_ENDPOINT_SPEC_FORCE_IO_TYPE_MATCH (1 << 0) #define USB_ENDPOINT_SPEC_FORCE_IO_TYPE_MATCH (1 << 0)
#define USB_ENDPOINT_SPEC_IO_EXCLUSIVE (1 << 1) #define USB_ENDPOINT_SPEC_IO_EXCLUSIVE (1 << 1)
extern uint8_t usb_drv_ep_specs_flags; extern uint8_t usb_drv_ep_specs_flags;
struct usb_drv_ep_alloc_ctx {
int8_t type[USB_NUM_ENDPOINTS][2];
int max_packet_size[USB_NUM_ENDPOINTS][2];
};
#else
/* option 2 */
void usb_drv_ep_reset_alloc_ctx(struct usb_drv_ep_alloc_ctx* ctx);
bool usb_drv_ep_allocate(struct usb_drv_ep_alloc_ctx* ctx, int ep, int type, int max_packet_size);
#endif
void usb_drv_ep_init(const struct usb_drv_ep_alloc_ctx* ctx, int ep);
void usb_drv_ep_deinit(const struct usb_drv_ep_alloc_ctx* ctx, int ep);
/* one-time initialisation of the USB driver */ /* one-time initialisation of the USB driver */
void usb_drv_startup(void); void usb_drv_startup(void);
void usb_drv_int_enable(bool enable); /* Target implemented */ void usb_drv_int_enable(bool enable); /* Target implemented */
@ -98,8 +121,6 @@ int usb_drv_port_speed(void);
void usb_drv_cancel_all_transfers(void); void usb_drv_cancel_all_transfers(void);
void usb_drv_set_test_mode(int mode); void usb_drv_set_test_mode(int mode);
bool usb_drv_connected(void); bool usb_drv_connected(void);
int usb_drv_init_endpoint(int endpoint, int type, int max_packet_size);
int usb_drv_deinit_endpoint(int endpoint);
#ifdef USB_HAS_ISOCHRONOUS #ifdef USB_HAS_ISOCHRONOUS
/* returns the last received frame number (the 11-bit number contained in the last SOF): /* returns the last received frame number (the 11-bit number contained in the last SOF):
* - full-speed: the host sends one SOF every 1ms (so 1000 SOF/s) * - full-speed: the host sends one SOF every 1ms (so 1000 SOF/s)

View file

@ -343,37 +343,37 @@ int usb_drv_port_speed(void)
return (USB_DEV_STS & USB_DEV_STS_MASK_SPD) ? 0 : 1; return (USB_DEV_STS & USB_DEV_STS_MASK_SPD) ? 0 : 1;
} }
int usb_drv_init_endpoint(int endpoint, int type, int max_packet_size) { void usb_drv_ep_init(const struct usb_drv_ep_alloc_ctx* ctx, int ep)
(void)max_packet_size; {
/* FIXME: support max packet size override */
const int epnum = EP_NUM(ep);
const int epdir = EP_DIR(ep);
const int type = ctx->type[epnum][epdir];
int i = EP_NUM(endpoint); if (epdir == DIR_IN) {
// int d = EP_DIR(endpoint) == DIR_IN ? 0 : 1; USB_IEP_CTRL(epnum) = USB_EP_CTRL_FLUSH |
USB_EP_CTRL_SNAK |
if (EP_DIR(endpoint) == DIR_IN) { USB_EP_CTRL_ACT |
USB_IEP_CTRL(i) = USB_EP_CTRL_FLUSH | (type << 4);
USB_EP_CTRL_SNAK | USB_DEV_EP_INTR_MASK &= ~(1<<epnum);
USB_EP_CTRL_ACT |
(type << 4);
USB_DEV_EP_INTR_MASK &= ~(1<<i);
} else { } else {
USB_OEP_CTRL(i) = USB_EP_CTRL_FLUSH | USB_OEP_CTRL(epnum) = USB_EP_CTRL_FLUSH |
USB_EP_CTRL_SNAK | USB_EP_CTRL_SNAK |
USB_EP_CTRL_ACT | USB_EP_CTRL_ACT |
(type << 4); (type << 4);
USB_DEV_EP_INTR_MASK &= ~(1<<(16+i)); USB_DEV_EP_INTR_MASK &= ~(1<<(16+epnum));
} }
return 0;
} }
int usb_drv_deinit_endpoint(int endpoint) { void usb_drv_ep_deinit(const struct usb_drv_ep_alloc_ctx* ctx, int ep)
int i = EP_NUM(endpoint); {
int d = EP_DIR(endpoint) == DIR_IN ? 0 : 1; (void)ctx;
int i = EP_NUM(ep);
int d = EP_DIR(ep) == DIR_IN ? 0 : 1;
endpoints[i][d].state = 0; endpoints[i][d].state = 0;
USB_DEV_EP_INTR_MASK |= (1<<(16*d+i)); USB_DEV_EP_INTR_MASK |= (1<<(16*d+i));
USB_EP_CTRL(i, !d) = USB_EP_CTRL_FLUSH | USB_EP_CTRL_SNAK; USB_EP_CTRL(i, !d) = USB_EP_CTRL_FLUSH | USB_EP_CTRL_SNAK;
return 0;
} }
void usb_drv_cancel_all_transfers(void) void usb_drv_cancel_all_transfers(void)

View file

@ -280,27 +280,30 @@ int usb_drv_port_speed(void)
return (DEV_INFO & DEV_SPEED) ? 0 : 1; return (DEV_INFO & DEV_SPEED) ? 0 : 1;
} }
int usb_drv_init_endpoint(int endpoint, int type, int max_packet_size) { void usb_drv_ep_init(const struct usb_drv_ep_alloc_ctx* ctx, int ep)
(void)max_packet_size; /* FIXME: support max packet size override */ {
/* FIXME: support max packet size override */
(void)ctx;
int num = EP_NUM(endpoint); const int epnum = EP_NUM(ep);
// int dir = EP_DIR(endpoint); const int epdir = EP_DIR(ep);
(void)type;
struct endpoint_t *endp = &endpoints[num]; struct endpoint_t *endp = &endpoints[epnum];
if(EP_DIR(endpoint) == DIR_IN) if(epdir == DIR_IN)
TXCON(endp) = (num << 8) | TXEPEN | TXNAK | TXACKINTEN | TXCFINTE; TXCON(endp) = (epnum << 8) | TXEPEN | TXNAK | TXACKINTEN | TXCFINTE;
else else
RXCON(endp) = (num << 8) | RXEPEN | RXNAK | RXACKINTEN | RXCFINTE | RXERRINTEN; RXCON(endp) = (epnum << 8) | RXEPEN | RXNAK | RXACKINTEN | RXCFINTE | RXERRINTEN;
EN_INT |= 1 << (num + 7); EN_INT |= 1 << (epnum + 7);
return 0; return 0;
} }
int usb_drv_deinit_endpoint(int endpoint) { void usb_drv_ep_deinit(const struct usb_drv_ep_alloc_ctx* ctx, int ep)
int num = EP_NUM(endpoint); {
// struct endpoint_t *endp = &endpoints[num]; (void)ctx;
int num = EP_NUM(ep);
/* disable interrupt from this endpoint */ /* disable interrupt from this endpoint */
EN_INT &= ~(1 << (num + 7)); EN_INT &= ~(1 << (num + 7));

View file

@ -1489,17 +1489,21 @@ void usb_drv_set_test_mode(int mode)
tnetv_usb_reg_write(TNETV_USB_CTRL, usbCtrl.val); tnetv_usb_reg_write(TNETV_USB_CTRL, usbCtrl.val);
} }
int usb_drv_init_endpoint(int endpoint, int type, int max_packet_size) { void usb_drv_ep_init(const struct usb_drv_ep_alloc_ctx* ctx, int ep)
(void)max_packet_size; /* FIXME: support max packet size override */ {
(void)type; /* FIXME: support max packet size override */
(void)ctx;
int num = EP_NUM(endpoint); int num = EP_NUM(ep);
int dir = EP_DIR(endpoint); int dir = EP_DIR(ep);
return tnetv_gadget_ep_enable(num, dir == DIR_IN); return tnetv_gadget_ep_enable(num, dir == DIR_IN);
} }
int usb_drv_deinit_endpoint(int endpoint) { void usb_drv_ep_deinit(const struct usb_drv_ep_alloc_ctx* ctx, int ep)
int num = EP_NUM(endpoint); {
int dir = EP_DIR(endpoint); (void)ctx;
int num = EP_NUM(ep);
int dir = EP_DIR(ep);
return tnetv_gadget_ep_disable(num, dir == DIR_IN); return tnetv_gadget_ep_disable(num, dir == DIR_IN);
} }

View file

@ -451,6 +451,42 @@ void usb_drv_startup(void)
((type) == USB_ENDPOINT_XFER_INT ? "INTR" : "INVL")))) ((type) == USB_ENDPOINT_XFER_INT ? "INTR" : "INVL"))))
#endif #endif
static void init_endpoint(int ep, int type, int mps) {
const int ep_num = EP_NUM(ep);
const int ep_dir = EP_DIR(ep);
logf("ep init: %d %s %s", ep_num, XFER_DIR_STR(ep_dir), XFER_TYPE_STR(type));
struct queue_head* qh;
unsigned int ctrl = REG_ENDPTCTRL(ep_num);
if(ep_dir == DIR_IN) {
ctrl &= ~EPCTRL_TX_TYPE;
ctrl |= EPCTRL_TX_DATA_TOGGLE_RST | EPCTRL_TX_ENABLE | type << EPCTRL_TX_EP_TYPE_SHIFT;
qh = &qh_array[ep_num * 2 + 1];
} else {
ctrl &= ~EPCTRL_RX_TYPE;
ctrl |= EPCTRL_RX_DATA_TOGGLE_RST | EPCTRL_RX_ENABLE | type << EPCTRL_RX_EP_TYPE_SHIFT;
qh = &qh_array[ep_num * 2];
}
REG_ENDPTCTRL(ep_num) = ctrl;
if(mps == -1) {
if(type == USB_ENDPOINT_XFER_ISOC) {
mps = 1024;
} else {
mps = usb_drv_port_speed() ? 512 : 64;
}
}
if(type == USB_ENDPOINT_XFER_ISOC)
/* FIXME: we can adjust the number of packets per frame, currently use one */
qh->max_pkt_length = mps << QH_MAX_PKT_LEN_POS | QH_ZLT_SEL | 1 << QH_MULT_POS;
else
qh->max_pkt_length = mps << QH_MAX_PKT_LEN_POS | QH_ZLT_SEL;
qh->dtd.next_td_ptr = QH_NEXT_TERMINATE;
}
/* manual: 32.14.1 Device Controller Initialization */ /* manual: 32.14.1 Device Controller Initialization */
void usb_drv_init(void) void usb_drv_init(void)
{ {
@ -494,8 +530,8 @@ void usb_drv_init(void)
* will cause undefined behavior for the data pid tracking on the active * will cause undefined behavior for the data pid tracking on the active
* endpoint/direction. */ * endpoint/direction. */
for(int ep_num=1;ep_num<USB_NUM_ENDPOINTS;ep_num++) { for(int ep_num=1;ep_num<USB_NUM_ENDPOINTS;ep_num++) {
usb_drv_init_endpoint(ep_num | USB_DIR_IN, USB_ENDPOINT_XFER_BULK, -1); init_endpoint(ep_num | USB_DIR_IN, USB_ENDPOINT_XFER_BULK, -1);
usb_drv_init_endpoint(ep_num | USB_DIR_OUT, USB_ENDPOINT_XFER_BULK, -1); init_endpoint(ep_num | USB_DIR_OUT, USB_ENDPOINT_XFER_BULK, -1);
} }
} }
@ -984,46 +1020,16 @@ void usb_drv_cancel_all_transfers(void)
} }
} }
int usb_drv_init_endpoint(int endpoint, int type, int max_packet_size) { void usb_drv_ep_init(const struct usb_drv_ep_alloc_ctx* ctx, int ep) {
int ep_num = EP_NUM(endpoint); const int ep_num = EP_NUM(ep);
int ep_dir = EP_DIR(endpoint); const int ep_dir = EP_DIR(ep);
init_endpoint(ep, ctx->type[ep_num][ep_dir], ctx->max_packet_size[ep_num][ep_dir]);
logf("ep init: %d %s %s", ep_num, XFER_DIR_STR(ep_dir), XFER_TYPE_STR(type));
struct queue_head* qh;
unsigned int ctrl = REG_ENDPTCTRL(ep_num);
if(ep_dir == DIR_IN) {
ctrl &= ~EPCTRL_TX_TYPE;
ctrl |= EPCTRL_TX_DATA_TOGGLE_RST | EPCTRL_TX_ENABLE | type << EPCTRL_TX_EP_TYPE_SHIFT;
qh = &qh_array[ep_num * 2 + 1];
} else {
ctrl &= ~EPCTRL_RX_TYPE;
ctrl |= EPCTRL_RX_DATA_TOGGLE_RST | EPCTRL_RX_ENABLE | type << EPCTRL_RX_EP_TYPE_SHIFT;
qh = &qh_array[ep_num * 2];
}
REG_ENDPTCTRL(ep_num) = ctrl;
if(max_packet_size == -1) {
if(type == USB_ENDPOINT_XFER_ISOC) {
max_packet_size = 1024;
} else {
max_packet_size = usb_drv_port_speed() ? 512 : 64;
}
}
if(type == USB_ENDPOINT_XFER_ISOC)
/* FIXME: we can adjust the number of packets per frame, currently use one */
qh->max_pkt_length = max_packet_size << QH_MAX_PKT_LEN_POS | QH_ZLT_SEL | 1 << QH_MULT_POS;
else
qh->max_pkt_length = max_packet_size << QH_MAX_PKT_LEN_POS | QH_ZLT_SEL;
qh->dtd.next_td_ptr = QH_NEXT_TERMINATE;
return 0;
} }
int usb_drv_deinit_endpoint(int endpoint) { void usb_drv_ep_deinit(const struct usb_drv_ep_alloc_ctx* ctx, int ep) {
int ep_num = EP_NUM(endpoint); (void)ctx;
int ep_dir = EP_DIR(endpoint); int ep_num = EP_NUM(ep);
int ep_dir = EP_DIR(ep);
logf("ep deinit: %d %s", ep_num, XFER_DIR_STR(ep_dir)); logf("ep deinit: %d %s", ep_num, XFER_DIR_STR(ep_dir));
@ -1032,8 +1038,6 @@ int usb_drv_deinit_endpoint(int endpoint) {
} else { } else {
REG_ENDPTCTRL(ep_num) &= ~EPCTRL_RX_ENABLE & ~EPCTRL_RX_TYPE; REG_ENDPTCTRL(ep_num) &= ~EPCTRL_RX_ENABLE & ~EPCTRL_RX_TYPE;
} }
return 0;
} }
static void prepare_td(struct transfer_descriptor* td, static void prepare_td(struct transfer_descriptor* td,

View file

@ -588,19 +588,23 @@ void INT_USB_FUNC(void)
GINTSTS = sts; GINTSTS = sts;
} }
int usb_drv_init_endpoint(int endpoint, int type, int max_packet_size) { void usb_drv_ep_init(const struct usb_drv_ep_alloc_ctx* ctx, int ep)
(void)max_packet_size; /* FIXME: support max packet size override */ {
/* FIXME: support max packet size override */
(void)ctx;
int num = EP_NUM(endpoint); const int epnum = EP_NUM(ep);
int dir = EP_DIR(endpoint); const int epdir = EP_DIR(ep);
bool out = dir == DIR_OUT; const int type = ctx->type[epnum][epdir];
DEPCTL(num, out) = (DEPCTL(num, out) & ~(DEPCTL_eptype_bits << DEPCTL_eptype_bitp))
bool out = epdir == DIR_OUT;
DEPCTL(epnum, out) = (DEPCTL(epnum, out) & ~(DEPCTL_eptype_bits << DEPCTL_eptype_bitp))
| DEPCTL_setd0pid | (type << DEPCTL_eptype_bitp) | DEPCTL_usbactep; | DEPCTL_setd0pid | (type << DEPCTL_eptype_bitp) | DEPCTL_usbactep;
return 0;
} }
int usb_drv_deinit_endpoint(int endpoint) { void usb_drv_ep_deinit(const struct usb_drv_ep_alloc_ctx* ctx, int ep)
return 0; {
(void)ctx;
} }
void usb_drv_cancel_all_transfers() void usb_drv_cancel_all_transfers()

View file

@ -100,16 +100,17 @@ static struct tcc_ep tcc_endpoints[] = {
static bool usb_drv_write_ep(struct tcc_ep *ep); static bool usb_drv_write_ep(struct tcc_ep *ep);
static void usb_set_speed(int); static void usb_set_speed(int);
int usb_drv_init_endpoint(int endpoint, int type, int max_packet_size) { void usb_drv_ep_init(const struct usb_drv_ep_alloc_ctx* ctx, int ep)
(void)max_packet_size; /* FIXME: support max packet size override */ {
/* FIXME: support max packet size override */
tcc_endpoints[EP_NUM(endpoint)].dir = EP_DIR(endpoint) == DIR_IN ? USB_DIR_IN : USB_DIR_OUT; (void)ctx;
return 0; tcc_endpoints[EP_NUM(ep)].dir = EP_DIR(ep) == DIR_IN ? USB_DIR_IN : USB_DIR_OUT;
} }
int usb_drv_deinit_endpoint(int endpoint) { void usb_drv_ep_deinit(const struct usb_drv_ep_alloc_ctx* ctx, int ep)
tcc_endpoints[EP_NUM(endpoint)].dir = -1; {
return 0; (void)ctx;
tcc_endpoints[EP_NUM(ep)].dir = -1;
} }
static inline void pullup_on(void) static inline void pullup_on(void)

View file

@ -836,14 +836,15 @@ void usb_drv_cancel_all_transfers(void)
restore_irq(flags); restore_irq(flags);
} }
int usb_drv_init_endpoint(int endpoint, int type, int max_packet_size) { void usb_drv_ep_init(const struct usb_drv_ep_alloc_ctx* ctx, int ep)
(void)endpoint; {
(void)type; /* FIXME: support max packet size override */
(void)max_packet_size; /* FIXME: support max packet size override */ (void)ctx;
return 0; (void)ep;
} }
int usb_drv_deinit_endpoint(int endpoint) { void usb_drv_ep_deinit(const struct usb_drv_ep_alloc_ctx* ctx, int ep)
(void)endpoint; {
return 0; (void)ctx;
(void)ep;
} }

View file

@ -1192,12 +1192,12 @@ void usb_drv_cancel_all_transfers(void)
restore_irq(flags); restore_irq(flags);
} }
int usb_drv_init_endpoint(int endpoint, int type, int max_packet_size) { void usb_drv_ep_init(const struct usb_drv_ep_alloc_ctx* ctx, int ep)
(void)max_packet_size; /* FIXME: support max packet size override */ {
(void)type; /* FIXME: support max packet size override */
(void)ctx;
int num = EP_NUM(endpoint); int num = EP_NUM(ep);
int dir = EP_DIR(endpoint); int dir = EP_DIR(ep);
int index = num * 2 + (dir == DIR_OUT ? 1 : 0); int index = num * 2 + (dir == DIR_OUT ? 1 : 0);
endpoints[index].allocated = true; endpoints[index].allocated = true;
if(dir == DIR_IN) if(dir == DIR_IN)
@ -1207,9 +1207,11 @@ int usb_drv_init_endpoint(int endpoint, int type, int max_packet_size) {
return 0; return 0;
} }
int usb_drv_deinit_endpoint(int endpoint) { void usb_drv_ep_deinit(const struct usb_drv_ep_alloc_ctx* ctx, int ep)
int num = EP_NUM(endpoint); {
int dir = EP_DIR(endpoint); (void)ctx;
int num = EP_NUM(ep);
int dir = EP_DIR(ep);
int index = num * 2 + (dir == DIR_OUT ? 1 : 0); int index = num * 2 + (dir == DIR_OUT ? 1 : 0);
endpoints[index].allocated = false; endpoints[index].allocated = false;
if(dir == DIR_IN) if(dir == DIR_IN)

View file

@ -28,7 +28,6 @@
#include "usb.h" #include "usb.h"
#include "usb_ch9.h" #include "usb_ch9.h"
#include "usb_drv.h"
#include "usb_core.h" #include "usb_core.h"
#include "usb_class_driver.h" #include "usb_class_driver.h"
@ -57,6 +56,12 @@
#include "usb_iap.h" #include "usb_iap.h"
#endif #endif
/* include order matters, include driver header before usb_drv.h */
#if CONFIG_USBOTG == USBOTG_DESIGNWARE
#include "usb-designware.h"
#endif
#include "usb_drv.h"
/* TODO: Move target-specific stuff somewhere else (serial number reading) */ /* TODO: Move target-specific stuff somewhere else (serial number reading) */
#if defined(IPOD_ARCH) && defined(CPU_PP) #if defined(IPOD_ARCH) && defined(CPU_PP)
@ -179,8 +184,6 @@ static int usb_no_host_callback(struct timeout *tmo)
} }
#endif #endif
static int usb_core_num_interfaces[NUM_CONFIGS];
typedef void (*completion_handler_t)(int ep, int dir, int status, int length); typedef void (*completion_handler_t)(int ep, int dir, int status, int length);
typedef bool (*fast_completion_handler_t)(int ep, int dir, int status, int length); typedef bool (*fast_completion_handler_t)(int ep, int dir, int status, int length);
typedef bool (*control_handler_t)(struct usb_ctrlrequest* req, void* reqdata, typedef bool (*control_handler_t)(struct usb_ctrlrequest* req, void* reqdata,
@ -199,7 +202,13 @@ struct ep_alloc_state {
struct usb_class_driver* owner[2]; struct usb_class_driver* owner[2];
}; };
static struct ep_alloc_state ep_alloc_states[NUM_CONFIGS][USB_NUM_ENDPOINTS]; struct config_state {
struct usb_drv_ep_alloc_ctx ep_alloc_ctx;
struct ep_alloc_state ep_alloc_states[USB_NUM_ENDPOINTS];
uint8_t num_interfaces;
};
struct config_state config_states[NUM_CONFIGS];
static struct usb_class_driver* drivers[USB_NUM_DRIVERS] = static struct usb_class_driver* drivers[USB_NUM_DRIVERS] =
{ {
@ -407,9 +416,6 @@ void usb_core_init(void)
} }
} }
/* clear endpoint allocation state */
memset(ep_alloc_states, 0, sizeof(ep_alloc_states));
initialized = true; initialized = true;
usb_state = DEFAULT; usb_state = DEFAULT;
usb_config = 0; usb_config = 0;
@ -548,52 +554,86 @@ static void usb_core_set_serial_function_id(void)
} }
/* synchronize endpoint initialization state to allocation state */ /* synchronize endpoint initialization state to allocation state */
static void init_deinit_endpoints(uint8_t conf_index, bool init) { static void init_deinit_endpoints(int config, bool init) {
for(int epnum = 0; epnum < USB_NUM_ENDPOINTS; epnum += 1) { for(int epnum = 0; epnum < USB_NUM_ENDPOINTS; epnum += 1) {
for(int dir = 0; dir < 2; dir += 1) { for(int dir = 0; dir < 2; dir += 1) {
struct ep_alloc_state* alloc = &ep_alloc_states[conf_index][epnum]; struct config_state* cstate = &config_states[config - 1];
struct usb_class_driver* driver = alloc->owner[dir]; struct ep_alloc_state* astate = &cstate->ep_alloc_states[epnum];
struct usb_class_driver* driver = astate->owner[dir];
if(driver == NULL) { if(driver == NULL) {
continue; continue;
} }
int ep = epnum | (dir == DIR_OUT ? USB_DIR_OUT : USB_DIR_IN); int ep = epnum | (dir == DIR_OUT ? USB_DIR_OUT : USB_DIR_IN);
int ret;
if(init) {
int ps = driver->get_max_packet_size ? driver->get_max_packet_size(ep) : -1;
ret = usb_drv_init_endpoint(ep, alloc->type[dir], ps);
} else {
ret = usb_drv_deinit_endpoint(ep);
}
if(ret) {
logf("usb_core: usb_drv_%s_endpoint failed ep=%d dir=%d", init ? "init" : "deinit", epnum, dir);
continue;
}
if(init) { if(init) {
usb_drv_ep_init(&cstate->ep_alloc_ctx, ep);
ep_data[epnum].completion_handler[dir] = driver->transfer_complete; ep_data[epnum].completion_handler[dir] = driver->transfer_complete;
ep_data[epnum].fast_completion_handler[dir] = driver->fast_transfer_complete; ep_data[epnum].fast_completion_handler[dir] = driver->fast_transfer_complete;
ep_data[epnum].control_handler[dir] = driver->control_request; ep_data[epnum].control_handler[dir] = driver->control_request;
} else {
usb_drv_ep_deinit(&cstate->ep_alloc_ctx, ep);
} }
} }
} }
} }
#ifndef usb_drv_ep_alloc_ctx
/* default endpoint allocator using usb_drv_ep_specs table */
static void usb_drv_ep_reset_alloc_ctx(struct usb_drv_ep_alloc_ctx* ctx) {
for(int i = 0; i < USB_NUM_ENDPOINTS; i += 1) {
ctx->type[i][0] = -1;
ctx->type[i][1] = -1;
}
}
static bool usb_drv_ep_allocate(struct usb_drv_ep_alloc_ctx* ctx, int ep, int type, int max_packet_size) {
const uint8_t epnum = EP_NUM(ep);
const uint8_t epdir = EP_DIR(ep);
struct usb_drv_ep_spec* spec = &usb_drv_ep_specs[epnum];
const int8_t spec_type = spec->type[epdir];
if(spec_type != type && spec_type != USB_ENDPOINT_TYPE_ANY) {
return false;
}
const int8_t other_type = ctx->type[epnum][!epdir];
if(usb_drv_ep_specs_flags & USB_ENDPOINT_SPEC_IO_EXCLUSIVE && other_type != -1) {
/* the other side is allocated */
return false;
}
if(usb_drv_ep_specs_flags & USB_ENDPOINT_SPEC_FORCE_IO_TYPE_MATCH && other_type != -1 && other_type != type) {
/* the other side is allocated with another type */
return false;
}
ctx->type[epnum][epdir] = type;
ctx->max_packet_size[epnum][epdir] = max_packet_size;
return true;
}
#endif
static void allocate_interfaces_and_endpoints(void) static void allocate_interfaces_and_endpoints(void)
{ {
if(usb_config != 0) { if(usb_config != 0) {
/* deinit currently used endpoints */ /* deinit currently used endpoints */
init_deinit_endpoints(usb_config - 1, false); init_deinit_endpoints(usb_config, false);
} }
retry:
/* reset allocations */ /* reset allocations */
memset(ep_alloc_states, 0, sizeof(ep_alloc_states)); for(int i = 0; i < NUM_CONFIGS; i += 1) {
config_states[i].num_interfaces = 0;
int interface[NUM_CONFIGS] = {0}; memset(config_states[i].ep_alloc_states, 0, sizeof(config_states[i].ep_alloc_states));
usb_drv_ep_reset_alloc_ctx(&config_states[i].ep_alloc_ctx);
}
for(int i = 0; i < USB_NUM_DRIVERS; i++) { for(int i = 0; i < USB_NUM_DRIVERS; i++) {
struct usb_class_driver* driver = drivers[i]; struct usb_class_driver* driver = drivers[i];
const uint8_t conf_index = driver->config - 1; struct config_state* cstate = &config_states[driver->config - 1];
if(!driver->enabled) { if(!driver->enabled || driver->error) {
continue; continue;
} }
@ -603,69 +643,38 @@ static void allocate_interfaces_and_endpoints(void)
struct usb_class_driver_ep_allocation* req = &driver->ep_allocs[reqnum]; struct usb_class_driver_ep_allocation* req = &driver->ep_allocs[reqnum];
req->ep = 0; req->ep = 0;
for(int epnum = 1; epnum < USB_NUM_ENDPOINTS; epnum += 1) { for(int epnum = 1; epnum < USB_NUM_ENDPOINTS; epnum += 1) {
struct usb_drv_ep_spec* spec = &usb_drv_ep_specs[epnum];
/* ep type check */
const int8_t spec_type = spec->type[req->dir];
if(spec_type != req->type && spec_type != USB_ENDPOINT_TYPE_ANY) {
continue;
}
/* free check */ /* free check */
struct ep_alloc_state* alloc = &ep_alloc_states[conf_index][epnum]; struct ep_alloc_state* alloc = &cstate->ep_alloc_states[epnum];
if(alloc->owner[req->dir] != NULL) { if(alloc->owner[req->dir] != NULL) {
continue; continue;
} }
/* this ep's requested direction is free */ /* driver specific check */
const int ep = epnum | (req->dir == DIR_OUT ? USB_DIR_OUT : USB_DIR_IN);
/* another checks */ const int ps = driver->get_max_packet_size ? driver->get_max_packet_size(ep) : -1;
if(usb_drv_ep_specs_flags & USB_ENDPOINT_SPEC_IO_EXCLUSIVE) { if(!usb_drv_ep_allocate(&cstate->ep_alloc_ctx, ep, req->type, ps)) {
/* check for the other direction type */ continue;
if(alloc->owner[!req->dir] != NULL) {
/* the other side is allocated */
continue;
}
}
if(usb_drv_ep_specs_flags & USB_ENDPOINT_SPEC_FORCE_IO_TYPE_MATCH) {
/* check for other direction type */
if(alloc->owner[!req->dir] != NULL && alloc->type[!req->dir] != req->type) {
/* the other side is allocated with another type */
continue;
}
} }
/* all checks passed, assign it */ /* all checks passed, assign it */
const int ep = epnum | (req->dir == DIR_OUT ? USB_DIR_OUT : USB_DIR_IN);
req->ep = ep; req->ep = ep;
alloc->owner[req->dir] = driver; alloc->owner[req->dir] = driver;
alloc->type[req->dir] = req->type; alloc->type[req->dir] = req->type;
break; break;
} }
if(req->ep == 0 && !req->optional) { if(req->ep == 0 && !req->optional) {
/* no matching ep found, disable the driver */ /* no matching ep found, retry allocation excluding this driver */
logf("usb_core: no endpoint allocated for driver %d", i);
driver->enabled = false; driver->enabled = false;
/* also revert all allocations for this driver */ goto retry;
for(reqnum = reqnum - 1; reqnum >= 0; reqnum -= 1) {
const uint8_t ep = driver->ep_allocs[reqnum].ep;
const uint8_t epnum = EP_NUM(ep);
const uint8_t epdir = EP_DIR(ep);
const uint8_t dir = epdir == USB_DIR_OUT ? DIR_OUT : DIR_IN;
ep_alloc_states[conf_index][epnum].owner[dir] = NULL;
}
break;
} }
} }
if(!driver->enabled) {
continue;
}
/* assign interfaces */ /* assign interfaces */
driver->first_interface = interface[conf_index]; driver->first_interface = cstate->num_interfaces;
interface[conf_index] = driver->set_first_interface(interface[conf_index]); cstate->num_interfaces = driver->set_first_interface(cstate->num_interfaces);
driver->last_interface = interface[conf_index]; driver->last_interface = cstate->num_interfaces;
} }
memcpy(usb_core_num_interfaces, interface, sizeof(interface));
} }
@ -765,7 +774,7 @@ static void request_handler_device_get_descriptor(struct usb_ctrlrequest* req, v
} }
} }
config_descriptor.bNumInterfaces = usb_core_num_interfaces[index]; config_descriptor.bNumInterfaces = config_states[index].num_interfaces;
config_descriptor.bConfigurationValue = index + 1; config_descriptor.bConfigurationValue = index + 1;
config_descriptor.wTotalLength = (uint16_t)size; config_descriptor.wTotalLength = (uint16_t)size;
memcpy(&response_data[0], &config_descriptor, sizeof(struct usb_config_descriptor)); memcpy(&response_data[0], &config_descriptor, sizeof(struct usb_config_descriptor));
@ -844,7 +853,7 @@ static int usb_core_do_set_config(uint8_t new_config)
drivers[i]->disconnect(); drivers[i]->disconnect();
} }
} }
init_deinit_endpoints(usb_config - 1, false); init_deinit_endpoints(usb_config, false);
/* clear any pending transfer completions, /* clear any pending transfer completions,
* because they are depend on contents of ep_data */ * because they are depend on contents of ep_data */
@ -861,7 +870,7 @@ static int usb_core_do_set_config(uint8_t new_config)
/* activate new config */ /* activate new config */
if(usb_config != 0) { if(usb_config != 0) {
init_deinit_endpoints(usb_config - 1, true); init_deinit_endpoints(usb_config, true);
for(int i = 0; i < USB_NUM_DRIVERS; i++) { for(int i = 0; i < USB_NUM_DRIVERS; i++) {
if(!is_active(drivers[i])) { if(!is_active(drivers[i])) {
continue; continue;