More work on enumerating cheap POS mice, arrrrgh.

Added timeout checks and retry functionality to control transaction
state machine. But some times the device just won't talk, so we flash
the fault LED slowly to give the user some clue about what happened.
pull/7/head
Robert Fisk 9 years ago
parent 9c1187fa05
commit 4186630689

@ -190,6 +190,8 @@
#define USBH_MAX_ERROR_COUNT 2
#define USBH_DEVICE_ADDRESS 1
#define USBH_CTRL_TRANSACTION_TIMEOUT_MS 100
/**
* @}
@ -413,8 +415,8 @@ typedef struct
uint8_t pipe_out;
uint8_t pipe_size;
uint8_t *buff;
uint32_t timer;
uint16_t length;
uint16_t timer;
USB_Setup_TypeDef setup;
CTRL_StateTypeDef state;
uint8_t errorcount;

@ -152,6 +152,8 @@ USBH_StatusTypeDef USBH_DeInit(USBH_HandleTypeDef *phost)
USBH_LL_Stop(phost);
}
USBH_LL_DeInit(phost);
return USBH_OK;
}
@ -187,6 +189,7 @@ static USBH_StatusTypeDef DeInitStateMachine(USBH_HandleTypeDef *phost)
phost->device.address = USBH_ADDRESS_DEFAULT;
phost->device.speed = USBH_SPEED_FULL;
phost->device.is_connected = 0;
return USBH_OK;
}
@ -840,7 +843,7 @@ USBH_StatusTypeDef USBH_LL_Connect (USBH_HandleTypeDef *phost)
}
else if (phost->gState == HOST_DEV_WAIT_FOR_ATTACHMENT)
{
//On the first boot after a power cycle with a low-speed device pre-attached,
//On a cold boot with a low-speed device pre-attached,
//we get a second port-connected interrupt!???
//So go back and do the port reset again...
phost->gState = HOST_IDLE;

@ -603,15 +603,14 @@ static USBH_StatusTypeDef USBH_HandleControl (USBH_HandleTypeDef *phost)
{
case CTRL_SETUP:
/* send a SETUP packet */
USBH_CtlSendSetup (phost,
phost->Control.timer = phost->Timer;
USBH_CtlSendSetup(phost,
(uint8_t *)phost->Control.setup.d8 ,
phost->Control.pipe_out);
phost->Control.state = CTRL_SETUP_WAIT;
break;
case CTRL_SETUP_WAIT:
URB_Status = USBH_LL_GetURBState(phost, phost->Control.pipe_out);
/* case SETUP packet sent successfully */
if(URB_Status == USBH_URB_DONE)
@ -647,22 +646,24 @@ static USBH_StatusTypeDef USBH_HandleControl (USBH_HandleTypeDef *phost)
phost->Control.state = CTRL_STATUS_IN;
}
}
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
#endif
}
else if(URB_Status == USBH_URB_ERROR)
{
phost->Control.state = CTRL_ERROR;
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
#endif
}
else if (URB_Status == USBH_URB_NOTREADY)
{
//Some mice cause a transaction error interrupt (HCINT_TXERR) at this point,
//so we retry and hope for the best!
phost->Control.state = CTRL_SETUP;
//Some mice cause a transaction error interrupt (HCINT_TXERR) at this point.
//Other mice just NAK our transaction.
//Either way we need to retry, but keep our original timeout so we don't wait forever.
USBH_CtlSendSetup(phost,
(uint8_t *)phost->Control.setup.d8 ,
phost->Control.pipe_out);
}
if ((int32_t)(phost->Timer - phost->Control.timer) >= USBH_CTRL_TRANSACTION_TIMEOUT_MS)
{
phost->Control.state = CTRL_ERROR;
}
break;
@ -678,171 +679,139 @@ static USBH_StatusTypeDef USBH_HandleControl (USBH_HandleTypeDef *phost)
break;
case CTRL_DATA_IN_WAIT:
URB_Status = USBH_LL_GetURBState(phost , phost->Control.pipe_in);
/* check is DATA packet transferred successfully */
if (URB_Status == USBH_URB_DONE)
{
phost->Control.state = CTRL_STATUS_OUT;
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
#endif
}
/* manage error cases*/
if (URB_Status == USBH_URB_STALL)
{
/* In stall case, return to previous machine state*/
status = USBH_NOT_SUPPORTED;
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
#endif
//Retry transaction
phost->Control.state = CTRL_ERROR;
}
else if (URB_Status == USBH_URB_ERROR)
{
/* Device error */
phost->Control.state = CTRL_ERROR;
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
#endif
phost->Control.state = CTRL_ERROR;
}
if ((int32_t)(phost->Timer - phost->Control.timer) >= USBH_CTRL_TRANSACTION_TIMEOUT_MS)
{
phost->Control.state = CTRL_ERROR;
}
break;
case CTRL_DATA_OUT:
phost->Control.timer = phost->Timer;
USBH_CtlSendData (phost,
phost->Control.buff,
phost->Control.length ,
phost->Control.pipe_out,
1);
phost->Control.timer = phost->Timer;
phost->Control.state = CTRL_DATA_OUT_WAIT;
break;
case CTRL_DATA_OUT_WAIT:
URB_Status = USBH_LL_GetURBState(phost , phost->Control.pipe_out);
URB_Status = USBH_LL_GetURBState(phost, phost->Control.pipe_out);
if (URB_Status == USBH_URB_DONE)
{ /* If the Setup Pkt is sent successful, then change the state */
phost->Control.state = CTRL_STATUS_IN;
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
#endif
}
/* handle error cases */
else if (URB_Status == USBH_URB_STALL)
{
/* In stall case, return to previous machine state*/
phost->Control.state = CTRL_STALLED;
status = USBH_NOT_SUPPORTED;
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
#endif
//Retry transaction
phost->Control.state = CTRL_ERROR;
}
else if (URB_Status == USBH_URB_NOTREADY)
{
/* Nack received from device */
phost->Control.state = CTRL_DATA_OUT;
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
#endif
}
else if (URB_Status == USBH_URB_ERROR)
{
/* device error */
phost->Control.state = CTRL_ERROR;
status = USBH_FAIL;
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
#endif
}
}
if ((int32_t)(phost->Timer - phost->Control.timer) >= USBH_CTRL_TRANSACTION_TIMEOUT_MS)
{
phost->Control.state = CTRL_ERROR;
}
break;
case CTRL_STATUS_IN:
/* Send 0 bytes out packet */
phost->Control.timer = phost->Timer;
USBH_CtlReceiveData (phost,
0,
0,
phost->Control.pipe_in);
phost->Control.timer = phost->Timer;
phost->Control.state = CTRL_STATUS_IN_WAIT;
break;
case CTRL_STATUS_IN_WAIT:
URB_Status = USBH_LL_GetURBState(phost , phost->Control.pipe_in);
if ( URB_Status == USBH_URB_DONE)
{ /* Control transfers completed, Exit the State Machine */
phost->Control.state = CTRL_COMPLETE;
status = USBH_OK;
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
#endif
}
else if (URB_Status == USBH_URB_ERROR)
{
phost->Control.state = CTRL_ERROR;
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
#endif
}
else if(URB_Status == USBH_URB_STALL)
{
/* Control transfers completed, Exit the State Machine */
status = USBH_NOT_SUPPORTED;
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
#endif
//Retry transaction
phost->Control.state = CTRL_ERROR;
}
if ((int32_t)(phost->Timer - phost->Control.timer) >= USBH_CTRL_TRANSACTION_TIMEOUT_MS)
{
phost->Control.state = CTRL_ERROR;
}
break;
case CTRL_STATUS_OUT:
phost->Control.timer = phost->Timer;
USBH_CtlSendData (phost,
0,
0,
phost->Control.pipe_out,
1);
phost->Control.timer = phost->Timer;
phost->Control.state = CTRL_STATUS_OUT_WAIT;
break;
case CTRL_STATUS_OUT_WAIT:
URB_Status = USBH_LL_GetURBState(phost , phost->Control.pipe_out);
if (URB_Status == USBH_URB_DONE)
{
status = USBH_OK;
phost->Control.state = CTRL_COMPLETE;
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
#endif
phost->Control.state = CTRL_COMPLETE;
}
else if (URB_Status == USBH_URB_NOTREADY)
{
phost->Control.state = CTRL_STATUS_OUT;
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
#endif
}
else if (URB_Status == USBH_URB_ERROR)
{
phost->Control.state = CTRL_ERROR;
#if (USBH_USE_OS == 1)
osMessagePut ( phost->os_event, USBH_CONTROL_EVENT, 0);
#endif
phost->Control.state = CTRL_ERROR;
}
if ((int32_t)(phost->Timer - phost->Control.timer) >= USBH_CTRL_TRANSACTION_TIMEOUT_MS)
{
phost->Control.state = CTRL_ERROR;
}
break;

