1 /******************************************************************************
3 * Copyright (C) 2016 Xilinx, Inc. All rights reserved.
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
15 * Use of the Software is limited solely to applications:
16 * (a) running on a Xilinx device, or
17 * (b) that interact with a Xilinx device through a bus or interconnect.
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
24 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 * Except as contained in this notice, the name of the Xilinx shall not be used
28 * in advertising or otherwise to promote the sale, use or other dealings in
29 * this Software without prior written authorization from Xilinx.
31 ******************************************************************************/
32 /****************************************************************************/
35 * @file xusbpsu_controltransfers.c
36 * @addtogroup usbpsu_v1_0
40 * MODIFICATION HISTORY:
42 * Ver Who Date Changes
43 * ----- ---- -------- -------------------------------------------------------
44 * 1.0 sg 06/06/16 First release
48 *****************************************************************************/
50 /***************************** Include Files *********************************/
53 #include "xusbpsu_endpoint.h"
54 /************************** Constant Definitions *****************************/
56 #define USB_DIR_OUT 0U /* to device */
57 #define USB_DIR_IN 0x80U /* to host */
59 /**************************** Type Definitions *******************************/
61 /***************** Macros (Inline Functions) Definitions *********************/
63 /************************** Function Prototypes ******************************/
66 /************************** Variable Definitions *****************************/
69 /****************************************************************************/
71 * Initiates DMA on Control Endpoint 0 to receive Setup packet.
73 * @param InstancePtr is a pointer to the XUsbPsu instance.
75 * @return XST_SUCCESS else XST_FAILURE.
79 *****************************************************************************/
80 s32 XUsbPsu_RecvSetup(struct XUsbPsu *InstancePtr)
82 struct XUsbPsu_EpParams *Params;
83 struct XUsbPsu_Trb *TrbPtr;
84 struct XUsbPsu_Ep *Ept;
87 Xil_AssertNonvoid(InstancePtr != NULL);
89 Params = XUsbPsu_GetEpParams(InstancePtr);
90 Xil_AssertNonvoid(Params != NULL);
92 /* Setup packet always on EP0 */
93 Ept = &InstancePtr->eps[0];
94 if ((Ept->EpStatus & XUSBPSU_EP_BUSY) != 0U) {
98 TrbPtr = &InstancePtr->Ep0_Trb;
100 TrbPtr->BufferPtrLow = (UINTPTR)&InstancePtr->SetupData;
101 TrbPtr->BufferPtrHigh = ((UINTPTR)&InstancePtr->SetupData >> 16) >> 16;
103 TrbPtr->Ctrl = XUSBPSU_TRBCTL_CONTROL_SETUP;
105 TrbPtr->Ctrl |= (XUSBPSU_TRB_CTRL_HWO
106 | XUSBPSU_TRB_CTRL_LST
107 | XUSBPSU_TRB_CTRL_IOC
108 | XUSBPSU_TRB_CTRL_ISP_IMI);
110 Xil_DCacheFlushRange((INTPTR)TrbPtr, sizeof(struct XUsbPsu_Trb));
113 Params->Param1 = (UINTPTR)TrbPtr;
115 InstancePtr->Ep0State = XUSBPSU_EP0_SETUP_PHASE;
117 Ret = XUsbPsu_SendEpCmd(InstancePtr, 0U, XUSBPSU_EP_DIR_OUT,
118 XUSBPSU_DEPCMD_STARTTRANSFER, Params);
119 if (Ret != XST_SUCCESS) {
123 Ept->EpStatus |= XUSBPSU_EP_BUSY;
124 Ept->ResourceIndex = (u8)XUsbPsu_EpGetTransferIndex(InstancePtr,
125 Ept->UsbEpNum, Ept->Direction);
130 /****************************************************************************/
132 * Stalls Control Endpoint and restarts to receive Setup packet.
134 * @param InstancePtr is a pointer to the XUsbPsu instance.
140 *****************************************************************************/
141 void XUsbPsu_Ep0StallRestart(struct XUsbPsu *InstancePtr)
143 struct XUsbPsu_Ep *Ept;
145 Xil_AssertVoid(InstancePtr != NULL);
147 /* reinitialize physical ep1 */
148 Ept = &InstancePtr->eps[1];
149 Ept->EpStatus = XUSBPSU_EP_ENABLED;
151 /* stall is always issued on EP0 */
152 XUsbPsu_EpSetStall(InstancePtr, 0U, XUSBPSU_EP_DIR_OUT);
154 Ept = &InstancePtr->eps[0];
155 Ept->EpStatus = XUSBPSU_EP_ENABLED;
156 InstancePtr->Ep0State = XUSBPSU_EP0_SETUP_PHASE;
157 (void)XUsbPsu_RecvSetup(InstancePtr);
160 /****************************************************************************/
162 * Checks the Data Phase and calls user Endpoint handler.
164 * @param InstancePtr is a pointer to the XUsbPsu instance.
165 * @param Event is a pointer to the Endpoint event occured in core.
171 *****************************************************************************/
172 void XUsbPsu_Ep0DataDone(struct XUsbPsu *InstancePtr,
173 const struct XUsbPsu_Event_Epevt *Event)
175 struct XUsbPsu_Ep *Ept;
176 struct XUsbPsu_Trb *TrbPtr;
182 Xil_AssertVoid(InstancePtr != NULL);
183 Xil_AssertVoid(Event != NULL);
185 Epnum = Event->Epnumber;
187 Ept = &InstancePtr->eps[Epnum];
188 TrbPtr = &InstancePtr->Ep0_Trb;
190 Xil_DCacheInvalidateRange((INTPTR)TrbPtr, sizeof(struct XUsbPsu_Trb));
192 Status = XUSBPSU_TRB_SIZE_TRBSTS(TrbPtr->Size);
193 if (Status == XUSBPSU_TRBSTS_SETUP_PENDING) {
197 Length = TrbPtr->Size & XUSBPSU_TRB_SIZE_MASK;
200 Ept->BytesTxed = Ept->RequestedBytes;
202 if (Dir == XUSBPSU_EP_DIR_IN) {
203 Ept->BytesTxed = Ept->RequestedBytes - Length;
204 } else if (Dir == XUSBPSU_EP_DIR_OUT) {
205 if (Ept->UnalignedTx == 1U) {
206 Ept->BytesTxed = Ept->RequestedBytes;
207 Ept->UnalignedTx = 0U;
212 if (Dir == XUSBPSU_EP_DIR_OUT) {
213 /* Invalidate Cache */
214 Xil_DCacheInvalidateRange((INTPTR)Ept->BufferPtr, Ept->BytesTxed);
217 if (Ept->Handler != NULL) {
218 Ept->Handler(InstancePtr, Ept->RequestedBytes, Ept->BytesTxed);
222 /****************************************************************************/
224 * Checks the Status Phase and starts next Control transfer.
226 * @param InstancePtr is a pointer to the XUsbPsu instance.
227 * @param Event is a pointer to the Endpoint event occured in core.
233 *****************************************************************************/
234 void XUsbPsu_Ep0StatusDone(struct XUsbPsu *InstancePtr,
235 const struct XUsbPsu_Event_Epevt *Event)
237 struct XUsbPsu_Trb *TrbPtr;
239 Xil_AssertVoid(InstancePtr != NULL);
240 Xil_AssertVoid(Event != NULL);
242 TrbPtr = &InstancePtr->Ep0_Trb;
244 if (InstancePtr->IsInTestMode != 0U) {
247 Ret = XUsbPsu_SetTestMode(InstancePtr,
248 InstancePtr->TestMode);
250 XUsbPsu_Ep0StallRestart(InstancePtr);
254 Xil_DCacheInvalidateRange((INTPTR)TrbPtr, sizeof(struct XUsbPsu_Trb));
256 (void)XUsbPsu_RecvSetup(InstancePtr);
259 /****************************************************************************/
261 * Handles Transfer complete event of Control Endpoints EP0 OUT and EP0 IN.
263 * @param InstancePtr is a pointer to the XUsbPsu instance.
264 * @param Event is a pointer to the Endpoint event occured in core.
270 *****************************************************************************/
271 void XUsbPsu_Ep0XferComplete(struct XUsbPsu *InstancePtr,
272 const struct XUsbPsu_Event_Epevt *Event)
274 struct XUsbPsu_Ep *Ept;
278 Xil_AssertVoid(InstancePtr != NULL);
279 Xil_AssertVoid(Event != NULL);
281 Ept = &InstancePtr->eps[Event->Epnumber];
282 Ctrl = &InstancePtr->SetupData;
284 Ept->EpStatus &= ~XUSBPSU_EP_BUSY;
285 Ept->ResourceIndex = 0U;
287 switch (InstancePtr->Ep0State) {
288 case XUSBPSU_EP0_SETUP_PHASE:
289 Xil_DCacheInvalidateRange((INTPTR)&InstancePtr->SetupData,
290 sizeof(InstancePtr->SetupData));
291 Length = Ctrl->wLength;
293 InstancePtr->IsThreeStage = 0U;
294 InstancePtr->ControlDir = XUSBPSU_EP_DIR_OUT;
296 InstancePtr->IsThreeStage = 1U;
297 InstancePtr->ControlDir = !!(Ctrl->bRequestType &
301 Xil_AssertVoid(InstancePtr->Chapter9 != NULL);
303 InstancePtr->Chapter9(InstancePtr,
304 &InstancePtr->SetupData);
307 case XUSBPSU_EP0_DATA_PHASE:
308 XUsbPsu_Ep0DataDone(InstancePtr, Event);
311 case XUSBPSU_EP0_STATUS_PHASE:
312 XUsbPsu_Ep0StatusDone(InstancePtr, Event);
316 /* Default case is a required MISRA-C guideline. */
321 /****************************************************************************/
323 * Starts Status Phase of Control Transfer
325 * @param InstancePtr is a pointer to the XUsbPsu instance.
326 * @param Event is a pointer to the Endpoint event occured in core.
328 * @return XST_SUCCESS else XST_FAILURE
332 *****************************************************************************/
333 s32 XUsbPsu_Ep0StartStatus(struct XUsbPsu *InstancePtr,
334 const struct XUsbPsu_Event_Epevt *Event)
336 struct XUsbPsu_Ep *Ept;
337 struct XUsbPsu_EpParams *Params;
338 struct XUsbPsu_Trb *TrbPtr;
343 Xil_AssertNonvoid(InstancePtr != NULL);
344 Xil_AssertNonvoid(Event != NULL);
346 Ept = &InstancePtr->eps[Event->Epnumber];
347 Params = XUsbPsu_GetEpParams(InstancePtr);
348 Xil_AssertNonvoid(Params != NULL);
349 if ((Ept->EpStatus & XUSBPSU_EP_BUSY) != 0U) {
353 Type = (InstancePtr->IsThreeStage != 0U) ? XUSBPSU_TRBCTL_CONTROL_STATUS3
354 : XUSBPSU_TRBCTL_CONTROL_STATUS2;
355 TrbPtr = &InstancePtr->Ep0_Trb;
356 /* we use same TrbPtr for setup packet */
357 TrbPtr->BufferPtrLow = (UINTPTR)&InstancePtr->SetupData;
358 TrbPtr->BufferPtrHigh = ((UINTPTR)&InstancePtr->SetupData >> 16) >> 16;
362 TrbPtr->Ctrl |= (XUSBPSU_TRB_CTRL_HWO
363 | XUSBPSU_TRB_CTRL_LST
364 | XUSBPSU_TRB_CTRL_IOC
365 | XUSBPSU_TRB_CTRL_ISP_IMI);
367 Xil_DCacheFlushRange((INTPTR)TrbPtr, sizeof(struct XUsbPsu_Trb));
370 Params->Param1 = (UINTPTR)TrbPtr;
372 InstancePtr->Ep0State = XUSBPSU_EP0_STATUS_PHASE;
375 * Control OUT transfer - Status stage happens on EP0 IN - EP1
376 * Control IN transfer - Status stage happens on EP0 OUT - EP0
378 Dir = !InstancePtr->ControlDir;
380 Ret = XUsbPsu_SendEpCmd(InstancePtr, 0U, Dir,
381 XUSBPSU_DEPCMD_STARTTRANSFER, Params);
382 if (Ret != XST_SUCCESS) {
386 Ept->EpStatus |= XUSBPSU_EP_BUSY;
387 Ept->ResourceIndex = (u8)XUsbPsu_EpGetTransferIndex(InstancePtr,
388 Ept->UsbEpNum, Ept->Direction);
393 /****************************************************************************/
395 * Ends Data Phase - used incase of error.
397 * @param InstancePtr is a pointer to the XUsbPsu instance.
398 * @param Dep is a pointer to the Endpoint structure.
404 *****************************************************************************/
405 void XUsbPsu_Ep0_EndControlData(struct XUsbPsu *InstancePtr,
406 struct XUsbPsu_Ep *Ept)
408 struct XUsbPsu_EpParams *Params;
411 Xil_AssertVoid(InstancePtr != NULL);
412 Xil_AssertVoid(Ept != NULL);
414 if (Ept->ResourceIndex == 0U) {
418 Params = XUsbPsu_GetEpParams(InstancePtr);
419 Xil_AssertVoid(Params != NULL);
421 Cmd = XUSBPSU_DEPCMD_ENDTRANSFER;
422 Cmd |= XUSBPSU_DEPCMD_PARAM(Ept->ResourceIndex);
423 (void)XUsbPsu_SendEpCmd(InstancePtr, Ept->UsbEpNum, Ept->Direction,
425 Ept->ResourceIndex = 0U;
429 /****************************************************************************/
431 * Handles Transfer Not Ready event of Control Endpoints EP0 OUT and EP0 IN.
433 * @param InstancePtr is a pointer to the XUsbPsu instance.
434 * @param Event is a pointer to the Endpoint event occured in core.
440 *****************************************************************************/
441 void XUsbPsu_Ep0XferNotReady(struct XUsbPsu *InstancePtr,
442 const struct XUsbPsu_Event_Epevt *Event)
444 struct XUsbPsu_Ep *Ept;
446 Xil_AssertVoid(InstancePtr != NULL);
447 Xil_AssertVoid(Event != NULL);
449 Ept = &InstancePtr->eps[Event->Epnumber];
451 switch (Event->Status) {
452 case DEPEVT_STATUS_CONTROL_DATA:
454 * We already have a DATA transfer in the controller's cache,
455 * if we receive a XferNotReady(DATA) we will ignore it, unless
456 * it's for the wrong direction.
458 * In that case, we must issue END_TRANSFER command to the Data
459 * Phase we already have started and issue SetStall on the
462 if (Event->Epnumber != InstancePtr->ControlDir) {
463 XUsbPsu_Ep0_EndControlData(InstancePtr, Ept);
464 XUsbPsu_Ep0StallRestart(InstancePtr);
468 case DEPEVT_STATUS_CONTROL_STATUS:
469 (void)XUsbPsu_Ep0StartStatus(InstancePtr, Event);
473 /* Default case is a required MIRSA-C guideline. */
478 /****************************************************************************/
480 * Handles Interrupts of Control Endpoints EP0 OUT and EP0 IN.
482 * @param InstancePtr is a pointer to the XUsbPsu instance.
483 * @param Event is a pointer to the Endpoint event occured in core.
489 *****************************************************************************/
490 void XUsbPsu_Ep0Intr(struct XUsbPsu *InstancePtr,
491 const struct XUsbPsu_Event_Epevt *Event)
494 Xil_AssertVoid(InstancePtr != NULL);
495 Xil_AssertVoid(Event != NULL);
497 switch (Event->Endpoint_Event) {
498 case XUSBPSU_DEPEVT_XFERCOMPLETE:
499 XUsbPsu_Ep0XferComplete(InstancePtr, Event);
502 case XUSBPSU_DEPEVT_XFERNOTREADY:
503 XUsbPsu_Ep0XferNotReady(InstancePtr, Event);
506 case XUSBPSU_DEPEVT_XFERINPROGRESS:
507 case XUSBPSU_DEPEVT_STREAMEVT:
508 case XUSBPSU_DEPEVT_EPCMDCMPLT:
512 /* Default case is a required MIRSA-C guideline. */
517 /****************************************************************************/
519 * Initiates DMA to send data on Control Endpoint EP0 IN to Host.
521 * @param InstancePtr is a pointer to the XUsbPsu instance.
522 * @param BufferPtr is pointer to data.
523 * @param BufferLen is Length of data buffer.
525 * @return XST_SUCCESS else XST_FAILURE
529 *****************************************************************************/
530 s32 XUsbPsu_Ep0Send(struct XUsbPsu *InstancePtr, u8 *BufferPtr, u32 BufferLen)
532 /* Control IN - EP1 */
533 struct XUsbPsu_EpParams *Params;
534 struct XUsbPsu_Ep *Ept;
535 struct XUsbPsu_Trb *TrbPtr;
538 Xil_AssertNonvoid(InstancePtr != NULL);
539 Xil_AssertNonvoid(BufferPtr != NULL);
541 Ept = &InstancePtr->eps[1];
542 Params = XUsbPsu_GetEpParams(InstancePtr);
543 Xil_AssertNonvoid(Params != NULL);
545 if ((Ept->EpStatus & XUSBPSU_EP_BUSY) != 0U) {
549 Ept->RequestedBytes = BufferLen;
551 Ept->BufferPtr = BufferPtr;
553 TrbPtr = &InstancePtr->Ep0_Trb;
555 TrbPtr->BufferPtrLow = (UINTPTR)BufferPtr;
556 TrbPtr->BufferPtrHigh = ((UINTPTR)BufferPtr >> 16) >> 16;
557 TrbPtr->Size = BufferLen;
558 TrbPtr->Ctrl = XUSBPSU_TRBCTL_CONTROL_DATA;
560 TrbPtr->Ctrl |= (XUSBPSU_TRB_CTRL_HWO
561 | XUSBPSU_TRB_CTRL_LST
562 | XUSBPSU_TRB_CTRL_IOC
563 | XUSBPSU_TRB_CTRL_ISP_IMI);
566 Params->Param1 = (UINTPTR)TrbPtr;
568 Xil_DCacheFlushRange((INTPTR)TrbPtr, sizeof(struct XUsbPsu_Trb));
569 Xil_DCacheFlushRange((INTPTR)BufferPtr, BufferLen);
571 InstancePtr->Ep0State = XUSBPSU_EP0_DATA_PHASE;
573 Ret = XUsbPsu_SendEpCmd(InstancePtr, 0U, XUSBPSU_EP_DIR_IN,
574 XUSBPSU_DEPCMD_STARTTRANSFER, Params);
575 if (Ret != XST_SUCCESS) {
579 Ept->EpStatus |= XUSBPSU_EP_BUSY;
580 Ept->ResourceIndex = (u8)XUsbPsu_EpGetTransferIndex(InstancePtr,
581 Ept->UsbEpNum, Ept->Direction);
586 /****************************************************************************/
588 * Initiates DMA to receive data on Control Endpoint EP0 OUT from Host.
590 * @param InstancePtr is a pointer to the XUsbPsu instance.
591 * @param BufferPtr is pointer to data.
592 * @param Length is Length of data to be received.
594 * @return XST_SUCCESS else XST_FAILURE
598 *****************************************************************************/
599 s32 XUsbPsu_Ep0Recv(struct XUsbPsu *InstancePtr, u8 *BufferPtr, u32 Length)
601 struct XUsbPsu_EpParams *Params;
602 struct XUsbPsu_Ep *Ept;
603 struct XUsbPsu_Trb *TrbPtr;
607 Xil_AssertNonvoid(InstancePtr != NULL);
608 Xil_AssertNonvoid(BufferPtr != NULL);
610 Ept = &InstancePtr->eps[0];
611 Params = XUsbPsu_GetEpParams(InstancePtr);
612 Xil_AssertNonvoid(Params != NULL);
614 if ((Ept->EpStatus & XUSBPSU_EP_BUSY) != 0U) {
618 Ept->RequestedBytes = Length;
621 Ept->BufferPtr = BufferPtr;
624 * 8.2.5 - An OUT transfer size (Total TRB buffer allocation)
625 * must be a multiple of MaxPacketSize even if software is expecting a
626 * fixed non-multiple of MaxPacketSize transfer from the Host.
628 if (!IS_ALIGNED(Length, Ept->MaxSize)) {
629 Size = (u32)roundup(Length, Ept->MaxSize);
630 InstancePtr->UnalignedTx = 1U;
633 TrbPtr = &InstancePtr->Ep0_Trb;
635 TrbPtr->BufferPtrLow = (UINTPTR)BufferPtr;
636 TrbPtr->BufferPtrHigh = ((UINTPTR)BufferPtr >> 16) >> 16;
638 TrbPtr->Ctrl = XUSBPSU_TRBCTL_CONTROL_DATA;
640 TrbPtr->Ctrl |= (XUSBPSU_TRB_CTRL_HWO
641 | XUSBPSU_TRB_CTRL_LST
642 | XUSBPSU_TRB_CTRL_IOC
643 | XUSBPSU_TRB_CTRL_ISP_IMI);
645 Xil_DCacheFlushRange((INTPTR)TrbPtr, sizeof(struct XUsbPsu_Trb));
646 Xil_DCacheInvalidateRange((INTPTR)BufferPtr, Length);
649 Params->Param1 = (UINTPTR)TrbPtr;
651 InstancePtr->Ep0State = XUSBPSU_EP0_DATA_PHASE;
653 Ret = XUsbPsu_SendEpCmd(InstancePtr, 0U, XUSBPSU_EP_DIR_OUT,
654 XUSBPSU_DEPCMD_STARTTRANSFER, Params);
655 if (Ret != XST_SUCCESS) {
659 Ept->EpStatus |= XUSBPSU_EP_BUSY;
660 Ept->ResourceIndex = (u8)XUsbPsu_EpGetTransferIndex(InstancePtr,
661 Ept->UsbEpNum, Ept->Direction);
666 /*****************************************************************************/
669 * API for Sleep routine.
671 * @param USeconds is time in MicroSeconds.
677 ******************************************************************************/
678 void XUsbSleep(u32 USeconds) {
679 (void)usleep(USeconds);