📄 xusbps_endpoint.c
字号:
Ep = &InstancePtr->DeviceConfig.Ep[EpNum]; if(Direction & XUSBPS_EP_DIRECTION_OUT) { Ep->Out.HandlerFunc = CallBackFunc; Ep->Out.HandlerRef = CallBackRef; } if(Direction & XUSBPS_EP_DIRECTION_IN) { Ep->In.HandlerFunc = CallBackFunc; Ep->In.HandlerRef = CallBackRef; } return XST_SUCCESS;}/*****************************************************************************//*** This function primes an endpoint.** @param InstancePtr is pointer to the XUsbPs instance.* @param EpNum is the number of the endpoint to receive data from.* @param Direction is the direction of the endpoint (bitfield):* - XUSBPS_EP_DIRECTION_OUT* - XUSBPS_EP_DIRECTION_IN** @return* - XST_SUCCESS: The operation completed successfully.* - XST_FAILURE: An error occured.* - XST_INVALID_PARAM: Invalid parameter passed.** @note None.*******************************************************************************/int XUsbPs_EpPrime(XUsbPs *InstancePtr, u8 EpNum, u8 Direction){ u32 Mask; Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(EpNum < InstancePtr->DeviceConfig.NumEndpoints); /* Get the right bit mask for the endpoint direction. */ switch (Direction) { case XUSBPS_EP_DIRECTION_OUT: Mask = 0x00000001; break; case XUSBPS_EP_DIRECTION_IN: Mask = 0x00010000; break; default: return XST_INVALID_PARAM; } /* Write the endpoint prime register. */ XUsbPs_WriteReg(InstancePtr->Config.BaseAddress, XUSBPS_EPPRIME_OFFSET, Mask << EpNum); return XST_SUCCESS;}/*****************************************************************************//*** This function extracts the Setup Data from a given endpoint.** @param InstancePtr is a pointer to the XUsbPs instance of the* controller.* @param EpNum is the number of the endpoint to receive data from.* @param SetupDataPtr is a pointer to the setup data structure to be* filled.** @return* - XST_SUCCESS: The operation completed successfully.* - XST_FAILURE: An error occured.** @note None.******************************************************************************/int XUsbPs_EpGetSetupData(XUsbPs *InstancePtr, int EpNum, XUsbPs_SetupData *SetupDataPtr){ XUsbPs_EpOut *Ep; u32 Data[2]; u8 *p; int Timeout; Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(SetupDataPtr != NULL); Xil_AssertNonvoid(EpNum < InstancePtr->DeviceConfig.NumEndpoints); Ep = &InstancePtr->DeviceConfig.Ep[EpNum].Out; /* Clear the pending endpoint setup stat bit. */ XUsbPs_WriteReg(InstancePtr->Config.BaseAddress, XUSBPS_EPSTAT_OFFSET, 1 << EpNum); /* Get the data from the Queue Heads Setup buffer into local variables * so we can extract the setup data values. */ do { /* Arm the tripwire. The tripwire will tell us if a new setup * packet arrived (in which case the tripwire bit will be * cleared) while we were reading the buffer. If a new setup * packet arrived the buffer is corrupted and we continue * reading. */ XUsbPs_SetTripwire(InstancePtr); XUsbPs_dQHInvalidateCache(Ep->dQH); Data[0] = XUsbPs_ReaddQH(Ep->dQH, XUSBPS_dQHSUB0); Data[1] = XUsbPs_ReaddQH(Ep->dQH, XUSBPS_dQHSUB1); } while (FALSE == XUsbPs_TripwireIsSet(InstancePtr)); /* Clear the Tripwire bit and continue. */ XUsbPs_ClrTripwire(InstancePtr); /* Data in the setup buffer is being converted by the core to big * endian format. We have to take care of proper byte swapping when * reading the setup data values. * * Need to check if there is a smarter way to do this and take the * processor/memory-controller endianess into account? */ p = (u8 *) Data; SetupDataPtr->bmRequestType = p[0]; SetupDataPtr->bRequest = p[1]; SetupDataPtr->wValue = (p[3] << 8) | p[2]; SetupDataPtr->wIndex = (p[5] << 8) | p[4]; SetupDataPtr->wLength = (p[7] << 8) | p[6]; /* Before we leave we need to make sure that the endpoint setup bit has * cleared. It needs to be 0 before the endpoint can be re-primed. * * Note: According to the documentation this endpoint setup bit should * clear within 1-2us after it has been written above. This means that * we should never catch it being 1 here. However, we still need to * poll it to make sure. Just in case, we use a counter 'Timeout' so we * won't hang here if the bit is stuck for some reason. */ Timeout = XUSBPS_TIMEOUT_COUNTER; while ((XUsbPs_ReadReg(InstancePtr->Config.BaseAddress, XUSBPS_EPSTAT_OFFSET) & (1 << EpNum)) && --Timeout) { /* NOP */ } if (0 == Timeout) { return XST_FAILURE; } return XST_SUCCESS;}/*****************************************************************************//**** This function initializes the endpoint pointer data structure.** The function sets up the local data structure with the aligned addresses for* the Queue Head and Transfer Descriptors.** @param DevCfgPtr is pointer to the XUsbPs DEVICE configuration* structure.** @return none** @note* Endpoints of type XUSBPS_EP_TYPE_NONE are not used in the* system. Therefore no memory is reserved for them.*******************************************************************************/static void XUsbPs_EpListInit(XUsbPs_DeviceConfig *DevCfgPtr){ int EpNum; u8 *p; XUsbPs_Endpoint *Ep; XUsbPs_EpConfig *EpCfg; /* Set up the XUsbPs_Endpoint array. This array is used to define the * location of the Queue Head list and the Transfer Descriptors in the * block of DMA memory that has been passed into the driver. * * 'p' is used to set the pointers in the local data structure. * Initially 'p' is pointed to the beginning of the DMAable memory * block. As pointers are assigned, 'p' is incremented by the size of * the respective object. */ Ep = DevCfgPtr->Ep; EpCfg = DevCfgPtr->EpCfg; /* Start off with 'p' pointing to the (aligned) beginning of the DMA * buffer. */ p = (u8 *) DevCfgPtr->PhysAligned; /* Initialize the Queue Head pointer list. * * Each endpoint has two Queue Heads. One for the OUT direction and one * for the IN direction. An OUT Queue Head is always followed by an IN * Queue Head. * * Queue Head alignment is XUSBPS_dQH_ALIGN. * * Note that we have to reserve space here for unused endpoints. */ for (EpNum = 0; EpNum < DevCfgPtr->NumEndpoints; ++EpNum) { /* OUT Queue Head */ Ep[EpNum].Out.dQH = (XUsbPs_dQH *) p; p += XUSBPS_dQH_ALIGN; /* IN Queue Head */ Ep[EpNum].In.dQH = (XUsbPs_dQH *) p; p += XUSBPS_dQH_ALIGN; } /* 'p' now points to the first address after the Queue Head list. The * Transfer Descriptors start here. * * Each endpoint has a variable number of Transfer Descriptors * depending on user configuration. * * Transfer Descriptor alignment is XUSBPS_dTD_ALIGN. */ for (EpNum = 0; EpNum < DevCfgPtr->NumEndpoints; ++EpNum) { /* OUT Descriptors. */ if (XUSBPS_EP_TYPE_NONE != EpCfg[EpNum].Out.Type) { Ep[EpNum].Out.dTDs = (XUsbPs_dTD *) p; Ep[EpNum].Out.dTDCurr = (XUsbPs_dTD *) p; p += XUSBPS_dTD_ALIGN * EpCfg[EpNum].Out.NumBufs; } /* IN Descriptors. */ if (XUSBPS_EP_TYPE_NONE != EpCfg[EpNum].In.Type) { Ep[EpNum].In.dTDs = (XUsbPs_dTD *) p; Ep[EpNum].In.dTDHead = (XUsbPs_dTD *) p; Ep[EpNum].In.dTDTail = (XUsbPs_dTD *) p; p += XUSBPS_dTD_ALIGN * EpCfg[EpNum].In.NumBufs; } } /* 'p' now points to the first address after the Transfer Descriptors. * The data buffers for the OUT Transfer Desciptors start here. * * Note that IN (TX) Transfer Descriptors are not assigned buffers at * this point. Buffers will be assigned when the user calls the send() * function. */ for (EpNum = 0; EpNum < DevCfgPtr->NumEndpoints; ++EpNum) { if (XUSBPS_EP_TYPE_NONE != EpCfg[EpNum].Out.Type) { /* If BufSize for this endpoint is set to 0 it means * that we do not need to attach a buffer to this * descriptor. We also initialize it's buffer pointer * to NULL. */ if (0 == EpCfg[EpNum].Out.BufSize) { Ep[EpNum].Out.dTDBufs = NULL; continue; } Ep[EpNum].Out.dTDBufs = p; p += EpCfg[EpNum].Out.BufSize * EpCfg[EpNum].Out.NumBufs; } } /* Initialize the endpoint event handlers to NULL. */ for (EpNum = 0; EpNum < DevCfgPtr->NumEndpoints; ++EpNum) { Ep[EpNum].Out.HandlerFunc = NULL; Ep[EpNum].In.HandlerFunc = NULL; }}/*****************************************************************************//**** This function initializes the Queue Head List in memory.** @param DevCfgPtr is a pointer to the XUsbPs DEVICE configuration* structure.** @return None** @note None.*******************************************************************************/static void XUsbPs_dQHInit(XUsbPs_DeviceConfig *DevCfgPtr){ int EpNum; 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) * */ for (EpNum = 0; EpNum < DevCfgPtr->NumEndpoints; ++EpNum) { /* OUT Queue Heads.*/ if (XUSBPS_EP_TYPE_NONE != EpCfg[EpNum].Out.Type) { 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); } /* Only control OUT needs this */ if(XUSBPS_EP_TYPE_CONTROL == EpCfg[EpNum].Out.Type) { 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); } /* IN Queue Heads. */ if (XUSBPS_EP_TYPE_NONE != EpCfg[EpNum].In.Type) { 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_dQHFlushCache(Ep[EpNum].In.dQH); } }}/*****************************************************************************//** * * This function initializes the Transfer Descriptors lists in memory. * * @param DevCfgPtr is a pointer to the XUsbPs DEVICE configuration * structure. * * @return * - XST_SUCCESS: The operation completed successfully. * - XST_FAILURE: An error occured. * ******************************************************************************/static int XUsbPs_dTDInit(XUsbPs_DeviceConfig *DevCfgPtr){ int EpNum; XUsbPs_Endpoint *Ep; XUsbPs_EpConfig *EpCfg; /* Setup pointers for simpler access. */ Ep = DevCfgPtr->Ep; EpCfg = DevCfgPtr->EpCfg; /* Walk through the list of endpoints and initialize their Transfer * Descriptors. */ for (EpNum = 0; EpNum < DevCfgPtr->NumEndpoints; ++EpNum) { int Td; int NumdTD; XUsbPs_EpOut *Out = &Ep[EpNum].Out; XUsbPs_EpIn *In = &Ep[EpNum].In; /* OUT Descriptors * =============== * * + Set the next link pointer * + Set the interrupt complete and the active bit * + Attach the buffer to the dTD */ if (XUSBPS_EP_TYPE_NONE != EpCfg[EpNum].Out.Type) { NumdTD = EpCfg[EpNum].Out.NumBufs; } else { NumdTD = 0; } 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 (NULL == Out->dTDBufs) { XUsbPs_dTDFlushCache(&Out->dTDs[Td]); continue; } Status = XUsbPs_dTDAttachBuffer( &Out->dTDs[Td], Out->dTDBufs +
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -