| /****************************************************************************** |
| * |
| * Copyright (C) 2016 Xilinx, Inc. All rights reserved. |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a copy |
| * of this software and associated documentation files (the "Software"), to deal |
| * in the Software without restriction, including without limitation the rights |
| * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| * copies of the Software, and to permit persons to whom the Software is |
| * furnished to do so, subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice shall be included in |
| * all copies or substantial portions of the Software. |
| * |
| * Use of the Software is limited solely to applications: |
| * (a) running on a Xilinx device, or |
| * (b) that interact with a Xilinx device through a bus or interconnect. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| * XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
| * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF |
| * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
| * SOFTWARE. |
| * |
| * Except as contained in this notice, the name of the Xilinx shall not be used |
| * in advertising or otherwise to promote the sale, use or other dealings in |
| * this Software without prior written authorization from Xilinx. |
| * |
| *****************************************************************************/ |
| /****************************************************************************/ |
| /** |
| * |
| * @file xusbpsu_endpoint.c |
| * @addtogroup usbpsu_v1_0 |
| * @{ |
| * |
| * |
| * <pre> |
| * MODIFICATION HISTORY: |
| * |
| * Ver Who Date Changes |
| * ----- ---- -------- ------------------------------------------------------- |
| * 1.0 sg 06/06/16 First release |
| * |
| * </pre> |
| * |
| *****************************************************************************/ |
| |
| /***************************** Include Files *********************************/ |
| |
| #include "xusbpsu.h" |
| #include "xusbpsu_endpoint.h" |
| /************************** Constant Definitions *****************************/ |
| |
| |
| /**************************** Type Definitions *******************************/ |
| |
| /* return Physical EP number as dwc3 mapping */ |
| #define PhysicalEp(epnum, direction) (((epnum) << 1 ) | (direction)) |
| |
| /***************** Macros (Inline Functions) Definitions *********************/ |
| |
| |
| /************************** Function Prototypes ******************************/ |
| |
| |
| /************************** Variable Definitions *****************************/ |
| |
| |
| /****************************************************************************/ |
| /** |
| * Returns zeroed parameters to be used by Endpoint commands |
| * |
| * @param InstancePtr is a pointer to the XUsbPsu instance. |
| * |
| * @return Zeroed Params structure pointer. |
| * |
| * @note None. |
| * |
| *****************************************************************************/ |
| struct XUsbPsu_EpParams *XUsbPsu_GetEpParams(struct XUsbPsu *InstancePtr) |
| { |
| if (InstancePtr == NULL) { |
| return NULL; |
| } |
| |
| InstancePtr->EpParams.Param0 = 0x00U; |
| InstancePtr->EpParams.Param1 = 0x00U; |
| InstancePtr->EpParams.Param2 = 0x00U; |
| |
| return &InstancePtr->EpParams; |
| } |
| |
| /****************************************************************************/ |
| /** |
| * Returns Transfer Index assigned by Core for an Endpoint transfer. |
| * |
| * @param InstancePtr is a pointer to the XUsbPsu instance. |
| * @param UsbEpNum is USB endpoint number. |
| * @param Dir is direction of endpoint - XUSBPSU_EP_DIR_IN/XUSBPSU_EP_DIR_OUT |
| * |
| * @return Transfer Resource Index. |
| * |
| * @note None. |
| * |
| *****************************************************************************/ |
| u32 XUsbPsu_EpGetTransferIndex(struct XUsbPsu *InstancePtr, u8 UsbEpNum, |
| u8 Dir) |
| { |
| u8 PhyEpNum; |
| u32 ResourceIndex; |
| |
| Xil_AssertNonvoid(InstancePtr != NULL); |
| Xil_AssertNonvoid(UsbEpNum <= (u8)16U); |
| Xil_AssertNonvoid((Dir == XUSBPSU_EP_DIR_IN) || |
| (Dir == XUSBPSU_EP_DIR_OUT)); |
| |
| PhyEpNum = (u8)PhysicalEp(UsbEpNum, Dir); |
| ResourceIndex = XUsbPsu_ReadReg(InstancePtr, XUSBPSU_DEPCMD(PhyEpNum)); |
| |
| return (u32)XUSBPSU_DEPCMD_GET_RSC_IDX(ResourceIndex); |
| } |
| |
| /****************************************************************************/ |
| /** |
| * Sends Endpoint command to Endpoint. |
| * |
| * @param InstancePtr is a pointer to the XUsbPsu instance. |
| * @param UsbEpNum is USB endpoint number. |
| * @param Dir is direction of endpoint |
| * - XUSBPSU_EP_DIR_IN/ XUSBPSU_EP_DIR_OUT. |
| * @param Cmd is Endpoint command. |
| * @param Params is Endpoint command parameters. |
| * |
| * @return XST_SUCCESS else XST_FAILURE. |
| * |
| * @note None. |
| * |
| *****************************************************************************/ |
| s32 XUsbPsu_SendEpCmd(struct XUsbPsu *InstancePtr, u8 UsbEpNum, u8 Dir, |
| u32 Cmd, struct XUsbPsu_EpParams *Params) |
| { |
| u32 PhyEpNum; |
| |
| Xil_AssertNonvoid(InstancePtr != NULL); |
| Xil_AssertNonvoid(UsbEpNum <= (u8)16U); |
| Xil_AssertNonvoid((Dir == XUSBPSU_EP_DIR_IN) || |
| (Dir == XUSBPSU_EP_DIR_OUT)); |
| |
| PhyEpNum = PhysicalEp(UsbEpNum, Dir); |
| |
| XUsbPsu_WriteReg(InstancePtr, XUSBPSU_DEPCMDPAR0(PhyEpNum), |
| Params->Param0); |
| XUsbPsu_WriteReg(InstancePtr, XUSBPSU_DEPCMDPAR1(PhyEpNum), |
| Params->Param1); |
| XUsbPsu_WriteReg(InstancePtr, XUSBPSU_DEPCMDPAR2(PhyEpNum), |
| Params->Param2); |
| |
| XUsbPsu_WriteReg(InstancePtr, XUSBPSU_DEPCMD(PhyEpNum), |
| Cmd | XUSBPSU_DEPCMD_CMDACT); |
| |
| if (XUsbPsu_Wait_Clear_Timeout(InstancePtr, XUSBPSU_DEPCMD(PhyEpNum), |
| XUSBPSU_DEPCMD_CMDACT, 500U) == (s32)XST_FAILURE) { |
| return XST_FAILURE; |
| } |
| |
| return XST_SUCCESS; |
| } |
| |
| /****************************************************************************/ |
| /** |
| * Sends Start New Configuration command to Endpoint. |
| * |
| * @param InstancePtr is a pointer to the XUsbPsu instance. |
| * @param UsbEpNum is USB endpoint number. |
| * @param Dir is direction of endpoint |
| * - XUSBPSU_EP_DIR_IN/ XUSBPSU_EP_DIR_OUT. |
| * |
| * @return XST_SUCCESS else XST_FAILURE. |
| * |
| * @note |
| * As per data book this command should be issued by software |
| * under these conditions: |
| * 1. After power-on-reset with XferRscIdx=0 before starting |
| * to configure Physical Endpoints 0 and 1. |
| * 2. With XferRscIdx=2 before starting to configure |
| * Physical Endpoints > 1 |
| * 3. This command should always be issued to |
| * Endpoint 0 (DEPCMD0). |
| * |
| *****************************************************************************/ |
| s32 XUsbPsu_StartEpConfig(struct XUsbPsu *InstancePtr, u32 UsbEpNum, u8 Dir) |
| { |
| struct XUsbPsu_EpParams *Params; |
| u32 Cmd; |
| u8 PhyEpNum; |
| |
| Xil_AssertNonvoid(InstancePtr != NULL); |
| Xil_AssertNonvoid(UsbEpNum <= (u32)16U); |
| Xil_AssertNonvoid((Dir == XUSBPSU_EP_DIR_IN) || |
| (Dir == XUSBPSU_EP_DIR_OUT)); |
| |
| PhyEpNum = (u8)PhysicalEp(UsbEpNum, (u32)Dir); |
| Params = XUsbPsu_GetEpParams(InstancePtr); |
| Xil_AssertNonvoid(Params != NULL); |
| |
| if (PhyEpNum != 1U) { |
| Cmd = XUSBPSU_DEPCMD_DEPSTARTCFG; |
| /* XferRscIdx == 0 for EP0 and 2 for the remaining */ |
| if (PhyEpNum > 1U) { |
| if (InstancePtr->IsConfigDone != 0U) { |
| return XST_SUCCESS; |
| } |
| InstancePtr->IsConfigDone = 1U; |
| Cmd |= XUSBPSU_DEPCMD_PARAM(2); |
| } |
| |
| return XUsbPsu_SendEpCmd(InstancePtr, 0U, XUSBPSU_EP_DIR_OUT, |
| Cmd, Params); |
| } |
| |
| return XST_SUCCESS; |
| } |
| |
| /****************************************************************************/ |
| /** |
| * Sends Set Endpoint Configuration command to Endpoint. |
| * |
| * @param InstancePtr is a pointer to the XUsbPsu instance. |
| * @param UsbEpNum is USB endpoint number. |
| * @param Dir is direction of endpoint - XUSBPSU_EP_DIR_IN/XUSBPSU_EP_DIR_OUT. |
| * @param Size is size of Endpoint size. |
| * @param Type is Endpoint type Control/Bulk/Interrupt/Isoc. |
| * |
| * @return XST_SUCCESS else XST_FAILURE. |
| * |
| * @note None. |
| * |
| *****************************************************************************/ |
| s32 XUsbPsu_SetEpConfig(struct XUsbPsu *InstancePtr, u8 UsbEpNum, u8 Dir, |
| u16 Size, u8 Type) |
| { |
| struct XUsbPsu_EpParams *Params; |
| u8 PhyEpNum; |
| |
| Xil_AssertNonvoid(InstancePtr != NULL); |
| Xil_AssertNonvoid(UsbEpNum <= (u8)16U); |
| Xil_AssertNonvoid((Dir == XUSBPSU_EP_DIR_IN) || |
| (Dir == XUSBPSU_EP_DIR_OUT)); |
| Xil_AssertNonvoid((Size >= 64U) && (Size <= 1024U)); |
| |
| Params = XUsbPsu_GetEpParams(InstancePtr); |
| Xil_AssertNonvoid(Params != NULL); |
| |
| PhyEpNum = PhysicalEp(UsbEpNum , Dir); |
| |
| Params->Param0 = XUSBPSU_DEPCFG_EP_TYPE(Type) |
| | XUSBPSU_DEPCFG_MAX_PACKET_SIZE(Size); |
| |
| /* |
| * Set burst size to 1 as recommended |
| */ |
| Params->Param0 |= XUSBPSU_DEPCFG_BURST_SIZE(1); |
| |
| Params->Param1 = XUSBPSU_DEPCFG_XFER_COMPLETE_EN |
| | XUSBPSU_DEPCFG_XFER_NOT_READY_EN; |
| |
| /* |
| * We are doing 1:1 mapping for endpoints, meaning |
| * Physical Endpoints 2 maps to Logical Endpoint 2 and |
| * so on. We consider the direction bit as part of the physical |
| * endpoint number. So USB endpoint 0x81 is 0x03. |
| */ |
| Params->Param1 |= XUSBPSU_DEPCFG_EP_NUMBER(PhyEpNum); |
| |
| if (Dir != XUSBPSU_EP_DIR_OUT) { |
| Params->Param0 |= XUSBPSU_DEPCFG_FIFO_NUMBER((u32)PhyEpNum >> 1); |
| } |
| |
| return XUsbPsu_SendEpCmd(InstancePtr, UsbEpNum, Dir, |
| XUSBPSU_DEPCMD_SETEPCONFIG, Params); |
| } |
| |
| /****************************************************************************/ |
| /** |
| * Sends Set Transfer Resource command to Endpoint. |
| * |
| * @param InstancePtr is a pointer to the XUsbPsu instance. |
| * @param UsbEpNum is USB endpoint number. |
| * @param Dir is direction of endpoint - XUSBPSU_EP_DIR_IN/ |
| * XUSBPSU_EP_DIR_OUT. |
| * |
| * @return XST_SUCCESS else XST_FAILURE. |
| * |
| * @note None. |
| * |
| *****************************************************************************/ |
| s32 XUsbPsu_SetXferResource(struct XUsbPsu *InstancePtr, u8 UsbEpNum, u8 Dir) |
| { |
| struct XUsbPsu_EpParams *Params; |
| |
| |
| Xil_AssertNonvoid(InstancePtr != NULL); |
| Xil_AssertNonvoid(UsbEpNum <= (u8)16U); |
| Xil_AssertNonvoid((Dir == XUSBPSU_EP_DIR_IN) || |
| (Dir == XUSBPSU_EP_DIR_OUT)); |
| |
| Params = XUsbPsu_GetEpParams(InstancePtr); |
| Xil_AssertNonvoid(Params != NULL); |
| |
| Params->Param0 = XUSBPSU_DEPXFERCFG_NUM_XFER_RES(1); |
| |
| return XUsbPsu_SendEpCmd(InstancePtr, UsbEpNum, Dir, |
| XUSBPSU_DEPCMD_SETTRANSFRESOURCE, Params); |
| } |
| |
| /****************************************************************************/ |
| /** |
| * Enables Endpoint for sending/receiving data. |
| * |
| * @param InstancePtr is a pointer to the XUsbPsu instance. |
| * @param UsbEpNum is USB endpoint number. |
| * @param Dir is direction of endpoint - XUSBPSU_EP_DIR_IN/XUSBPSU_EP_DIR_OUT. |
| * @param Maxsize is size of Endpoint size. |
| * @param Type is Endpoint type Control/Bulk/Interrupt/Isoc. |
| * |
| * @return XST_SUCCESS else XST_FAILURE. |
| * |
| * @note None. |
| * |
| ****************************************************************************/ |
| s32 XUsbPsu_EpEnable(struct XUsbPsu *InstancePtr, u8 UsbEpNum, u8 Dir, |
| u16 Maxsize, u8 Type) |
| { |
| struct XUsbPsu_Ep *Ept; |
| u32 RegVal; |
| s32 Ret = (s32)XST_FAILURE; |
| u32 PhyEpNum; |
| |
| Xil_AssertNonvoid(InstancePtr != NULL); |
| Xil_AssertNonvoid(UsbEpNum <= (u8)16U); |
| Xil_AssertNonvoid((Dir == XUSBPSU_EP_DIR_IN) || |
| (Dir == XUSBPSU_EP_DIR_OUT)); |
| Xil_AssertNonvoid((Maxsize >= 64U) && (Maxsize <= 1024U)); |
| |
| PhyEpNum = PhysicalEp(UsbEpNum , Dir); |
| Ept = &InstancePtr->eps[PhyEpNum]; |
| |
| Ept->UsbEpNum = UsbEpNum; |
| Ept->Direction = Dir; |
| Ept->Type = Type; |
| Ept->MaxSize = Maxsize; |
| Ept->PhyEpNum = (u8)PhyEpNum; |
| |
| if ((Ept->EpStatus & XUSBPSU_EP_ENABLED) == 0U) { |
| Ret = XUsbPsu_StartEpConfig(InstancePtr, UsbEpNum, Dir); |
| if (Ret != 0) { |
| return Ret; |
| } |
| } |
| |
| Ret = XUsbPsu_SetEpConfig(InstancePtr, UsbEpNum, Dir, Maxsize, Type); |
| if (Ret != 0) { |
| return Ret; |
| } |
| |
| if ((Ept->EpStatus & XUSBPSU_EP_ENABLED) == 0U) { |
| Ret = XUsbPsu_SetXferResource(InstancePtr, UsbEpNum, Dir); |
| if (Ret != 0) { |
| return Ret; |
| } |
| |
| Ept->EpStatus |= XUSBPSU_EP_ENABLED; |
| |
| RegVal = XUsbPsu_ReadReg(InstancePtr, XUSBPSU_DALEPENA); |
| RegVal |= XUSBPSU_DALEPENA_EP(Ept->PhyEpNum); |
| XUsbPsu_WriteReg(InstancePtr, XUSBPSU_DALEPENA, RegVal); |
| } |
| |
| return XST_SUCCESS; |
| } |
| |
| /****************************************************************************/ |
| /** |
| * Disables Endpoint. |
| * |
| * @param InstancePtr is a pointer to the XUsbPsu instance. |
| * @param UsbEpNum is USB endpoint number. |
| * @param Dir is direction of endpoint |
| * - XUSBPSU_EP_DIR_IN/XUSBPSU_EP_DIR_OUT. |
| * |
| * @return XST_SUCCESS else XST_FAILURE. |
| * |
| * @note None. |
| * |
| ****************************************************************************/ |
| s32 XUsbPsu_EpDisable(struct XUsbPsu *InstancePtr, u8 UsbEpNum, u8 Dir) |
| { |
| u32 RegVal; |
| u8 PhyEpNum; |
| struct XUsbPsu_Ep *Ept; |
| |
| Xil_AssertNonvoid(InstancePtr != NULL); |
| Xil_AssertNonvoid(UsbEpNum <= (u8)16U); |
| Xil_AssertNonvoid((Dir == XUSBPSU_EP_DIR_IN) || |
| (Dir == XUSBPSU_EP_DIR_OUT)); |
| |
| PhyEpNum = PhysicalEp(UsbEpNum , Dir); |
| Ept = &InstancePtr->eps[PhyEpNum]; |
| |
| RegVal = XUsbPsu_ReadReg(InstancePtr, XUSBPSU_DALEPENA); |
| RegVal &= ~XUSBPSU_DALEPENA_EP(PhyEpNum); |
| XUsbPsu_WriteReg(InstancePtr, XUSBPSU_DALEPENA, RegVal); |
| |
| Ept->Type = 0U; |
| Ept->EpStatus = 0U; |
| Ept->MaxSize = 0U; |
| |
| return XST_SUCCESS; |
| } |
| |
| /****************************************************************************/ |
| /** |
| * Enables USB Control Endpoint i.e., EP0OUT and EP0IN of Core. |
| * |
| * @param InstancePtr is a pointer to the XUsbPsu instance. |
| * @param Size is control endpoint size. |
| * |
| * @return XST_SUCCESS else XST_FAILURE. |
| * |
| * @note None. |
| * |
| ****************************************************************************/ |
| s32 XUsbPsu_EnableControlEp(struct XUsbPsu *InstancePtr, u16 Size) |
| { |
| s32 RetVal; |
| |
| Xil_AssertNonvoid(InstancePtr != NULL); |
| Xil_AssertNonvoid((Size >= 64U) && (Size <= 512U)); |
| |
| RetVal = XUsbPsu_EpEnable(InstancePtr, 0U, XUSBPSU_EP_DIR_OUT, Size, |
| XUSBPSU_ENDPOINT_XFER_CONTROL); |
| if (RetVal != 0) { |
| return XST_FAILURE; |
| } |
| |
| RetVal = XUsbPsu_EpEnable(InstancePtr, 0U, XUSBPSU_EP_DIR_IN, Size, |
| XUSBPSU_ENDPOINT_XFER_CONTROL); |
| if (RetVal != 0) { |
| return XST_FAILURE; |
| } |
| |
| return XST_SUCCESS; |
| } |
| |
| /****************************************************************************/ |
| /** |
| * Initializes Endpoints. All OUT endpoints are even numbered and all IN |
| * endpoints are odd numbered. EP0 is for Control OUT and EP1 is for |
| * Control IN. |
| * |
| * @param InstancePtr is a pointer to the XUsbPsu instance. |
| * |
| * @return None. |
| * |
| * @note None. |
| * |
| ****************************************************************************/ |
| void XUsbPsu_InitializeEps(struct XUsbPsu *InstancePtr) |
| { |
| u8 i; |
| u8 Epnum; |
| |
| Xil_AssertVoid(InstancePtr != NULL); |
| |
| for (i = 0U; i < InstancePtr->NumOutEps; i++) { |
| Epnum = (i << 1U) | XUSBPSU_EP_DIR_OUT; |
| InstancePtr->eps[Epnum].PhyEpNum = Epnum; |
| InstancePtr->eps[Epnum].Direction = XUSBPSU_EP_DIR_OUT; |
| } |
| for (i = 0U; i < InstancePtr->NumInEps; i++) { |
| Epnum = (i << 1U) | XUSBPSU_EP_DIR_IN; |
| InstancePtr->eps[Epnum].PhyEpNum = Epnum; |
| InstancePtr->eps[Epnum].Direction = XUSBPSU_EP_DIR_IN; |
| } |
| } |
| |
| /****************************************************************************/ |
| /** |
| * Stops transfer on Endpoint. |
| * |
| * @param InstancePtr is a pointer to the XUsbPsu instance. |
| * @param UsbEpNum is USB endpoint number. |
| * @param Dir is direction of endpoint - XUSBPSU_EP_DIR_IN/XUSBPSU_EP_DIR_OUT. |
| * |
| * @return None. |
| * |
| * @note None. |
| * |
| ****************************************************************************/ |
| void XUsbPsu_StopTransfer(struct XUsbPsu *InstancePtr, u8 UsbEpNum, u8 Dir) |
| { |
| struct XUsbPsu_Ep *Ept; |
| struct XUsbPsu_EpParams *Params; |
| u8 PhyEpNum; |
| u32 Cmd; |
| |
| Xil_AssertVoid(InstancePtr != NULL); |
| Xil_AssertVoid(UsbEpNum <= (u8)16U); |
| Xil_AssertVoid((Dir == XUSBPSU_EP_DIR_IN) || (Dir == XUSBPSU_EP_DIR_OUT)); |
| |
| PhyEpNum = PhysicalEp(UsbEpNum, Dir); |
| Params = XUsbPsu_GetEpParams(InstancePtr); |
| Xil_AssertVoid(Params != NULL); |
| |
| Ept = &InstancePtr->eps[PhyEpNum]; |
| |
| if (Ept->ResourceIndex == 0U) { |
| return; |
| } |
| |
| /* |
| * - Issue EndTransfer WITH CMDIOC bit set |
| * - Wait 100us |
| */ |
| Cmd = XUSBPSU_DEPCMD_ENDTRANSFER; |
| Cmd |= XUSBPSU_DEPCMD_CMDIOC; |
| Cmd |= XUSBPSU_DEPCMD_PARAM(Ept->ResourceIndex); |
| (void)XUsbPsu_SendEpCmd(InstancePtr, Ept->PhyEpNum, Ept->Direction, |
| Cmd, Params); |
| Ept->ResourceIndex = 0U; |
| Ept->EpStatus &= ~XUSBPSU_EP_BUSY; |
| XUsbSleep(100U); |
| } |
| |
| /****************************************************************************/ |
| /** |
| * Clears Stall on all endpoints. |
| * |
| * @param InstancePtr is a pointer to the XUsbPsu instance. |
| * |
| * @return None. |
| * |
| * @note None. |
| * |
| ****************************************************************************/ |
| void XUsbPsu_ClearStalls(struct XUsbPsu *InstancePtr) |
| { |
| struct XUsbPsu_EpParams *Params; |
| u32 Epnum; |
| struct XUsbPsu_Ep *Ept; |
| |
| Xil_AssertVoid(InstancePtr != NULL); |
| |
| Params = XUsbPsu_GetEpParams(InstancePtr); |
| Xil_AssertVoid(Params != NULL); |
| |
| for (Epnum = 1U; Epnum < XUSBPSU_ENDPOINTS_NUM; Epnum++) { |
| |
| Ept = &InstancePtr->eps[Epnum]; |
| if (Ept == NULL) { |
| continue; |
| } |
| |
| if ((Ept->EpStatus & XUSBPSU_EP_STALL) == 0U) { |
| continue; |
| } |
| |
| Ept->EpStatus &= ~XUSBPSU_EP_STALL; |
| |
| (void)XUsbPsu_SendEpCmd(InstancePtr, Ept->PhyEpNum, |
| Ept->Direction, XUSBPSU_DEPCMD_CLEARSTALL, |
| Params); |
| } |
| } |
| |
| /****************************************************************************/ |
| /** |
| * Initiates DMA to send data on endpoint to Host. |
| * |
| * @param InstancePtr is a pointer to the XUsbPsu instance. |
| * @param UsbEp is USB endpoint number. |
| * @param BufferPtr is pointer to data. |
| * @param BufferLen is length of data buffer. |
| * |
| * @return XST_SUCCESS else XST_FAILURE |
| * |
| * @note None. |
| * |
| *****************************************************************************/ |
| s32 XUsbPsu_EpBufferSend(struct XUsbPsu *InstancePtr, u8 UsbEp, |
| u8 *BufferPtr, u32 BufferLen) |
| { |
| u8 PhyEpNum; |
| s32 RetVal; |
| struct XUsbPsu_Trb *TrbPtr; |
| struct XUsbPsu_Ep *Ept; |
| struct XUsbPsu_EpParams *Params; |
| |
| Xil_AssertNonvoid(InstancePtr != NULL); |
| Xil_AssertNonvoid(UsbEp <= (u8)16U); |
| Xil_AssertNonvoid(BufferPtr != NULL); |
| |
| PhyEpNum = PhysicalEp(UsbEp, XUSBPSU_EP_DIR_IN); |
| if (PhyEpNum == 1U) { |
| RetVal = XUsbPsu_Ep0Send(InstancePtr, BufferPtr, BufferLen); |
| return RetVal; |
| } |
| |
| Ept = &InstancePtr->eps[PhyEpNum]; |
| |
| if (Ept->Direction != XUSBPSU_EP_DIR_IN) { |
| return XST_FAILURE; |
| } |
| |
| Ept->RequestedBytes = BufferLen; |
| Ept->BytesTxed = 0U; |
| Ept->BufferPtr = BufferPtr; |
| |
| TrbPtr = &Ept->EpTrb; |
| Xil_AssertNonvoid(TrbPtr != NULL); |
| |
| TrbPtr->BufferPtrLow = (UINTPTR)BufferPtr; |
| TrbPtr->BufferPtrHigh = ((UINTPTR)BufferPtr >> 16) >> 16; |
| TrbPtr->Size = BufferLen & XUSBPSU_TRB_SIZE_MASK; |
| TrbPtr->Ctrl = XUSBPSU_TRBCTL_NORMAL; |
| |
| TrbPtr->Ctrl |= (XUSBPSU_TRB_CTRL_HWO |
| | XUSBPSU_TRB_CTRL_LST |
| | XUSBPSU_TRB_CTRL_IOC |
| | XUSBPSU_TRB_CTRL_ISP_IMI); |
| |
| Xil_DCacheFlushRange((INTPTR)TrbPtr, sizeof(struct XUsbPsu_Trb)); |
| Xil_DCacheFlushRange((INTPTR)BufferPtr, BufferLen); |
| |
| Params = XUsbPsu_GetEpParams(InstancePtr); |
| Xil_AssertNonvoid(Params != NULL); |
| Params->Param0 = 0U; |
| Params->Param1 = (UINTPTR)TrbPtr; |
| |
| RetVal = XUsbPsu_SendEpCmd(InstancePtr, UsbEp, Ept->Direction, |
| XUSBPSU_DEPCMD_STARTTRANSFER, Params); |
| if (RetVal != XST_SUCCESS) { |
| return XST_FAILURE; |
| } |
| Ept->ResourceIndex = (u8)XUsbPsu_EpGetTransferIndex(InstancePtr, |
| Ept->UsbEpNum, |
| Ept->Direction); |
| return XST_SUCCESS; |
| } |
| |
| /****************************************************************************/ |
| /** |
| * Initiates DMA to receive data on Endpoint from Host. |
| * |
| * @param InstancePtr is a pointer to the XUsbPsu instance. |
| * @param EpNum is USB endpoint number. |
| * @param BufferPtr is pointer to data. |
| * @param Length is length of data to be received. |
| * |
| * @return XST_SUCCESS else XST_FAILURE |
| * |
| * @note None. |
| * |
| *****************************************************************************/ |
| s32 XUsbPsu_EpBufferRecv(struct XUsbPsu *InstancePtr, u8 UsbEp, |
| u8 *BufferPtr, u32 Length) |
| { |
| u8 PhyEpNum; |
| u32 Size; |
| s32 RetVal; |
| struct XUsbPsu_Trb *TrbPtr; |
| struct XUsbPsu_Ep *Ept; |
| struct XUsbPsu_EpParams *Params; |
| |
| Xil_AssertNonvoid(InstancePtr != NULL); |
| Xil_AssertNonvoid(UsbEp <= (u8)16U); |
| Xil_AssertNonvoid(BufferPtr != NULL); |
| |
| PhyEpNum = PhysicalEp(UsbEp, XUSBPSU_EP_DIR_OUT); |
| if (PhyEpNum == 0U) { |
| RetVal = XUsbPsu_Ep0Recv(InstancePtr, BufferPtr, Length); |
| return RetVal; |
| } |
| |
| Ept = &InstancePtr->eps[PhyEpNum]; |
| |
| if (Ept->Direction != XUSBPSU_EP_DIR_OUT) { |
| return XST_FAILURE; |
| } |
| |
| Ept->RequestedBytes = Length; |
| Size = Length; |
| Ept->BytesTxed = 0U; |
| Ept->BufferPtr = BufferPtr; |
| |
| /* |
| * 8.2.5 - An OUT transfer size (Total TRB buffer allocation) |
| * must be a multiple of MaxPacketSize even if software is expecting a |
| * fixed non-multiple of MaxPacketSize transfer from the Host. |
| */ |
| if (!IS_ALIGNED(Length, Ept->MaxSize)) { |
| Size = (u32)roundup(Length, Ept->MaxSize); |
| Ept->UnalignedTx = 1U; |
| } |
| |
| TrbPtr = &Ept->EpTrb; |
| Xil_AssertNonvoid(TrbPtr != NULL); |
| |
| TrbPtr->BufferPtrLow = (UINTPTR)BufferPtr; |
| TrbPtr->BufferPtrHigh = ((UINTPTR)BufferPtr >> 16) >> 16; |
| TrbPtr->Size = Size; |
| TrbPtr->Ctrl = XUSBPSU_TRBCTL_NORMAL; |
| |
| TrbPtr->Ctrl |= (XUSBPSU_TRB_CTRL_HWO |
| | XUSBPSU_TRB_CTRL_LST |
| | XUSBPSU_TRB_CTRL_IOC |
| | XUSBPSU_TRB_CTRL_ISP_IMI); |
| |
| |
| Xil_DCacheFlushRange((INTPTR)TrbPtr, sizeof(struct XUsbPsu_Trb)); |
| Xil_DCacheInvalidateRange((INTPTR)BufferPtr, Length); |
| |
| Params = XUsbPsu_GetEpParams(InstancePtr); |
| Xil_AssertNonvoid(Params != NULL); |
| Params->Param0 = 0U; |
| Params->Param1 = (UINTPTR)TrbPtr; |
| |
| RetVal = XUsbPsu_SendEpCmd(InstancePtr, UsbEp, Ept->Direction, |
| XUSBPSU_DEPCMD_STARTTRANSFER, Params); |
| if (RetVal != XST_SUCCESS) { |
| return XST_FAILURE; |
| } |
| Ept->ResourceIndex = (u8)XUsbPsu_EpGetTransferIndex(InstancePtr, |
| Ept->UsbEpNum, |
| Ept->Direction); |
| return XST_SUCCESS; |
| } |
| |
| /****************************************************************************/ |
| /** |
| * Stalls an Endpoint. |
| * |
| * @param InstancePtr is a pointer to the XUsbPsu instance. |
| * @param EpNum is USB endpoint number. |
| * @param Dir is direction. |
| * |
| * @return None. |
| * |
| * @note None. |
| * |
| *****************************************************************************/ |
| void XUsbPsu_EpSetStall(struct XUsbPsu *InstancePtr, u8 Epnum, u8 Dir) |
| { |
| u8 PhyEpNum; |
| struct XUsbPsu_Ep *Ept = NULL; |
| struct XUsbPsu_EpParams *Params; |
| |
| Xil_AssertVoid(InstancePtr != NULL); |
| Xil_AssertVoid(Epnum <= (u8)16U); |
| Xil_AssertVoid((Dir == XUSBPSU_EP_DIR_IN) || (Dir == XUSBPSU_EP_DIR_OUT)); |
| |
| PhyEpNum = PhysicalEp(Epnum, Dir); |
| Ept = &InstancePtr->eps[PhyEpNum]; |
| |
| Params = XUsbPsu_GetEpParams(InstancePtr); |
| Xil_AssertVoid(Params != NULL); |
| |
| (void)XUsbPsu_SendEpCmd(InstancePtr, Ept->PhyEpNum, Ept->Direction, |
| XUSBPSU_DEPCMD_SETSTALL, Params); |
| |
| Ept->EpStatus |= XUSBPSU_EP_STALL; |
| } |
| |
| /****************************************************************************/ |
| /** |
| * Clears Stall on an Endpoint. |
| * |
| * @param InstancePtr is a pointer to the XUsbPsu instance. |
| * @param EpNum is USB endpoint number. |
| * @param Dir is direction. |
| * |
| * @return None. |
| * |
| * @note None. |
| * |
| *****************************************************************************/ |
| void XUsbPsu_EpClearStall(struct XUsbPsu *InstancePtr, u8 Epnum, u8 Dir) |
| { |
| u8 PhyEpNum; |
| struct XUsbPsu_Ep *Ept = NULL; |
| struct XUsbPsu_EpParams *Params; |
| |
| Xil_AssertVoid(InstancePtr != NULL); |
| Xil_AssertVoid(Epnum <= (u8)16U); |
| Xil_AssertVoid((Dir == XUSBPSU_EP_DIR_IN) || (Dir == XUSBPSU_EP_DIR_OUT)); |
| |
| PhyEpNum = PhysicalEp(Epnum, Dir); |
| Ept = &InstancePtr->eps[PhyEpNum]; |
| |
| Params = XUsbPsu_GetEpParams(InstancePtr); |
| Xil_AssertVoid(Params != NULL); |
| |
| (void)XUsbPsu_SendEpCmd(InstancePtr, Ept->PhyEpNum, Ept->Direction, |
| XUSBPSU_DEPCMD_CLEARSTALL, Params); |
| |
| Ept->EpStatus &= ~XUSBPSU_EP_STALL; |
| } |
| |
| /****************************************************************************/ |
| /** |
| * Sets an user handler to be called after data is sent/received by an Endpoint |
| * |
| * @param InstancePtr is a pointer to the XUsbPsu instance. |
| * @param EpNum is USB endpoint number. |
| * @param Dir is direction of endpoint - XUSBPSU_EP_DIR_IN/XUSBPSU_EP_DIR_OUT. |
| * @param Handler is user handler to be called. |
| * |
| * @return None. |
| * |
| * @note None. |
| * |
| *****************************************************************************/ |
| void XUsbPsu_SetEpHandler(struct XUsbPsu *InstancePtr, u8 Epnum, |
| u8 Dir, void (*Handler)(void *, u32, u32)) |
| { |
| u8 PhyEpNum; |
| struct XUsbPsu_Ep *Ept; |
| |
| Xil_AssertVoid(InstancePtr != NULL); |
| Xil_AssertVoid(Epnum <= (u8)16U); |
| Xil_AssertVoid((Dir == XUSBPSU_EP_DIR_IN) || (Dir == XUSBPSU_EP_DIR_OUT)); |
| |
| PhyEpNum = PhysicalEp(Epnum, Dir); |
| Ept = &InstancePtr->eps[PhyEpNum]; |
| Ept->Handler = Handler; |
| } |
| |
| /****************************************************************************/ |
| /** |
| * Returns status of endpoint - Stalled or not |
| * |
| * @param InstancePtr is a pointer to the XUsbPsu instance. |
| * @param EpNum is USB endpoint number. |
| * @param Dir is direction of endpoint - XUSBPSU_EP_DIR_IN/XUSBPSU_EP_DIR_OUT. |
| * |
| * @return |
| * 1 - if stalled |
| * 0 - if not stalled |
| * |
| * @note None. |
| * |
| *****************************************************************************/ |
| s32 XUsbPsu_IsEpStalled(struct XUsbPsu *InstancePtr, u8 Epnum, u8 Dir) |
| { |
| u8 PhyEpNum; |
| struct XUsbPsu_Ep *Ept; |
| |
| Xil_AssertNonvoid(InstancePtr != NULL); |
| Xil_AssertNonvoid(Epnum <= (u8)16U); |
| Xil_AssertNonvoid((Dir == XUSBPSU_EP_DIR_IN) || (Dir == XUSBPSU_EP_DIR_OUT)); |
| |
| PhyEpNum = PhysicalEp(Epnum, Dir); |
| Ept = &InstancePtr->eps[PhyEpNum]; |
| |
| return (s32)(!!(Ept->EpStatus & XUSBPSU_EP_STALL)); |
| } |
| |
| /****************************************************************************/ |
| /** |
| * Checks the Data Phase and calls user Endpoint handler. |
| * |
| * @param InstancePtr is a pointer to the XUsbPsu instance. |
| * @param Event is a pointer to the Endpoint event occured in core. |
| * |
| * @return None. |
| * |
| * @note None. |
| * |
| *****************************************************************************/ |
| void XUsbPsu_EpXferComplete(struct XUsbPsu *InstancePtr, |
| const struct XUsbPsu_Event_Epevt *Event) |
| { |
| struct XUsbPsu_Ep *Ept; |
| struct XUsbPsu_Trb *TrbPtr; |
| u32 Length; |
| u32 Epnum; |
| u8 Dir; |
| |
| Xil_AssertVoid(InstancePtr != NULL); |
| Xil_AssertVoid(Event != NULL); |
| |
| Epnum = Event->Epnumber; |
| Ept = &InstancePtr->eps[Epnum]; |
| Dir = Ept->Direction; |
| TrbPtr = &Ept->EpTrb; |
| Xil_AssertVoid(TrbPtr != NULL); |
| |
| Xil_DCacheInvalidateRange((INTPTR)TrbPtr, sizeof(struct XUsbPsu_Trb)); |
| |
| Length = TrbPtr->Size & XUSBPSU_TRB_SIZE_MASK; |
| |
| if (Length == 0U) { |
| Ept->BytesTxed = Ept->RequestedBytes; |
| } else { |
| if (Dir == XUSBPSU_EP_DIR_IN) { |
| Ept->BytesTxed = Ept->RequestedBytes - Length; |
| } else if (Dir == XUSBPSU_EP_DIR_OUT) { |
| if (Ept->UnalignedTx == 1U) { |
| Ept->BytesTxed = Ept->RequestedBytes; |
| Ept->UnalignedTx = 0U; |
| } |
| } |
| } |
| |
| if (Dir == XUSBPSU_EP_DIR_OUT) { |
| /* Invalidate Cache */ |
| Xil_DCacheInvalidateRange((INTPTR)Ept->BufferPtr, Ept->BytesTxed); |
| } |
| |
| if (Ept->Handler != NULL) { |
| Ept->Handler(InstancePtr, Ept->RequestedBytes, Ept->BytesTxed); |
| } |
| } |
| /** @} */ |