use dcd_edpt0_status_complete() to set address without blocking for samd21/samd51/stm32_fsdev

This commit is contained in:
hathach
2019-11-28 13:39:29 +07:00
parent ac701c398b
commit d7558e8a0f
7 changed files with 82 additions and 43 deletions

View File

@@ -98,13 +98,13 @@ void dcd_int_disable(uint8_t rhport)
void dcd_set_address (uint8_t rhport, uint8_t dev_addr)
{
// Response with status first before changing device address
dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0);
(void) dev_addr;
// Wait for EP0 to finish before switching the address.
while (USB->DEVICE.DeviceEndpoint[0].EPSTATUS.bit.BK1RDY == 1) {}
// Response with zlp status
dcd_edpt_xfer(rhport, 0x80, NULL, 0);
USB->DEVICE.DADD.reg = USB_DEVICE_DADD_DADD(dev_addr) | USB_DEVICE_DADD_ADDEN;
// DCD can only set address after status for this request is complete
// do it at dcd_edpt0_status_complete()
// Enable SUSPEND interrupt since the bus signal D+/D- are stable now.
USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTENCLR_SUSPEND; // clear pending
@@ -116,7 +116,6 @@ void dcd_set_config (uint8_t rhport, uint8_t config_num)
(void) rhport;
(void) config_num;
// Nothing to do
}
void dcd_remote_wakeup(uint8_t rhport)
@@ -130,6 +129,20 @@ void dcd_remote_wakeup(uint8_t rhport)
/* DCD Endpoint port
*------------------------------------------------------------------*/
// Invoked when a control transfer's status stage is complete.
// May help DCD to prepare for next control transfer, this API is optional.
void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * request)
{
(void) rhport;
if (request->bRequest == TUSB_REQ_SET_ADDRESS)
{
uint8_t const dev_addr = (uint8_t) request->wValue;
USB->DEVICE.DADD.reg = USB_DEVICE_DADD_DADD(dev_addr) | USB_DEVICE_DADD_ADDEN;
}
}
bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
{
(void) rhport;

View File

@@ -104,13 +104,13 @@ void dcd_int_disable(uint8_t rhport)
void dcd_set_address (uint8_t rhport, uint8_t dev_addr)
{
// Response with status first before changing device address
dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0);
(void) dev_addr;
// Wait for EP0 to finish before switching the address.
while (USB->DEVICE.DeviceEndpoint[0].EPSTATUS.bit.BK1RDY == 1) {}
// Response with zlp status
dcd_edpt_xfer(rhport, 0x80, NULL, 0);
USB->DEVICE.DADD.reg = USB_DEVICE_DADD_DADD(dev_addr) | USB_DEVICE_DADD_ADDEN;
// DCD can only set address after status for this request is complete
// do it at dcd_edpt0_status_complete()
// Enable SUSPEND interrupt since the bus signal D+/D- are stable now.
USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTENCLR_SUSPEND; // clear pending
@@ -135,6 +135,19 @@ void dcd_remote_wakeup(uint8_t rhport)
/* DCD Endpoint port
*------------------------------------------------------------------*/
// Invoked when a control transfer's status stage is complete.
// May help DCD to prepare for next control transfer, this API is optional.
void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * request)
{
(void) rhport;
if (request->bRequest == TUSB_REQ_SET_ADDRESS)
{
uint8_t const dev_addr = (uint8_t) request->wValue;
USB->DEVICE.DADD.reg = USB_DEVICE_DADD_DADD(dev_addr) | USB_DEVICE_DADD_ADDEN;
}
}
bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
{
(void) rhport;

View File

@@ -120,7 +120,10 @@ void dcd_set_address (uint8_t rhport, uint8_t dev_addr)
(void) rhport;
(void) dev_addr;
// SAMG can only set address after status for this request is complete
// Response with zlp status
dcd_edpt_xfer(rhport, 0x80, NULL, 0);
// DCD can only set address after status for this request is complete.
// do it at dcd_edpt0_status_complete()
}

View File

@@ -172,7 +172,6 @@ static inline xfer_ctl_t* xfer_ctl_ptr(uint32_t epnum, uint32_t dir)
static TU_ATTR_ALIGNED(4) uint32_t _setup_packet[6];
static uint8_t newDADDR; // Used to set the new device address during the CTR IRQ handler
static uint8_t remoteWakeCountdown; // When wake is requested
// EP Buffers assigned from end of memory location, to minimize their chance of crashing
@@ -297,14 +296,11 @@ void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
{
(void)rhport;
// FIXME use dcd_edpt0_status_complete()
// We cannot immediatly change it; it must be queued to change after the STATUS packet is sent.
// (CTR handler will actually change the address once it sees that the transmission is complete)
newDADDR = dev_addr;
// Respond with status
dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0);
// DCD can only set address after status for this request is complete.
// do it at dcd_edpt0_status_complete()
}
// Receive Set Config request
@@ -361,7 +357,7 @@ static void dcd_handle_bus_reset(void)
ep_buf_ptr = DCD_STM32_BTABLE_BASE + 8*MAX_EP_COUNT; // 8 bytes per endpoint (two TX and two RX words, each)
dcd_edpt_open (0, &ep0OUT_desc);
dcd_edpt_open (0, &ep0IN_desc);
newDADDR = 0u;
USB->DADDR = USB_DADDR_EF; // Set enable flag, and leaving the device address as zero.
}
@@ -397,13 +393,7 @@ static uint16_t dcd_ep_ctr_handler(void)
if((xfer->total_len == xfer->queued_len))
{
dcd_event_xfer_complete(0u, (uint8_t)(0x80 + EPindex), xfer->total_len, XFER_RESULT_SUCCESS, true);
if((newDADDR != 0) && ( xfer->total_len == 0U))
{
// Delayed setting of the DADDR after the 0-len DATA packet acking the request is sent.
reg16_clear_bits(&USB->DADDR, USB_DADDR_ADD);
USB->DADDR = (uint16_t)(USB->DADDR | newDADDR); // leave the enable bit set
newDADDR = 0;
}
if(xfer->total_len == 0) // Probably a status message?
{
pcd_clear_rx_dtog(USB,EPindex);
@@ -601,6 +591,22 @@ static void dcd_fs_irqHandler(void) {
// Endpoint API
//--------------------------------------------------------------------+
// Invoked when a control transfer's status stage is complete.
// May help DCD to prepare for next control transfer, this API is optional.
void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * request)
{
(void) rhport;
if (request->bRequest == TUSB_REQ_SET_ADDRESS)
{
uint8_t const dev_addr = (uint8_t) request->wValue;
// Setting new address after the whole request is complete
reg16_clear_bits(&USB->DADDR, USB_DADDR_ADD);
USB->DADDR = (uint16_t)(USB->DADDR | dev_addr); // leave the enable bit set
}
}
// The STM32F0 doesn't seem to like |= or &= to manipulate the EP#R registers,
// so I'm using the #define from HAL here, instead.

View File

@@ -236,7 +236,6 @@ void dcd_set_address (uint8_t rhport, uint8_t dev_addr)
(void) rhport;
USB_OTG_DeviceTypeDef * dev = DEVICE_BASE;
dev->DCFG |= (dev_addr << USB_OTG_DCFG_DAD_Pos) & USB_OTG_DCFG_DAD_Msk;
// Response with status after changing device address