@ -201,12 +201,6 @@ void Downstream_HostUserCallback(USBH_HandleTypeDef *phost, uint8_t id)
return;
}
//Called from main()
if (id == HOST_USER_UNRECOVERED_ERROR)
{
DOWNSTREAM_STATEMACHINE_FREAKOUT;
return;
}
//Called from main()
if (id == HOST_USER_CLASS_ACTIVE)
@ -263,8 +257,10 @@ void Downstream_HostUserCallback(USBH_HandleTypeDef *phost, uint8_t id)
return;
}
//Called from main():
if (id == HOST_USER_CLASS_FAILED)
if ((id == HOST_USER_CLASS_FAILED) ||
(id == HOST_USER_UNRECOVERED_ERROR)) //Probably due to a crappy device that won't enumerate!
{
//Unsupported device classes will cause a slow fault flash.
//This is distinct from the fast freakout flash caused by internal errors or attacks.
@ -273,5 +269,6 @@ void Downstream_HostUserCallback(USBH_HandleTypeDef *phost, uint8_t id)
DownstreamState = STATE_ERROR;
return;
}
}

@ -85,7 +85,7 @@ void HAL_HCD_MspDeInit(HCD_HandleTypeDef* hhcd)
PA11 ------> USB_OTG_FS_DM
PA12 ------> USB_OTG_FS_DP
*/
HAL_GPIO_DeInit(GPIOA, GPIO_PIN_11|GPIO_PIN_12);
//HAL_GPIO_DeInit(GPIOA, GPIO_PIN_11|GPIO_PIN_12);
/* Peripheral interrupt Deinit*/
HAL_NVIC_DisableIRQ(OTG_FS_IRQn);

Loading…
Cancel
Save