USBH: STM32 LLD: various improvements
- general cleanup - implemented workaround to undocumented erratum (the OTG core may report successful enabling of port when connecting a low-speed device, but really it generates no traffic and remains in a "dumb" state) - improved handling of disconnection of devices (avoid submitting URBs if the port is disabled)
This commit is contained in:
parent
ca1882c01b
commit
02585210d1
|
@ -127,16 +127,6 @@ static inline void _save_dt_mask(usbh_ep_t *ep, uint32_t hctsiz) {
|
|||
ep->dt_mask = hctsiz & HCTSIZ_DPID_MASK;
|
||||
}
|
||||
|
||||
#if 1
|
||||
#define _transfer_completed _transfer_completedI
|
||||
#else
|
||||
static inline void _transfer_completed(usbh_ep_t *ep, usbh_urb_t *urb, usbh_urbstatus_t status) {
|
||||
osalSysLockFromISR();
|
||||
_transfer_completedI(ep, urb, status);
|
||||
osalSysUnlockFromISR();
|
||||
}
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Functions called from many places. */
|
||||
/*===========================================================================*/
|
||||
|
@ -466,7 +456,7 @@ static void _purge_queue(USBHDriver *host, struct list_head *list) {
|
|||
_release_channel(host, hcm);
|
||||
_update_urb(ep, hcm->hc->HCTSIZ, urb, FALSE);
|
||||
}
|
||||
_transfer_completed(ep, urb, USBH_URBSTATUS_DISCONNECTED);
|
||||
_transfer_completedI(ep, urb, USBH_URBSTATUS_DISCONNECTED);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -622,6 +612,13 @@ bool usbh_lld_ep_reset(usbh_ep_t *ep) {
|
|||
|
||||
void usbh_lld_urb_submit(usbh_urb_t *urb) {
|
||||
usbh_ep_t *const ep = urb->ep;
|
||||
USBHDriver *const host = ep->device->host;
|
||||
|
||||
if (!(host->otg->HPRT & HPRT_PENA)) {
|
||||
uwarnf("\t%s: Can't submit URB, port disabled", ep->name);
|
||||
_usbh_urb_completeI(urb, USBH_URBSTATUS_DISCONNECTED);
|
||||
return;
|
||||
}
|
||||
|
||||
/* add the URB to the EP's queue */
|
||||
list_add_tail(&urb->node, &ep->urb_list);
|
||||
|
@ -633,7 +630,7 @@ void usbh_lld_urb_submit(usbh_urb_t *urb) {
|
|||
_move_to_pending_queue(ep);
|
||||
|
||||
if (usbhEPIsPeriodic(ep)) {
|
||||
ep->device->host->otg->GINTMSK |= GINTMSK_SOFM;
|
||||
host->otg->GINTMSK |= GINTMSK_SOFM;
|
||||
} else {
|
||||
/* try to queue non-periodic transfers */
|
||||
_try_commit_np(ep->device->host);
|
||||
|
@ -666,7 +663,7 @@ bool usbh_lld_urb_abort(usbh_urb_t *urb, usbh_urbstatus_t status) {
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
/* This URB is active, we can cancel it now */
|
||||
/* This URB is inactive, we can cancel it now */
|
||||
uinfof("\t%s: usbh_lld_urb_abort: URB is not active", ep->name);
|
||||
_transfer_completedI(ep, urb, status);
|
||||
|
||||
|
@ -766,7 +763,7 @@ static void _complete_bulk_int(USBHDriver *host, stm32_hc_management_t *hcm, usb
|
|||
_save_dt_mask(ep, hctsiz);
|
||||
if (_update_urb(ep, hctsiz, urb, TRUE)) {
|
||||
udbgf("\t%s: done", ep->name);
|
||||
_transfer_completed(ep, urb, USBH_URBSTATUS_OK);
|
||||
_transfer_completedI(ep, urb, USBH_URBSTATUS_OK);
|
||||
} else {
|
||||
osalDbgCheck(urb->requestedLength > 0x7FFFF);
|
||||
uwarnf("\t%s: incomplete", ep->name);
|
||||
|
@ -797,7 +794,7 @@ static void _complete_control(USBHDriver *host, stm32_hc_management_t *hcm, usbh
|
|||
} else {
|
||||
osalDbgCheck(ep->xfer.u.ctrl_phase == USBH_LLD_CTRLPHASE_STATUS);
|
||||
udbgf("\t%s: STATUS done", ep->name);
|
||||
_transfer_completed(ep, urb, USBH_URBSTATUS_OK);
|
||||
_transfer_completedI(ep, urb, USBH_URBSTATUS_OK);
|
||||
}
|
||||
_try_commit_np(host);
|
||||
}
|
||||
|
@ -823,7 +820,7 @@ static void _complete_iso(USBHDriver *host, stm32_hc_management_t *hcm, usbh_ep_
|
|||
udbgf("\t%s: done", hcm->ep->name);
|
||||
_release_channel(host, hcm);
|
||||
_update_urb(ep, hctsiz, urb, TRUE);
|
||||
_transfer_completed(ep, urb, USBH_URBSTATUS_OK);
|
||||
_transfer_completedI(ep, urb, USBH_URBSTATUS_OK);
|
||||
_try_commit_p(host, FALSE);
|
||||
}
|
||||
|
||||
|
@ -908,7 +905,7 @@ static inline void _chh_int(USBHDriver *host, stm32_hc_management_t *hcm, stm32_
|
|||
switch (reason) {
|
||||
case USBH_LLD_HALTREASON_NAK:
|
||||
if ((ep->type == USBH_EPTYPE_INT) && ep->in) {
|
||||
_transfer_completed(ep, urb, USBH_URBSTATUS_TIMEOUT);
|
||||
_transfer_completedI(ep, urb, USBH_URBSTATUS_TIMEOUT);
|
||||
} else {
|
||||
ep->xfer.error_count = 0;
|
||||
_move_to_pending_queue(ep);
|
||||
|
@ -923,12 +920,12 @@ static inline void _chh_int(USBHDriver *host, stm32_hc_management_t *hcm, stm32_
|
|||
} else {
|
||||
ep->status = USBH_EPSTATUS_HALTED;
|
||||
}
|
||||
_transfer_completed(ep, urb, USBH_URBSTATUS_STALL);
|
||||
_transfer_completedI(ep, urb, USBH_URBSTATUS_STALL);
|
||||
break;
|
||||
|
||||
case USBH_LLD_HALTREASON_ERROR:
|
||||
if ((ep->type == USBH_EPTYPE_ISO) || done || (ep->xfer.error_count >= 3)) {
|
||||
_transfer_completed(ep, urb, USBH_URBSTATUS_ERROR);
|
||||
_transfer_completedI(ep, urb, USBH_URBSTATUS_ERROR);
|
||||
} else {
|
||||
uerrf("\t%s: err=%d, done=%d, retry", ep->name, ep->xfer.error_count, done);
|
||||
_move_to_pending_queue(ep);
|
||||
|
@ -937,7 +934,7 @@ static inline void _chh_int(USBHDriver *host, stm32_hc_management_t *hcm, stm32_
|
|||
|
||||
case USBH_LLD_HALTREASON_ABORT:
|
||||
uwarnf("\t%s: Abort", ep->name);
|
||||
_transfer_completed(ep, urb, urb->status);
|
||||
_transfer_completedI(ep, urb, urb->status);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -1024,6 +1021,36 @@ static inline void _hcint_int(USBHDriver *host) {
|
|||
/* Host interrupts. */
|
||||
/*===========================================================================*/
|
||||
static inline void _sof_int(USBHDriver *host) {
|
||||
|
||||
/* this is part of the workaround to the LS bug in the OTG core */
|
||||
#undef HPRT_PLSTS_MASK
|
||||
#define HPRT_PLSTS_MASK (3U<<10)
|
||||
if (host->check_ls_activity) {
|
||||
uint16_t remaining = host->otg->HFNUM >> 16;
|
||||
if (remaining < 5975) {
|
||||
uwarnf("LS: ISR called too late (time=%d)", 6000 - remaining);
|
||||
return;
|
||||
}
|
||||
/* 15us loop */
|
||||
for (;;) {
|
||||
uint32_t line_status = host->otg->HPRT & HPRT_PLSTS_MASK;
|
||||
remaining = host->otg->HFNUM >> 16;
|
||||
if (line_status != HPRT_PLSTS_DM) {
|
||||
uinfof("LS: activity detected, line=%d, time=%d", line_status >> 10, 6000 - remaining);
|
||||
host->check_ls_activity = FALSE;
|
||||
host->otg->GINTMSK = (host->otg->GINTMSK & ~GINTMSK_SOFM) | (GINTMSK_HCM | GINTMSK_RXFLVLM);
|
||||
host->rootport.lld_status |= USBH_PORTSTATUS_ENABLE;
|
||||
host->rootport.lld_c_status |= USBH_PORTSTATUS_C_ENABLE;
|
||||
return;
|
||||
}
|
||||
if (remaining < 5910) {
|
||||
uwarn("LS: No activity detected");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* real SOF interrupt */
|
||||
udbg("SOF");
|
||||
_try_commit_p(host, TRUE);
|
||||
}
|
||||
|
@ -1143,17 +1170,19 @@ static inline void _ptxfe_int(USBHDriver *host) {
|
|||
uinfo("PTXFE");
|
||||
}
|
||||
|
||||
static inline void _discint_int(USBHDriver *host) {
|
||||
uint32_t hprt = host->otg->HPRT;
|
||||
static void _disable(USBHDriver *host) {
|
||||
host->rootport.lld_status &= ~(USBH_PORTSTATUS_CONNECTION | USBH_PORTSTATUS_ENABLE);
|
||||
host->rootport.lld_c_status |= USBH_PORTSTATUS_C_CONNECTION | USBH_PORTSTATUS_C_ENABLE;
|
||||
|
||||
uwarn("\tDISCINT");
|
||||
|
||||
if (!(hprt & HPRT_PCSTS)) {
|
||||
host->rootport.lld_status &= ~(USBH_PORTSTATUS_CONNECTION | USBH_PORTSTATUS_ENABLE);
|
||||
host->rootport.lld_c_status |= USBH_PORTSTATUS_C_CONNECTION | USBH_PORTSTATUS_C_ENABLE;
|
||||
}
|
||||
_purge_active(host);
|
||||
_purge_pending(host);
|
||||
|
||||
host->otg->GINTMSK &= ~(GINTMSK_HCM | GINTMSK_RXFLVLM);
|
||||
}
|
||||
|
||||
static inline void _discint_int(USBHDriver *host) {
|
||||
uinfo("DISCINT: Port disconnection detected");
|
||||
_disable(host);
|
||||
}
|
||||
|
||||
static inline void _hprtint_int(USBHDriver *host) {
|
||||
|
@ -1169,8 +1198,6 @@ static inline void _hprtint_int(USBHDriver *host) {
|
|||
uinfo("\tHPRT: Port connection detected");
|
||||
host->rootport.lld_status |= USBH_PORTSTATUS_CONNECTION;
|
||||
host->rootport.lld_c_status |= USBH_PORTSTATUS_C_CONNECTION;
|
||||
} else {
|
||||
uinfo("\tHPRT: Port disconnection detected");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1178,9 +1205,32 @@ static inline void _hprtint_int(USBHDriver *host) {
|
|||
hprt_clr |= HPRT_PENCHNG;
|
||||
if (hprt & HPRT_PENA) {
|
||||
uinfo("\tHPRT: Port enabled");
|
||||
host->rootport.lld_status |= USBH_PORTSTATUS_ENABLE;
|
||||
host->rootport.lld_status &= ~(USBH_PORTSTATUS_HIGH_SPEED | USBH_PORTSTATUS_LOW_SPEED);
|
||||
|
||||
/* configure FIFOs */
|
||||
#define HNPTXFSIZ DIEPTXF0
|
||||
#if STM32_USBH_USE_OTG1
|
||||
#if STM32_USBH_USE_OTG2
|
||||
if (&USBHD1 == host)
|
||||
#endif
|
||||
{
|
||||
otg->GRXFSIZ = GRXFSIZ_RXFD(STM32_OTG1_RXFIFO_SIZE / 4);
|
||||
otg->HNPTXFSIZ = HPTXFSIZ_PTXSA(STM32_OTG1_RXFIFO_SIZE / 4) | HPTXFSIZ_PTXFD(STM32_OTG1_NPTXFIFO_SIZE / 4);
|
||||
otg->HPTXFSIZ = HPTXFSIZ_PTXSA((STM32_OTG1_RXFIFO_SIZE / 4) + (STM32_OTG1_NPTXFIFO_SIZE / 4)) | HPTXFSIZ_PTXFD(STM32_OTG1_PTXFIFO_SIZE / 4);
|
||||
}
|
||||
#endif
|
||||
#if STM32_USBH_USE_OTG2
|
||||
#if STM32_USBH_USE_OTG1
|
||||
if (&USBHD2 == host)
|
||||
#endif
|
||||
{
|
||||
otg->GRXFSIZ = GRXFSIZ_RXFD(STM32_OTG2_RXFIFO_SIZE / 4);
|
||||
otg->HNPTXFSIZ = HPTXFSIZ_PTXSA(STM32_OTG2_RXFIFO_SIZE / 4) | HPTXFSIZ_PTXFD(STM32_OTG2_NPTXFIFO_SIZE / 4);
|
||||
otg->HPTXFSIZ = HPTXFSIZ_PTXSA((STM32_OTG2_RXFIFO_SIZE / 4) + (STM32_OTG2_NPTXFIFO_SIZE / 4)) | HPTXFSIZ_PTXFD(STM32_OTG2_PTXFIFO_SIZE / 4);
|
||||
}
|
||||
#endif
|
||||
#undef HNPTXFSIZ
|
||||
|
||||
/* Make sure the FIFOs are flushed. */
|
||||
otg_txfifo_flush(host, 0x10);
|
||||
otg_rxfifo_flush(host);
|
||||
|
@ -1197,9 +1247,23 @@ static inline void _hprtint_int(USBHDriver *host) {
|
|||
host->rootport.lld_status |= USBH_PORTSTATUS_LOW_SPEED;
|
||||
otg->HFIR = 6000;
|
||||
otg->HCFG = (otg->HCFG & ~HCFG_FSLSPCS_MASK) | HCFG_FSLSPCS_6;
|
||||
|
||||
/* Low speed devices connected to the STM32's internal transceiver sometimes
|
||||
* don't behave correctly. Although HPRT reports a port enable, really
|
||||
* no traffic is generated, and the core is non-functional. To avoid
|
||||
* this we won't report the port enable until we are sure that the
|
||||
* port is working. */
|
||||
host->check_ls_activity = TRUE;
|
||||
otg->GINTMSK |= GINTMSK_SOFM;
|
||||
} else {
|
||||
otg->HFIR = 48000;
|
||||
otg->HCFG = (otg->HCFG & ~HCFG_FSLSPCS_MASK) | HCFG_FSLSPCS_48;
|
||||
host->check_ls_activity = FALSE;
|
||||
|
||||
/* enable channel and rx interrupts */
|
||||
otg->GINTMSK |= GINTMSK_HCM | GINTMSK_RXFLVLM;
|
||||
host->rootport.lld_status |= USBH_PORTSTATUS_ENABLE;
|
||||
host->rootport.lld_c_status |= USBH_PORTSTATUS_C_ENABLE;
|
||||
}
|
||||
} else {
|
||||
if (hprt & HPRT_PCSTS) {
|
||||
|
@ -1211,13 +1275,8 @@ static inline void _hprtint_int(USBHDriver *host) {
|
|||
} else {
|
||||
uerr("\tHPRT: Port disabled due to disconnect");
|
||||
}
|
||||
|
||||
_purge_active(host);
|
||||
_purge_pending(host);
|
||||
|
||||
host->rootport.lld_status &= ~USBH_PORTSTATUS_ENABLE;
|
||||
_disable(host);
|
||||
}
|
||||
host->rootport.lld_c_status |= USBH_PORTSTATUS_C_ENABLE;
|
||||
}
|
||||
|
||||
if (hprt & HPRT_POCCHNG) {
|
||||
|
@ -1249,24 +1308,19 @@ static void usb_lld_serve_interrupt(USBHDriver *host) {
|
|||
}
|
||||
|
||||
/* check mismatch */
|
||||
if (gintsts & GINTSTS_MMIS) {
|
||||
uerr("Mode Mismatch");
|
||||
otg->GINTSTS = gintsts;
|
||||
return;
|
||||
}
|
||||
osalDbgAssert((gintsts & GINTSTS_MMIS) == 0, "mode mismatch");
|
||||
|
||||
gintsts &= otg->GINTMSK;
|
||||
#if USBH_DEBUG_ENABLE_WARNINGS
|
||||
if (!gintsts) {
|
||||
#if USBH_DEBUG_ENABLE_WARNINGS
|
||||
uint32_t a, b;
|
||||
a = otg->GINTSTS;
|
||||
b = otg->GINTMSK;
|
||||
uwarnf("GINTSTS=%08x, GINTMSK=%08x", a, b);
|
||||
uwarnf("Masked bits caused an ISR: GINTSTS=%08x, GINTMSK=%08x (unhandled bits=%08x)", a, b, a & ~b);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// otg->GINTMSK &= ~(GINTMSK_NPTXFEM | GINTMSK_PTXFEM);
|
||||
otg->GINTSTS = gintsts;
|
||||
|
||||
if (gintsts & GINTSTS_SOF)
|
||||
|
@ -1365,24 +1419,22 @@ static void _init(USBHDriver *host) {
|
|||
|
||||
#if STM32_USBH_USE_OTG1
|
||||
#if STM32_USBH_USE_OTG2
|
||||
if (&USBHD1 == host) {
|
||||
if (&USBHD1 == host)
|
||||
#endif
|
||||
{
|
||||
host->otg = OTG_FS;
|
||||
host->channels_number = STM32_OTG1_CHANNELS_NUMBER;
|
||||
#if STM32_USBH_USE_OTG2
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if STM32_USBH_USE_OTG2
|
||||
#if STM32_USBH_USE_OTG1
|
||||
if (&USBHD2 == host) {
|
||||
if (&USBHD2 == host)
|
||||
#endif
|
||||
{
|
||||
host->otg = OTG_HS;
|
||||
host->channels_number = STM32_OTG2_CHANNELS_NUMBER;
|
||||
#if STM32_USBH_USE_OTG1
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
INIT_LIST_HEAD(&host->ch_free[0]);
|
||||
INIT_LIST_HEAD(&host->ch_free[1]);
|
||||
|
@ -1417,8 +1469,9 @@ static void _usbh_start(USBHDriver *usbh) {
|
|||
/* Clock activation.*/
|
||||
#if STM32_USBH_USE_OTG1
|
||||
#if STM32_USBH_USE_OTG2
|
||||
if (&USBHD1 == usbh) {
|
||||
if (&USBHD1 == usbh)
|
||||
#endif
|
||||
{
|
||||
/* OTG FS clock enable and reset.*/
|
||||
rccEnableOTG_FS(FALSE);
|
||||
rccResetOTG_FS();
|
||||
|
@ -1427,15 +1480,14 @@ static void _usbh_start(USBHDriver *usbh) {
|
|||
|
||||
/* Enables IRQ vector.*/
|
||||
nvicEnableVector(STM32_OTG1_NUMBER, STM32_USB_OTG1_IRQ_PRIORITY);
|
||||
#if STM32_USBH_USE_OTG2
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if STM32_USBH_USE_OTG2
|
||||
#if STM32_USBH_USE_OTG1
|
||||
if (&USBHD2 == usbh) {
|
||||
if (&USBHD2 == usbh)
|
||||
#endif
|
||||
{
|
||||
/* OTG HS clock enable and reset.*/
|
||||
rccEnableOTG_HS(TRUE); // Enable HS clock when cpu is in sleep mode
|
||||
rccDisableOTG_HSULPI(TRUE); // Disable HS ULPI clock when cpu is in sleep mode
|
||||
|
@ -1445,9 +1497,7 @@ static void _usbh_start(USBHDriver *usbh) {
|
|||
|
||||
/* Enables IRQ vector.*/
|
||||
nvicEnableVector(STM32_OTG2_NUMBER, STM32_USB_OTG2_IRQ_PRIORITY);
|
||||
#if STM32_USBH_USE_OTG1
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
otgp->GUSBCFG = GUSBCFG_PHYSEL | GUSBCFG_TRDT(5);
|
||||
|
@ -1487,41 +1537,11 @@ static void _usbh_start(USBHDriver *usbh) {
|
|||
|
||||
otgp->HPRT |= HPRT_PPWR;
|
||||
|
||||
/* without this delay, the FIFO sizes are set INcorrectly */
|
||||
osalThreadSleepS(MS2ST(200));
|
||||
|
||||
#define HNPTXFSIZ DIEPTXF0
|
||||
#if STM32_USBH_USE_OTG1
|
||||
#if STM32_USBH_USE_OTG2
|
||||
if (&USBHD1 == usbh) {
|
||||
#endif
|
||||
otgp->GRXFSIZ = GRXFSIZ_RXFD(STM32_OTG1_RXFIFO_SIZE / 4);
|
||||
otgp->HNPTXFSIZ = HPTXFSIZ_PTXSA((STM32_OTG1_RXFIFO_SIZE / 4)) | HPTXFSIZ_PTXFD(STM32_OTG1_NPTXFIFO_SIZE / 4);
|
||||
otgp->HPTXFSIZ = HPTXFSIZ_PTXSA((STM32_OTG1_RXFIFO_SIZE / 4) + (STM32_OTG1_NPTXFIFO_SIZE / 4)) | HPTXFSIZ_PTXFD(STM32_OTG1_PTXFIFO_SIZE / 4);
|
||||
#if STM32_USBH_USE_OTG2
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#if STM32_USBH_USE_OTG2
|
||||
#if STM32_USBH_USE_OTG1
|
||||
if (&USBHD2 == usbh) {
|
||||
#endif
|
||||
otgp->GRXFSIZ = GRXFSIZ_RXFD(STM32_OTG2_RXFIFO_SIZE / 4);
|
||||
otgp->HNPTXFSIZ = HPTXFSIZ_PTXSA((STM32_OTG2_RXFIFO_SIZE / 4)) | HPTXFSIZ_PTXFD(STM32_OTG2_NPTXFIFO_SIZE / 4);
|
||||
otgp->HPTXFSIZ = HPTXFSIZ_PTXSA((STM32_OTG2_RXFIFO_SIZE / 4) + (STM32_OTG2_NPTXFIFO_SIZE / 4)) | HPTXFSIZ_PTXFD(STM32_OTG2_PTXFIFO_SIZE / 4);
|
||||
#if STM32_USBH_USE_OTG1
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#undef HNPTXFSIZ
|
||||
|
||||
otg_txfifo_flush(usbh, 0x10);
|
||||
otg_rxfifo_flush(usbh);
|
||||
|
||||
otgp->GINTSTS = 0xffffffff;
|
||||
otgp->GINTMSK = GINTMSK_DISCM /*| GINTMSK_PTXFEM*/ | GINTMSK_HCM | GINTMSK_HPRTM
|
||||
/*| GINTMSK_IPXFRM | GINTMSK_NPTXFEM*/ | GINTMSK_RXFLVLM
|
||||
/*| GINTMSK_SOFM */ | GINTMSK_MMISM;
|
||||
otgp->GINTMSK = GINTMSK_DISCM | GINTMSK_HPRTM | GINTMSK_MMISM;
|
||||
|
||||
usbh->rootport.lld_status = USBH_PORTSTATUS_POWER;
|
||||
usbh->rootport.lld_c_status = 0;
|
||||
|
@ -1586,7 +1606,7 @@ usbh_urbstatus_t usbh_lld_root_hub_request(USBHDriver *usbh, uint8_t bmRequestTy
|
|||
break;
|
||||
|
||||
case USBH_PORT_FEAT_C_OVERCURRENT:
|
||||
usbh->rootport.lld_c_status &= USBH_PORTSTATUS_C_OVERCURRENT;
|
||||
usbh->rootport.lld_c_status &= ~USBH_PORTSTATUS_C_OVERCURRENT;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -1597,18 +1617,7 @@ usbh_urbstatus_t usbh_lld_root_hub_request(USBHDriver *usbh, uint8_t bmRequestTy
|
|||
break;
|
||||
|
||||
case GetHubDescriptor:
|
||||
/*dev_dbg(hsotg->dev, "GetHubDescriptor\n");
|
||||
hub_desc = (struct usb_hub_descriptor *)buf;
|
||||
hub_desc->bDescLength = 9;
|
||||
hub_desc->bDescriptorType = USB_DT_HUB;
|
||||
hub_desc->bNbrPorts = 1;
|
||||
hub_desc->wHubCharacteristics =
|
||||
cpu_to_le16(HUB_CHAR_COMMON_LPSM |
|
||||
HUB_CHAR_INDV_PORT_OCPM);
|
||||
hub_desc->bPwrOn2PwrGood = 1;
|
||||
hub_desc->bHubContrCurrent = 0;
|
||||
hub_desc->u.hs.DeviceRemovable[0] = 0;
|
||||
hub_desc->u.hs.DeviceRemovable[1] = 0xff;*/
|
||||
osalDbgAssert(0, "unsupported");
|
||||
break;
|
||||
|
||||
case GetHubStatus:
|
||||
|
@ -1644,11 +1653,29 @@ usbh_urbstatus_t usbh_lld_root_hub_request(USBHDriver *usbh, uint8_t bmRequestTy
|
|||
uint32_t hprt;
|
||||
otg->PCGCCTL = 0;
|
||||
hprt = otg->HPRT;
|
||||
if (hprt & HPRT_PENA) {
|
||||
/* This can occur when the OTG core doesn't generate traffic
|
||||
* despite reporting a successful por enable */
|
||||
uerr("Detected enabled port; resetting OTG core");
|
||||
otg->GAHBCFG = 0;
|
||||
osalThreadSleepS(MS2ST(20));
|
||||
_usbh_start(usbh); /* this effectively resets the core */
|
||||
osalThreadSleepS(MS2ST(100)); /* during this delay, the core generates connect ISR */
|
||||
uinfo("OTG reset ended");
|
||||
if (otg->HPRT & HPRT_PCSTS) {
|
||||
/* if the device is still connected, don't report a C_CONNECTION flag, which would cause
|
||||
* the upper layer to abort enumeration */
|
||||
uinfo("Clear connection change flag");
|
||||
usbh->rootport.lld_c_status &= ~USBH_PORTSTATUS_C_CONNECTION;
|
||||
}
|
||||
}
|
||||
/* note: writing PENA = 1 actually disables the port */
|
||||
hprt &= ~(HPRT_PSUSP | HPRT_PENA | HPRT_PCDET | HPRT_PENCHNG | HPRT_POCCHNG );
|
||||
hprt &= ~(HPRT_PSUSP | HPRT_PENA | HPRT_PCDET | HPRT_PENCHNG | HPRT_POCCHNG);
|
||||
while ((otg->GRSTCTL & GRSTCTL_AHBIDL) == 0);
|
||||
otg->HPRT = hprt | HPRT_PRST;
|
||||
osalThreadSleepS(MS2ST(60));
|
||||
osalThreadSleepS(MS2ST(15));
|
||||
otg->HPRT = hprt;
|
||||
osalThreadSleepS(MS2ST(10));
|
||||
usbh->rootport.lld_c_status |= USBH_PORTSTATUS_C_RESET;
|
||||
osalSysUnlock();
|
||||
} break;
|
||||
|
@ -1672,14 +1699,7 @@ usbh_urbstatus_t usbh_lld_root_hub_request(USBHDriver *usbh, uint8_t bmRequestTy
|
|||
}
|
||||
|
||||
uint8_t usbh_lld_roothub_get_statuschange_bitmap(USBHDriver *usbh) {
|
||||
osalSysLock();
|
||||
if (usbh->rootport.lld_c_status) {
|
||||
osalSysUnlock();
|
||||
return 1 << 1;
|
||||
}
|
||||
osalSysUnlock();
|
||||
return 0;
|
||||
return usbh->rootport.lld_c_status ? (1 << 1) : 0;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -63,6 +63,8 @@ typedef struct stm32_hc_management {
|
|||
|
||||
#define _usbhdriver_ll_data \
|
||||
stm32_otg_t *otg; \
|
||||
/* low-speed port reset bug */ \
|
||||
bool check_ls_activity; \
|
||||
/* channels */ \
|
||||
uint8_t channels_number; \
|
||||
stm32_hc_management_t channels[STM32_OTG2_CHANNELS_NUMBER]; \
|
||||
|
|
Loading…
Reference in New Issue