From 00ccd391991a78c44615555e574a8644a16ad13d Mon Sep 17 00:00:00 2001 From: Robert Fisk Date: Sat, 10 Sep 2016 21:08:18 +1200 Subject: [PATCH] So I tested this innocent-looking Transcend flash drive... It will sometimes NAK part-way through a multi-packet OUT URB. And what it wants is for the host to resend beginning from the last even-numbered packet. NOT the last packet it received, and NOT the beginning of that URB. --- .../Src/stm32f4xx_hal_hcd.c | 30 +++++++++++++++++++ .../Class/MSC/Src/usbh_msc_bot.c | 7 +++++ 2 files changed, 37 insertions(+) diff --git a/Downstream/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_hcd.c b/Downstream/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_hcd.c index e1b9f0b..5c200db 100644 --- a/Downstream/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_hcd.c +++ b/Downstream/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_hcd.c @@ -99,6 +99,7 @@ static void HCD_HC_IN_IRQHandler(HCD_HandleTypeDef *hhcd, uint8_t chnum); static void HCD_HC_OUT_IRQHandler(HCD_HandleTypeDef *hhcd, uint8_t chnum); static void HCD_RXQLVL_IRQHandler(HCD_HandleTypeDef *hhcd); static void HCD_Port_IRQHandler(HCD_HandleTypeDef *hhcd); +static void HAL_HCD_OUT_RewindUnsentPackets(HCD_HandleTypeDef *hhcd, uint8_t chnum); /** * @} */ @@ -1019,6 +1020,7 @@ static void HCD_HC_OUT_IRQHandler (HCD_HandleTypeDef *hhcd, uint8_t chnum) else if ((USBx_HC(chnum)->HCINT) & USB_OTG_HCINT_NYET) { + HAL_HCD_OUT_RewindUnsentPackets(hhcd, chnum); hhcd->hc[chnum].state = HC_NYET; hhcd->hc[chnum].ErrCnt= 0; __HAL_HCD_UNMASK_HALT_HC_INT(chnum); @@ -1053,6 +1055,7 @@ static void HCD_HC_OUT_IRQHandler (HCD_HandleTypeDef *hhcd, uint8_t chnum) else if ((USBx_HC(chnum)->HCINT) & USB_OTG_HCINT_NAK) { + HAL_HCD_OUT_RewindUnsentPackets(hhcd, chnum); hhcd->hc[chnum].ErrCnt = 0; __HAL_HCD_UNMASK_HALT_HC_INT(chnum); USB_HC_Halt(hhcd->Instance, chnum); @@ -1062,6 +1065,7 @@ static void HCD_HC_OUT_IRQHandler (HCD_HandleTypeDef *hhcd, uint8_t chnum) else if ((USBx_HC(chnum)->HCINT) & USB_OTG_HCINT_TXERR) { + HAL_HCD_OUT_RewindUnsentPackets(hhcd, chnum); __HAL_HCD_UNMASK_HALT_HC_INT(chnum); USB_HC_Halt(hhcd->Instance, chnum); hhcd->hc[chnum].state = HC_XACTERR; @@ -1070,6 +1074,7 @@ static void HCD_HC_OUT_IRQHandler (HCD_HandleTypeDef *hhcd, uint8_t chnum) else if ((USBx_HC(chnum)->HCINT) & USB_OTG_HCINT_DTERR) { + HAL_HCD_OUT_RewindUnsentPackets(hhcd, chnum); __HAL_HCD_UNMASK_HALT_HC_INT(chnum); USB_HC_Halt(hhcd->Instance, chnum); __HAL_HCD_CLEAR_HC_INT(chnum, USB_OTG_HCINT_NAK); @@ -1133,6 +1138,31 @@ static void HCD_HC_OUT_IRQHandler (HCD_HandleTypeDef *hhcd, uint8_t chnum) } } + +static void HAL_HCD_OUT_RewindUnsentPackets(HCD_HandleTypeDef *hhcd, uint8_t chnum) +{ + USB_OTG_GlobalTypeDef *USBx = hhcd->Instance; + uint32_t unsentByteCount; + + if (hhcd->hc[chnum].xfer_len == 0) + { + return; + } + + //Calculate bytes actually transferred by URB from channel's remaining packet count. + //Most flash drives do not need this! + //Sent packet count must be rounded DOWN to the nearest 2 packets. Wanna know why? Ask Transcend!!! + unsentByteCount = ((((USBx_HC(chnum)->HCTSIZ & USB_OTG_HCTSIZ_PKTCNT) >> 19) + 1) & ~1) * hhcd->hc[chnum].max_packet; + if (unsentByteCount > hhcd->hc[chnum].xfer_len) + { + unsentByteCount = hhcd->hc[chnum].xfer_len; + } + hhcd->hc[chnum].xfer_count = hhcd->hc[chnum].xfer_len - unsentByteCount; +} + + + + /** * @brief Handle Rx Queue Level interrupt requests. * @param hhcd: HCD handle diff --git a/Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/MSC/Src/usbh_msc_bot.c b/Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/MSC/Src/usbh_msc_bot.c index 32b68af..e20f8c3 100644 --- a/Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/MSC/Src/usbh_msc_bot.c +++ b/Downstream/Middlewares/ST/STM32_USB_Host_Library/Class/MSC/Src/usbh_msc_bot.c @@ -134,6 +134,7 @@ USBH_StatusTypeDef USBH_MSC_BOT_Process (USBH_HandleTypeDef *phost, uint8_t lun) BOT_CSWStatusTypeDef CSW_Status = BOT_CSW_CMD_FAILED; USBH_URBStateTypeDef URB_Status = USBH_URB_IDLE; MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData; + uint32_t partialTransferLength; uint8_t toggle = 0; switch (MSC_Handle->hbot.state) @@ -367,6 +368,12 @@ USBH_StatusTypeDef USBH_MSC_BOT_Process (USBH_HandleTypeDef *phost, uint8_t lun) } else { + //Increment counters by the amount of data actually transferred during the NAK'd URB + partialTransferLength = USBH_LL_GetLastXferSize(phost, MSC_Handle->OutPipe); + MSC_Handle->hbot.cbw.field.DataTransferLength -= partialTransferLength; + MSC_Handle->hbot.bot_packet_bytes_remaining -= partialTransferLength; + MSC_Handle->hbot.bot_packet_pbuf += partialTransferLength; + USBH_MSC_BOT_Write_Multipacket_PrepareURB(phost); } }