summaryrefslogtreecommitdiff
path: root/src/portable
diff options
context:
space:
mode:
authorGavin Li <[email protected]>2020-10-05 22:40:00 -0700
committerGavin Li <[email protected]>2020-10-06 14:43:10 -0700
commit020ad47bb004cb01e2c7834a34d74da66cef3532 (patch)
tree2a087585a91d38ee0a00bace5a638a43a33f7d4f /src/portable
parent8b2c82255750488232eae72f3d5dcbacfd6227f3 (diff)
stm32: fix ISTR and CTR_RX/TX race conditions
Diffstat (limited to 'src/portable')
-rw-r--r--src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c18
-rw-r--r--src/portable/st/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h8
2 files changed, 17 insertions, 9 deletions
diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
index 32179874e..033d7cbd7 100644
--- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
+++ b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
@@ -203,6 +203,11 @@ static inline void reg16_clear_bits(__IO uint16_t *reg, uint16_t mask) {
*reg = (uint16_t)(*reg & ~mask);
}
+// Bits in ISTR are cleared upon writing 0
+static inline void clear_istr_bits(uint16_t mask) {
+ USB->ISTR = ~mask;
+}
+
void dcd_init (uint8_t rhport)
{
/* Clocks should already be enabled */
@@ -231,7 +236,7 @@ void dcd_init (uint8_t rhport)
USB->BTABLE = DCD_STM32_BTABLE_BASE;
- reg16_clear_bits(&USB->ISTR, USB_ISTR_ALL_EVENTS); // Clear pending interrupts
+ USB->ISTR = 0; // Clear pending interrupts
// Reset endpoints to disabled
for(uint32_t i=0; i<STFSDEV_EP_COUNT; i++)
@@ -512,7 +517,7 @@ void dcd_int_handler(uint8_t rhport) {
if(int_status & USB_ISTR_RESET) {
// USBRST is start of reset.
- reg16_clear_bits(&USB->ISTR, USB_ISTR_RESET);
+ clear_istr_bits(USB_ISTR_RESET);
dcd_handle_bus_reset();
dcd_event_bus_signal(0, DCD_EVENT_BUS_RESET, true);
return; // Don't do the rest of the things here; perhaps they've been cleared?
@@ -523,14 +528,13 @@ void dcd_int_handler(uint8_t rhport) {
/* servicing of the endpoint correct transfer interrupt */
/* clear of the CTR flag into the sub */
dcd_ep_ctr_handler();
- reg16_clear_bits(&USB->ISTR, USB_ISTR_CTR);
}
if (int_status & USB_ISTR_WKUP)
{
reg16_clear_bits(&USB->CNTR, USB_CNTR_LPMODE);
reg16_clear_bits(&USB->CNTR, USB_CNTR_FSUSP);
- reg16_clear_bits(&USB->ISTR, USB_ISTR_WKUP);
+ clear_istr_bits(USB_ISTR_WKUP);
dcd_event_bus_signal(0, DCD_EVENT_RESUME, true);
}
@@ -544,13 +548,13 @@ void dcd_int_handler(uint8_t rhport) {
USB->CNTR |= USB_CNTR_LPMODE;
/* clear of the ISTR bit must be done after setting of CNTR_FSUSP */
- reg16_clear_bits(&USB->ISTR, USB_ISTR_SUSP);
+ clear_istr_bits(USB_ISTR_SUSP);
dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true);
}
#if USE_SOF
if(int_status & USB_ISTR_SOF) {
- reg16_clear_bits(&USB->ISTR, USB_ISTR_SOF);
+ clear_istr_bits(USB_ISTR_SOF);
dcd_event_bus_signal(0, DCD_EVENT_SOF, true);
}
#endif
@@ -564,7 +568,7 @@ void dcd_int_handler(uint8_t rhport) {
{
remoteWakeCountdown--;
}
- reg16_clear_bits(&USB->ISTR, USB_ISTR_ESOF);
+ clear_istr_bits(USB_ISTR_ESOF);
}
}
diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h
index 4f2b2294e..d26c700d2 100644
--- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h
+++ b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev_pvt_st.h
@@ -143,13 +143,17 @@ static inline uint32_t pcd_get_eptype(USB_TypeDef * USBx, uint32_t bEpNum)
static inline void pcd_clear_rx_ep_ctr(USB_TypeDef * USBx, uint32_t bEpNum)
{
uint32_t regVal = pcd_get_endpoint(USBx, bEpNum);
- regVal &= 0x7FFFu & USB_EPREG_MASK;
+ regVal &= USB_EPREG_MASK;
+ regVal &= ~USB_EP_CTR_RX;
+ regVal |= USB_EP_CTR_TX; // preserve CTR_TX (clears on writing 0)
pcd_set_endpoint(USBx, bEpNum, regVal);
}
static inline void pcd_clear_tx_ep_ctr(USB_TypeDef * USBx, uint32_t bEpNum)
{
uint32_t regVal = pcd_get_endpoint(USBx, bEpNum);
- regVal &= regVal & 0xFF7FU & USB_EPREG_MASK;
+ regVal &= USB_EPREG_MASK;
+ regVal &= ~USB_EP_CTR_TX;
+ regVal |= USB_EP_CTR_RX; // preserve CTR_RX (clears on writing 0)
pcd_set_endpoint(USBx, bEpNum,regVal);
}
/**