📄 usb20hw.c
字号:
/* Return if it worked this time */
if (ENDPOINT_PRIMED(ep_index)) {
USB_INTS_ON;
return USB_OK;
}
}
/*
* If the endpoint is not primed but the next-dTD pointer is
* not terminal, then we have hardware problems.
*/
USB_ForceReset = RESET_HW;
}
USB_INTS_ON;
return USB_OK;
}
/**************************************************************************
*
* Function Name : USB_init_endpoint
* Returned Value : None
* Comments :
* Initializes the endpoint and the data structures associated with the
* endpoint.
*
**************************************************************************/
void USB_init_endpoint(Uint16 ep_index, Uint16 max_pkt_size,
Uint8 type, Uint8 zero_length_packet_flag)
{
dQH_STRUCT *ep_queue_head_ptr;
USB_ASSERT(!usb_state.EP_INIT[ep_index]);
USB_ASSERT(EP_NUM(ep_index) == 0 || !usb_state.EP_DTD_HEADS[ep_index]);
USB_ASSERT(type != USB_CONTROL_ENDPOINT || zero_length_packet_flag == 0);
/*
* I have seen this occur due to plugging and unplugging the USB cable.
*/
if (!ENDPOINT_NOT_PRIMED(ep_index)) {
USB_ForceReset = RESET_HW;
return;
}
usb_state.EP_INIT[ep_index] = TRUE;
/* Get the endpoint queue head address. */
ep_queue_head_ptr = usb_state.EP_QUEUE_HEAD_PTR + ep_index;
/*
* Set the max packet length and/or "Interrupt On Setup" (control only),
* "Zero Length Termination Select" fields (non-control only).
*/
ep_queue_head_ptr->MAX_PKT_LENGTH = max_pkt_size << 16;
if (type == USB_CONTROL_ENDPOINT)
ep_queue_head_ptr->MAX_PKT_LENGTH |= DTD_IOS;
else if (zero_length_packet_flag)
ep_queue_head_ptr->MAX_PKT_LENGTH |= DTD_ZERO_LEN_TER_SEL;
/* Enable the endpoint for Rx or Tx. */
if (EP_DIRECTION(ep_index)) {
/* transmit */
usb_opreg->ENDPTCTRLX[EP_NUM(ep_index)] |= TX_ENABLE|(type<<TX_T_SHFT);
} else {
/* receive */
usb_opreg->ENDPTCTRLX[EP_NUM(ep_index)] |= RX_ENABLE|(type<<RX_T_SHFT);
}
}
/**************************************************************************
*
* Function Name : USB_ISR_deinit_endpoint
* Returned Value : TRUE if caller must defer to task level
* Comments :
* Flushes and disables the endpoint and the data structures associated
* with the endpoint. Just return if pending hardware reset.
*
**************************************************************************/
void USB_ISR_deinit_endpoint(Uint16 ep_index)
{
dDT_STRUCT *dTD, *next_dTD;
Uint32 endpoint_bit, i;
if (USB_ForceReset)
return;
endpoint_bit = EP_REGBIT(ep_index);
/*
* Starting at the head dTD, follow down the chain terminating all
* of the dTD transfers in progress and/or queued.
*/
dTD = usb_state.EP_DTD_HEADS[ep_index];
while (dTD) {
dTD->NEXT |= DTD_TERM_BIT;
dTD->SIZE_IOC_STS = 0;
dTD = (dDT_STRUCT *)(dTD->NEXT & ~DTD_TERM_BIT);
}
/*
* Flush this endpoint:
* NOTE: There is a caveat in the manual that flushing may take a
* large amount of time. Since we should not be flushing with a
* request in progress, this indicates trouble. Give up immediately
* if its taking time to flush; defer to a task level reset.
*/
for (i = 0; i < HW_LOOP_CNT; i++) {
usb_opreg->ENDPTFLUSH = endpoint_bit;
/* Wait until this bit is reset. */
if (!(usb_opreg->ENDPTFLUSH & endpoint_bit))
break;
}
if ((usb_opreg->ENDPTPRIME | usb_opreg->ENDPTSTATUS) & endpoint_bit) {
USB_ForceReset = RESET_SW;
return;
}
/* Return the dTDs to the pool. */
dTD = usb_state.EP_DTD_HEADS[ep_index];
while (dTD) {
next_dTD = (dDT_STRUCT *)(dTD->NEXT & ~DTD_TERM_BIT);
dTD->NEXT = (Uint32)usb_state.DTD_POOL;
usb_state.DTD_POOL = dTD;
dTD = next_dTD;
}
/* Disable the endpoint for Rx/Tx and reset the endpoint type. */
if (EP_DIRECTION(ep_index)) {
/* transmit */
usb_opreg->ENDPTCTRLX[EP_NUM(ep_index)] &= VUSB_EPCTRL_TX_EP_MASK;
} else {
/* receive */
usb_opreg->ENDPTCTRLX[EP_NUM(ep_index)] &= VUSB_EPCTRL_RX_EP_MASK;
}
usb_state.EP_INIT[ep_index] = FALSE;
usb_state.EP_DTD_HEADS[ep_index] = NULL;
}
/**************************************************************************
*
* Function Name : USB_chip_and_data_base_initialize
* Returned Value : None
* Comments :
* Initializes the USB device controller.
*
**************************************************************************/
static void USB_chip_and_data_base_initialize(void)
{
dDT_STRUCT *dTD;
Uint32 i;
/* Don't process a reset interrupt at ISR level while we are in here. */
USB_ForceReset = RESET_HW;
#if RESET_PWR_CYCLE
if (USB_Hard_Reset) {
*(volatile Uint32 *)USBCTR &= ~1;
PSPRINTF("HARDWARE USB CHIP RESET\n");
TASKSLEEP_MILLISECONDS(500);
}
#endif
/* Disable the controller. */
usb_opreg->USB_CMD = 0;
/* Zero out the Endpoint queue heads. */
BZERO(usb_state.EP_QUEUE_HEAD_PTR, 2*USB_MAX_ENDPOINTS*sizeof(dQH_STRUCT));
/* Zero out the device transfer descriptors. */
BZERO(usb_state.DTD_ALIGNED_BASE_PTR, DTD_POOL_CNT*sizeof(dDT_STRUCT));
/*
* Zero out the endpoint transaction descriptor heads. (Tail is
* "don't care" if head is null.)
*/
BZERO(usb_state.EP_DTD_HEADS, 2*USB_MAX_ENDPOINTS*sizeof(dDT_STRUCT*));
/* Make sure the 16 MSBs of this register are 0s. */
usb_opreg->ENDPT_SETUP_STAT = 0;
/* Program the controller to be a USB "device" controller. */
usb_opreg->USB_MODE = (Uint32)VUSB_MODE_CTRL_MODE_DEV;
for (i = 0; i < 2 * USB_MAX_ENDPOINTS; i++) {
/* Initialize all device queue heads. */
usb_state.EP_QUEUE_HEAD_PTR[i].NEXT_DTD_PTR = DTD_TERM_BIT;
/* Initially no endpoints are initialized. */
usb_state.EP_INIT[i] = FALSE;
}
/* Configure the Endpoint List Address. */
usb_opreg->EP_LIST_ADDR = (Uint32)usb_state.EP_QUEUE_HEAD_PTR;
/* Enqueue all the dTDs into the free pool. */
usb_state.DTD_POOL = NULL;
dTD = usb_state.DTD_ALIGNED_BASE_PTR;
for (i = 0; i < DTD_POOL_CNT; i++, dTD++) {
/* Move the dTD to the free dTD pool. */
dTD->NEXT = (Uint32)usb_state.DTD_POOL;
usb_state.DTD_POOL = dTD;
}
/* Initialize the endpoint 0 properties. */
usb_opreg->ENDPTCTRLX[0] = VUSB_EPCTRL_TX_DATA_TOGGLE_RST |
VUSB_EPCTRL_RX_DATA_TOGGLE_RST;
#if RESET_PWR_CYCLE
if (USB_Hard_Reset) {
*(volatile Uint32 *)USBCTR |= 0x61;
USB_Hard_Reset = FALSE;
}
#endif
/* Enable interrupts. */
usb_opreg->USB_INTR = VUSB_INTERRUPT_BITS;
/* Set the Run bit in the command register. */
usb_opreg->USB_CMD = VUSB_CMD_RUN_STOP;
/* In case we stopped due to hardware hang, flush endpoints. */
for (i = 0; i < HW_LOOP_LIMIT; i++) {
usb_opreg->ENDPTFLUSH = 0xffffffff;
/* Wait until this bit is reset. */
if (!(usb_opreg->ENDPTFLUSH & 0xffffffff))
break;
}
/* Initialize endpoint 0 in both directions. */
USB_init_endpoint(EP0_RECV, EP0_PKT_SIZE, USB_CONTROL_ENDPOINT, 0);
USB_init_endpoint(EP0_SEND, EP0_PKT_SIZE, USB_CONTROL_ENDPOINT, 0);
USB_ForceReset = NO_RESET;
}
/**************************************************************************
*
* Function Name : USB_ISR_process_tr_complete
* Returned Value : None
* Comments :
* Service transaction-complete interrupt.
*
**************************************************************************/
static void USB_ISR_process_tr_complete(void)
{
dDT_STRUCT *dTD, *next_dTD;
Uint32 endpt_bits, tbit;
Uint16 ep, ep_index;
while (usb_opreg->ENDPT_SETUP_STAT | usb_opreg->ENDPTCOMPLETE) {
/*
* We use separate loops for ENDPTSETUPSTAT and ENDPTCOMPLETE because
* the setup packets are to be read ASAP.
*
* First process all Setup packets received.
*/
endpt_bits = usb_opreg->ENDPT_SETUP_STAT;
/* We only support Endpoint 0 control endpoint. */
USB_ASSERT((endpt_bits & ~1) == 0);
if (endpt_bits & 1) {
SETUP_STRUCT *p;
int n;
/*
* Copy the Setup data from the 8-byte setup
* buffer to setup structure.
*/
p = (SETUP_STRUCT *)&usb_state.EP_QUEUE_HEAD_PTR->SETUP_BUFFER;
usb_setup.REQUESTTYPE = p->REQUESTTYPE;
usb_setup.REQUEST = p->REQUEST;
usb_setup.INDEX = p->INDEX;
usb_setup.VALUE = p->VALUE;
usb_setup.LENGTH = p->LENGTH;
/* Clear the bit in the ENDPTSETUPSTAT register for Endpoint 0. */
usb_opreg->ENDPT_SETUP_STAT = 1;
/* Hang for up to 200 usecs. for SetupStatus to clear */
for (n = 0; n < 40; n++) {
Uint32 t0;
if (!(usb_opreg->ENDPT_SETUP_STAT & 1))
break;
t0 = *(unsigned volatile int *)HRTCNTL0;
while (*(unsigned volatile int *)HRTCNTL0 - t0 < 5*133)
;
}
if (n >= 40) {
/* Something is wrong; force a hardware reset */
USB_ForceReset = RESET_HW;
return;
}
USBserviceEP[0](0, TRUE, 8);
}
/* Process non-setup transaction-complete interrupts. */
endpt_bits = usb_opreg->ENDPTCOMPLETE;
if (endpt_bits) {
/* Clear the bits in the register. */
usb_opreg->ENDPTCOMPLETE = endpt_bits;
/* Test each endpoint for both IN and OUT directions. */
for (ep_index = 0; endpt_bits; ep_index++) {
tbit = 1 << ((ep_index >> 1) + 16*(ep_index & 1));
if (endpt_bits & tbit) {
endpt_bits &= ~tbit;
ep = EP_NUM(ep_index);
/* Get the first dTD for this endpoint. */
dTD = usb_state.EP_DTD_HEADS[ep_index];
/* Process all the dTDs that are done. */
while (dTD) {
/* Break out if this and remaining dTDs still active. */
if (dTD->SIZE_IOC_STS & DTD_STATUS_ACTIVE) {
/*
* Possible hardware failure here. See if the
* first dTD on the head chain has already been
* processed but not set inactive.
*/
if ((usb_state.EP_QUEUE_HEAD_PTR + ep_index)
->CURR_DTD_PTR == dTD->NEXT)
{
dTD->SIZE_IOC_STS = (dTD->SIZE_IOC_STS &
0xffff0000) | 0x8000;
}
else
break;
}
/*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -