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.
USG_1.0
Robert Fisk 8 years ago
parent 32ca5cdcf9
commit 00ccd39199

@ -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

@ -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);
}
}

Loading…
Cancel
Save