📄 xusbps_endpoint.c
字号:
(Td * EpCfg[EpNum].Out.BufSize), EpCfg[EpNum].Out.BufSize); if (XST_SUCCESS != Status) { return XST_FAILURE; } XUsbPs_dTDFlushCache(&Out->dTDs[Td]); } /* IN Descriptors * ============== * * + Set the next link pointer * + Set the Terminate bit to mark it available */ if (XUSBPS_EP_TYPE_NONE != EpCfg[EpNum].In.Type) { NumdTD = EpCfg[EpNum].In.NumBufs; } else { NumdTD = 0; } for (Td = 0; Td < NumdTD; ++Td) { int NextTd = (Td + 1) % NumdTD; XUsbPs_dTDInvalidateCache(&In->dTDs[Td]); /* Set NEXT link pointer. */ XUsbPs_WritedTD(In->dTDs[Td], XUSBPS_dTDNLP, In->dTDs[NextTd]); /* Set the IN descriptor's TERMINATE bits. */ XUsbPs_dTDSetTerminate(In->dTDs[Td]); XUsbPs_dTDFlushCache(&In->dTDs[Td]); } } return XST_SUCCESS;}/*****************************************************************************//** * * This function associates a buffer with a Transfer Descriptor. The function * will take care of splitting the buffer into multiple 4kB aligned segments if * the buffer happens to span one or more 4kB pages. * * @param dTDIndex is a pointer to the Transfer Descriptor * @param BufferPtr is pointer to the buffer to link to the descriptor. * @param BufferLen is the length of the buffer. * * @return * - XST_SUCCESS: The operation completed successfully. * - XST_FAILURE: An error occured. * - XST_USB_BUF_TOO_BIG: The provided buffer is bigger than tha * maximum allowed buffer size (16k). * * @note * Cache invalidation and flushing needs to be handler by the * caller of this function. * ******************************************************************************/static int XUsbPs_dTDAttachBuffer(XUsbPs_dTD *dTDPtr, const u8 *BufferPtr, u32 BufferLen){ u32 BufAddr; u32 BufEnd; u32 PtrNum; Xil_AssertNonvoid(dTDPtr != NULL); /* Check if the buffer is smaller than 16kB. */ if (BufferLen > XUSBPS_dTD_BUF_MAX_SIZE) { return XST_USB_BUF_TOO_BIG; } /* Get a u32 of the buffer pointer to avoid casting in the following * logic operations. */ BufAddr = (u32) BufferPtr; /* Set the buffer pointer 0. Buffer pointer 0 can point to any location * in memory. It does not need to be 4kB aligned. However, if the * provided buffer spans one or more 4kB boundaries, we need to set up * the subsequent buffer pointers which must be 4kB aligned. */ XUsbPs_WritedTD(dTDPtr, XUSBPS_dTDBPTR(0), BufAddr); /* Check if the buffer spans a 4kB boundary. * * Only do this check, if we are not sending a 0-length buffer. */ if (BufferLen > 0) { BufEnd = BufAddr + BufferLen -1; PtrNum = 1; while ((BufAddr & 0xFFFFF000) != (BufEnd & 0xFFFFF000)) { /* The buffer spans at least one boundary, let's set * the next buffer pointer and repeat the procedure * until the end of the buffer and the pointer written * are in the same 4kB page. */ BufAddr = (BufAddr + 0x1000) & 0xFFFFF000; XUsbPs_WritedTD(dTDPtr, XUSBPS_dTDBPTR(PtrNum), BufAddr); PtrNum++; } } /* Set the length of the buffer. */ XUsbPs_dTDSetTransferLen(dTDPtr, BufferLen); /* We remember the buffer pointer in the user data field (reserved * field in the dTD). This makes it easier to reset the buffer pointer * after a buffer has been received on the endpoint. The buffer pointer * needs to be reset because the DMA engine modifies the buffer pointer * while receiving. */ XUsbPs_WritedTD(dTDPtr, XUSBPS_dTDUSERDATA, BufferPtr); return XST_SUCCESS;}/*****************************************************************************//** * This function set the Max PacketLen for the queue head for isochronous EP. * * If the max packet length is greater than XUSBPS_MAX_PACKET_SIZE, then * Mult bits are set to reflect that. * * @param dQHPtr is a pointer to the dQH element. * @param Len is the Length to be set. * ******************************************************************************/static void XUsbPs_dQHSetMaxPacketLenISO(XUsbPs_dQH *dQHPtr, u32 Len){ int mult = (Len & ENDPOINT_MAXP_MULT_MASK) >> ENDPOINT_MAXP_MULT_SHIFT; int maxp_size = (int)(Len & ENDPOINT_MAXP_LENGTH_MASK); if(maxp_size > XUSBPS_MAX_PACKET_SIZE){ return; } if(mult > 2) { return; } /* Ch9 uses zero-based count on mult, CI uses one-based count. */ mult += 1; XUsbPs_WritedQH(dQHPtr, XUSBPS_dQHCFG, (XUsbPs_ReaddQH(dQHPtr, XUSBPS_dQHCFG) & ~XUSBPS_dQHCFG_MPL_MASK) | (maxp_size << XUSBPS_dQHCFG_MPL_SHIFT)); /* Set Mult to tell hardware how many transactions in each microframe */ XUsbPs_WritedQH(dQHPtr, XUSBPS_dQHCFG, (XUsbPs_ReaddQH(dQHPtr, XUSBPS_dQHCFG) & ~XUSBPS_dQHCFG_MULT_MASK) | (mult << XUSBPS_dQHCFG_MULT_SHIFT));}/*****************************************************************************//*** This function reconfigures one Ep corresponding to host's request of setting* alternate interface. The endpoint has been disabled before this call.** Both QH and dTDs are updated for the new configuration.** @param InstancePtr is a pointer to the XUsbPs instance of the* controller.* @param CfgPtr* Pointer to the updated XUsbPs DEVICE configuration structure.** @param EpNum* The endpoint to be reconfigured.** @param NewDirection* The new transfer direction the endpoint.** @param DirectionChanged* A boolean value indicate whether the transfer direction has changed.** @return* XST_SUCCESS upon success, XST_FAILURE otherwise.*******************************************************************************/int XUsbPs_ReconfigureEp(XUsbPs *InstancePtr, XUsbPs_DeviceConfig *CfgPtr, int EpNum, unsigned short NewDirection, int DirectionChanged) { int Status = XST_SUCCESS; XUsbPs_Endpoint *Ep; XUsbPs_EpConfig *EpCfg; Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(CfgPtr != NULL); Ep = CfgPtr->Ep; EpCfg = CfgPtr->EpCfg; /* If transfer direction changes, dTDs has to be reset * Number of buffers are preset and should not to be changed. */ if(DirectionChanged) { if(NewDirection == XUSBPS_EP_DIRECTION_OUT) { u8 *p; /* Swap the pointer to the dTDs. */ Ep[EpNum].Out.dTDs = Ep[EpNum].In.dTDs; p = (u8 *)(Ep[EpNum].Out.dTDs + XUSBPS_dTD_ALIGN * EpCfg[EpNum].Out.NumBufs); /* Set the OUT buffer if buffer size is not zero */ if(EpCfg[EpNum].Out.BufSize > 0) { Ep[EpNum].Out.dTDBufs = p; } } else if(NewDirection == XUSBPS_EP_DIRECTION_IN) { Ep[EpNum].In.dTDs = Ep[EpNum].Out.dTDs; } } /* Reset dTD progress tracking pointers */ if(NewDirection == XUSBPS_EP_DIRECTION_IN) { Ep[EpNum].In.dTDHead = Ep[EpNum].In.dTDTail = Ep[EpNum].In.dTDs; } else if(NewDirection == XUSBPS_EP_DIRECTION_OUT) { Ep[EpNum].Out.dTDCurr = Ep[EpNum].Out.dTDs; } /* Reinitialize information in QH */ XUsbPs_dQHReinitEp(CfgPtr, EpNum, NewDirection); /* Reinitialize the dTD linked list, and flush the cache */ Status = XUsbPs_dTDReinitEp(CfgPtr, EpNum, NewDirection); if(Status != XST_SUCCESS) { return Status; } return XST_SUCCESS;}/*****************************************************************************//** * This function re-initializes the Queue Head List in memory. * The endpoint 1 has been disabled before this call. * * @param DevCfgPtr * Pointer to the updated XUsbPs DEVICE configuration structure. * * @param EpNum * The endpoint to be reconfigured. * * @param NewDirection * The new transfer direction of endpoint 1 * * @return none * ******************************************************************************/static void XUsbPs_dQHReinitEp(XUsbPs_DeviceConfig *DevCfgPtr,int EpNum, unsigned short NewDirection){ XUsbPs_Endpoint *Ep; XUsbPs_EpConfig *EpCfg; /* Setup pointers for simpler access. */ Ep = DevCfgPtr->Ep; EpCfg = DevCfgPtr->EpCfg; /* Go through the list of Queue Head entries and: * * - Set Transfer Descriptor addresses * - Set Maximum Packet Size * - Disable Zero Length Termination (ZLT) for non-isochronous transfers * - Enable Interrupt On Setup (IOS) * */ if(NewDirection == XUSBPS_EP_DIRECTION_OUT) { /* OUT Queue Heads. */ XUsbPs_WritedQH(Ep[EpNum].Out.dQH, XUSBPS_dQHCPTR, Ep[EpNum].Out.dTDs); /* For isochronous, ep max packet size translates to different * values in queue head than other types. * Also enable ZLT for isochronous. */ if(XUSBPS_EP_TYPE_ISOCHRONOUS == EpCfg[EpNum].Out.Type) { XUsbPs_dQHSetMaxPacketLenISO(Ep[EpNum].Out.dQH, EpCfg[EpNum].Out.MaxPacketSize); XUsbPs_dQHEnableZLT(Ep[EpNum].Out.dQH); }else { XUsbPs_dQHSetMaxPacketLen(Ep[EpNum].Out.dQH, EpCfg[EpNum].Out.MaxPacketSize); XUsbPs_dQHDisableZLT(Ep[EpNum].Out.dQH); } XUsbPs_dQHSetIOS(Ep[EpNum].Out.dQH); /* Set up the overlay next dTD pointer. */ XUsbPs_WritedQH(Ep[EpNum].Out.dQH, XUSBPS_dQHdTDNLP, Ep[EpNum].Out.dTDs); XUsbPs_dQHFlushCache(Ep[EpNum].Out.dQH); } else if(NewDirection == XUSBPS_EP_DIRECTION_IN) { /* IN Queue Heads. */ XUsbPs_WritedQH(Ep[EpNum].In.dQH, XUSBPS_dQHCPTR, Ep[EpNum].In.dTDs); /* Isochronous ep packet size can be larger than 1024. */ if(XUSBPS_EP_TYPE_ISOCHRONOUS == EpCfg[EpNum].In.Type) { XUsbPs_dQHSetMaxPacketLenISO(Ep[EpNum].In.dQH, EpCfg[EpNum].In.MaxPacketSize); XUsbPs_dQHEnableZLT(Ep[EpNum].In.dQH); }else { XUsbPs_dQHSetMaxPacketLen(Ep[EpNum].In.dQH, EpCfg[EpNum].In.MaxPacketSize); XUsbPs_dQHDisableZLT(Ep[EpNum].In.dQH); } XUsbPs_dQHSetIOS(Ep[EpNum].In.dQH); XUsbPs_dQHFlushCache(Ep[EpNum].In.dQH); }}/*****************************************************************************//** * * This function re-initializes the Transfer Descriptors lists in memory. * The endpoint has been disabled before the call. The transfer descriptors * list pointer has been initialized too. * * @param DevCfgPtr * Pointer to the XUsbPs DEVICE configuration structure. * * @param EpNum * The endpoint to be reconfigured. * * @param NewDirection * The new transfer direction of endpoint 1 * * @return * - XST_SUCCESS: The operation completed successfully. * - XST_FAILURE: An error occured. * ******************************************************************************/static int XUsbPs_dTDReinitEp(XUsbPs_DeviceConfig *DevCfgPtr,int EpNum, unsigned short NewDirection){ XUsbPs_Endpoint *Ep; XUsbPs_EpConfig *EpCfg; int Td; int NumdTD; /* Setup pointers for simpler access. */ Ep = DevCfgPtr->Ep; EpCfg = DevCfgPtr->EpCfg; if(NewDirection == XUSBPS_EP_DIRECTION_OUT) { XUsbPs_EpOut *Out = &Ep[EpNum].Out; /* OUT Descriptors * =============== * * + Set the next link pointer * + Set the interrupt complete and the active bit * + Attach the buffer to the dTD */ NumdTD = EpCfg[EpNum].Out.NumBufs; for (Td = 0; Td < NumdTD; ++Td) { int Status; int NextTd = (Td + 1) % NumdTD; XUsbPs_dTDInvalidateCache(&Out->dTDs[Td]); /* Set NEXT link pointer. */ XUsbPs_WritedTD(&Out->dTDs[Td], XUSBPS_dTDNLP, &Out->dTDs[NextTd]); /* Set the OUT descriptor ACTIVE and enable the * interrupt on complete. */ XUsbPs_dTDSetActive(&Out->dTDs[Td]); XUsbPs_dTDSetIOC(&Out->dTDs[Td]); /* Set up the data buffer with the descriptor. If the * buffer pointer is NULL it means that we do not need * to attach a buffer to this descriptor. */ if (Out->dTDBufs != NULL) { Status = XUsbPs_dTDAttachBuffer( &Out->dTDs[Td], Out->dTDBufs + (Td * EpCfg[EpNum].Out.BufSize), EpCfg[EpNum].Out.BufSize); if (Status != XST_SUCCESS) { return XST_FAILURE; } } XUsbPs_dTDFlushCache(&Out->dTDs[Td]); } } else if(NewDirection == XUSBPS_EP_DIRECTION_IN) { XUsbPs_EpIn *In = &Ep[EpNum].In; /* IN Descriptors * ============== * * + Set the next link pointer * + Set the Terminate bit to mark it available */ NumdTD = EpCfg[EpNum].In.NumBufs; for (Td = 0; Td < NumdTD; ++Td) { int NextTd = (Td + 1) % NumdTD; XUsbPs_dTDInvalidateCache(&In->dTDs[Td]); /* Set NEXT link pointer. */ XUsbPs_WritedTD(&In->dTDs[Td], XUSBPS_dTDNLP, &In->dTDs[NextTd]); /* Set the IN descriptor's TERMINATE bits. */ XUsbPs_dTDSetTerminate(&In->dTDs[Td]); XUsbPs_dTDFlushCache(&In->dTDs[Td]); } } return XST_SUCCESS;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -