3 Copyright (c) 2007, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 The EHCI register operation routines.
29 Create Frame List Structure
31 @param Uhc UHCI device
33 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources
34 @retval EFI_UNSUPPORTED Map memory fail
35 @retval EFI_SUCCESS Success
43 EFI_PHYSICAL_ADDRESS MappedAddr
;
52 // The Frame List is a common buffer that will be
53 // accessed by both the cpu and the usb bus master
54 // at the same time. The Frame List ocupies 4K bytes,
55 // and must be aligned on 4-Kbyte boundaries.
58 Pages
= EFI_SIZE_TO_PAGES (Bytes
);
60 Status
= Uhc
->PciIo
->AllocateBuffer (
69 if (EFI_ERROR (Status
)) {
70 return EFI_OUT_OF_RESOURCES
;
73 Status
= Uhc
->PciIo
->Map (
75 EfiPciIoOperationBusMasterCommonBuffer
,
82 if (EFI_ERROR (Status
) || (Bytes
!= 4096)) {
83 Status
= EFI_UNSUPPORTED
;
87 Uhc
->FrameBase
= (UINT32
*) (UINTN
) MappedAddr
;
88 Uhc
->FrameMapping
= Mapping
;
91 // Allocate the QH used by sync interrupt/control/bulk transfer.
92 // FS ctrl/bulk queue head is set to loopback so additional BW
93 // can be reclaimed. Notice, LS don't support bulk transfer and
94 // also doesn't support BW reclamation.
96 Uhc
->SyncIntQh
= UhciCreateQh (Uhc
, 1);
97 Uhc
->CtrlQh
= UhciCreateQh (Uhc
, 1);
98 Uhc
->BulkQh
= UhciCreateQh (Uhc
, 1);
100 if ((Uhc
->SyncIntQh
== NULL
) || (Uhc
->CtrlQh
== NULL
) || (Uhc
->BulkQh
== NULL
)) {
101 Uhc
->PciIo
->Unmap (Uhc
->PciIo
, Mapping
);
102 Status
= EFI_OUT_OF_RESOURCES
;
109 // Link the three together: SyncIntQh->CtrlQh->BulkQh <---------+
110 // Each frame entry is linked to this sequence of QH. These QH
111 // will remain on the schedul, never got removed
113 Uhc
->SyncIntQh
->QhHw
.HorizonLink
= QH_HLINK (Uhc
->CtrlQh
, FALSE
);
114 Uhc
->SyncIntQh
->NextQh
= Uhc
->CtrlQh
;
116 Uhc
->CtrlQh
->QhHw
.HorizonLink
= QH_HLINK (Uhc
->BulkQh
, FALSE
);
117 Uhc
->CtrlQh
->NextQh
= Uhc
->BulkQh
;
120 // Some old platform such as Intel's Tiger 4 has a difficult time
121 // in supporting the full speed bandwidth reclamation in the previous
122 // mentioned form. Most new platforms don't suffer it.
124 Uhc
->BulkQh
->QhHw
.HorizonLink
= QH_HLINK (Uhc
->BulkQh
, FALSE
);
126 Uhc
->BulkQh
->NextQh
= NULL
;
128 for (Index
= 0; Index
< UHCI_FRAME_NUM
; Index
++) {
129 Uhc
->FrameBase
[Index
] = QH_HLINK (Uhc
->SyncIntQh
, FALSE
);
133 // Tell the Host Controller where the Frame List lies,
134 // by set the Frame List Base Address Register.
136 UhciSetFrameListBaseAddr (Uhc
->PciIo
, (VOID
*) (Uhc
->FrameBase
));
140 if (Uhc
->SyncIntQh
!= NULL
) {
141 UsbHcFreeMem (Uhc
->MemPool
, Uhc
->SyncIntQh
, sizeof (UHCI_QH_SW
));
144 if (Uhc
->CtrlQh
!= NULL
) {
145 UsbHcFreeMem (Uhc
->MemPool
, Uhc
->CtrlQh
, sizeof (UHCI_QH_SW
));
148 if (Uhc
->BulkQh
!= NULL
) {
149 UsbHcFreeMem (Uhc
->MemPool
, Uhc
->BulkQh
, sizeof (UHCI_QH_SW
));
152 Uhc
->PciIo
->FreeBuffer (Uhc
->PciIo
, Pages
, Buffer
);
158 Destory FrameList buffer
160 @param Uhc The UHCI device
166 UhciDestoryFrameList (
171 // Unmap the common buffer for framelist entry,
172 // and free the common buffer.
173 // Uhci's frame list occupy 4k memory.
175 Uhc
->PciIo
->Unmap (Uhc
->PciIo
, Uhc
->FrameMapping
);
177 Uhc
->PciIo
->FreeBuffer (
179 EFI_SIZE_TO_PAGES (4096),
180 (VOID
*) Uhc
->FrameBase
183 if (Uhc
->SyncIntQh
!= NULL
) {
184 UsbHcFreeMem (Uhc
->MemPool
, Uhc
->SyncIntQh
, sizeof (UHCI_QH_SW
));
187 if (Uhc
->CtrlQh
!= NULL
) {
188 UsbHcFreeMem (Uhc
->MemPool
, Uhc
->CtrlQh
, sizeof (UHCI_QH_SW
));
191 if (Uhc
->BulkQh
!= NULL
) {
192 UsbHcFreeMem (Uhc
->MemPool
, Uhc
->BulkQh
, sizeof (UHCI_QH_SW
));
195 Uhc
->FrameBase
= NULL
;
196 Uhc
->SyncIntQh
= NULL
;
203 Convert the poll rate to the maxium 2^n that is smaller
206 @param Interval The poll rate to convert
208 @return The converted poll rate
212 UhciConvertPollRate (
218 ASSERT (Interval
!= 0);
221 // Find the index (1 based) of the highest non-zero bit
225 while (Interval
!= 0) {
230 return (UINTN
)1 << (BitCount
- 1);
235 Link a queue head (for asynchronous interrupt transfer) to
238 @param FrameBase The base of the frame list
239 @param Qh The queue head to link into
245 UhciLinkQhToFrameList (
254 ASSERT ((FrameBase
!= NULL
) && (Qh
!= NULL
));
256 for (Index
= 0; Index
< UHCI_FRAME_NUM
; Index
+= Qh
->Interval
) {
258 // First QH can't be NULL because we always keep static queue
259 // heads on the frame list
261 ASSERT (!LINK_TERMINATED (FrameBase
[Index
]));
262 Next
= UHCI_ADDR (FrameBase
[Index
]);
266 // Now, insert the queue head (Qh) into this frame:
267 // 1. Find a queue head with the same poll interval, just insert
268 // Qh after this queue head, then we are done.
270 // 2. Find the position to insert the queue head into:
271 // Previous head's interval is bigger than Qh's
272 // Next head's interval is less than Qh's
273 // Then, insert the Qh between then
275 // This method is very much the same as that used by EHCI.
276 // Because each QH's interval is round down to 2^n, poll
279 while (Next
->Interval
> Qh
->Interval
) {
284 ASSERT (Next
!= NULL
);
287 // The entry may have been linked into the frame by early insertation.
288 // For example: if insert a Qh with Qh.Interval == 4, and there is a Qh
289 // with Qh.Interval == 8 on the frame. If so, we are done with this frame.
290 // It isn't necessary to compare all the QH with the same interval to
291 // Qh. This is because if there is other QH with the same interval, Qh
292 // should has been inserted after that at FrameBase[0] and at FrameBase[0] it is
293 // impossible (Next == Qh)
299 if (Next
->Interval
== Qh
->Interval
) {
301 // If there is a QH with the same interval, it locates at
302 // FrameBase[0], and we can simply insert it after this QH. We
305 ASSERT ((Index
== 0) && (Qh
->NextQh
== NULL
));
313 Qh
->QhHw
.HorizonLink
= Prev
->QhHw
.HorizonLink
;
314 Prev
->QhHw
.HorizonLink
= QH_HLINK (Qh
, FALSE
);
319 // OK, find the right position, insert it in. If Qh's next
320 // link has already been set, it is in position. This is
321 // guarranted by 2^n polling interval.
323 if (Qh
->NextQh
== NULL
) {
325 Qh
->QhHw
.HorizonLink
= QH_HLINK (Next
, FALSE
);
329 FrameBase
[Index
] = QH_HLINK (Qh
, FALSE
);
332 Prev
->QhHw
.HorizonLink
= QH_HLINK (Qh
, FALSE
);
339 Unlink QH from the frame list is easier: find all
340 the precedence node, and pointer there next to QhSw's
343 @param FrameBase The base address of the frame list
344 @param Qh The queue head to unlink
350 UhciUnlinkQhFromFrameList (
359 ASSERT ((FrameBase
!= NULL
) && (Qh
!= NULL
));
361 for (Index
= 0; Index
< UHCI_FRAME_NUM
; Index
+= Qh
->Interval
) {
363 // Frame link can't be NULL because we always keep static
364 // queue heads on the frame list
366 ASSERT (!LINK_TERMINATED (FrameBase
[Index
]));
367 This
= UHCI_ADDR (FrameBase
[Index
]);
371 // Walk through the frame's QH list to find the
372 // queue head to remove
374 while ((This
!= NULL
) && (This
!= Qh
)) {
380 // Qh may have already been unlinked from this frame
389 // Qh is the first entry in the frame
391 FrameBase
[Index
] = Qh
->QhHw
.HorizonLink
;
393 Prev
->NextQh
= Qh
->NextQh
;
394 Prev
->QhHw
.HorizonLink
= Qh
->QhHw
.HorizonLink
;
403 @param Uhc This UHCI device
404 @param Td UHCI_TD_SW to check
405 @param IsLow Is Low Speed Device
406 @param QhResult Return the result of this TD list
408 @return Whether the TD's result is finialized.
417 OUT UHCI_QH_RESULT
*QhResult
428 // Initialize the data toggle to that of the first
429 // TD. The next toggle to use is either:
430 // 1. first TD's toggle if no TD is executed OK
431 // 2. the next toggle of last executed-OK TD
433 QhResult
->Result
= EFI_USB_NOERROR
;
434 QhResult
->NextToggle
= (UINT8
)Td
->TdHw
.DataToggle
;
435 QhResult
->Complete
= 0;
439 State
= (UINT8
)TdHw
->Status
;
442 // UHCI will set STALLED bit when it abort the execution
443 // of TD list. There are several reasons:
444 // 1. BABBLE error happened
445 // 2. Received a STALL response
446 // 3. Error count decreased to zero.
448 // It also set CRC/Timeout/NAK/Buffer Error/BitStuff Error
449 // bits when corresponding conditions happen. But these
450 // conditions are not deadly, that is a TD can successfully
451 // completes even these bits are set. But it is likely that
452 // upper layer won't distinguish these condtions. So, only
453 // set these bits when TD is actually halted.
455 if (State
& USBTD_STALLED
) {
456 if (State
& USBTD_BABBLE
) {
457 QhResult
->Result
|= EFI_USB_ERR_BABBLE
;
459 } else if (TdHw
->ErrorCount
!= 0) {
460 QhResult
->Result
|= EFI_USB_ERR_STALL
;
463 if (State
& USBTD_CRC
) {
464 QhResult
->Result
|= EFI_USB_ERR_CRC
;
467 if (State
& USBTD_BUFFERR
) {
468 QhResult
->Result
|= EFI_USB_ERR_BUFFER
;
471 if (Td
->TdHw
.Status
& USBTD_BITSTUFF
) {
472 QhResult
->Result
|= EFI_USB_ERR_BITSTUFF
;
475 if (TdHw
->ErrorCount
== 0) {
476 QhResult
->Result
|= EFI_USB_ERR_TIMEOUT
;
482 } else if (State
& USBTD_ACTIVE
) {
484 // The TD is still active, no need to check further.
486 QhResult
->Result
|= EFI_USB_ERR_NOTEXECUTE
;
493 // Update the next data toggle, it is always the
494 // next to the last known-good TD's data toggle if
495 // any TD is executed OK
497 QhResult
->NextToggle
= (UINT8
) (1 - (UINT8
)TdHw
->DataToggle
);
500 // This TD is finished OK or met short packet read. Update the
501 // transfer length if it isn't a SETUP.
503 Len
= (TdHw
->ActualLen
+ 1) & 0x7FF;
505 if (TdHw
->PidCode
!= SETUP_PACKET_ID
) {
506 QhResult
->Complete
+= Len
;
510 // Short packet condition for full speed input TD, also
511 // terminate the transfer
513 if (!IsLow
&& (TdHw
->ShortPacket
== 1) && (Len
< Td
->DataLen
)) {
514 DEBUG ((EFI_D_INFO
, "UhciCheckTdStatus: short packet read occured\n"));
526 // Check whether HC is halted. Don't move this up. It must be
527 // called after data toggle is successfully updated.
529 if (!UhciIsHcWorking (Uhc
->PciIo
)) {
530 QhResult
->Result
|= EFI_USB_ERR_SYSTEM
;
535 Uhc
->PciIo
->Flush (Uhc
->PciIo
);
538 UhciAckAllInterrupt (Uhc
);
545 Check the result of the transfer
547 @param Uhc The UHCI device
548 @param Td The first TDs of the transfer
549 @param TimeOut TimeOut value in milliseconds
550 @param IsLow Is Low Speed Device
551 @param QhResult The variable to return result
553 @retval EFI_SUCCESS The transfer finished with success
554 @retval EFI_DEVICE_ERROR Transfer failed
558 UhciExecuteTransfer (
564 OUT UHCI_QH_RESULT
*QhResult
573 Status
= EFI_SUCCESS
;
574 Delay
= (TimeOut
* UHC_1_MILLISECOND
/ UHC_SYNC_POLL_INTERVAL
) + 1;
576 for (Index
= 0; Index
< Delay
; Index
++) {
577 Finished
= UhciCheckTdStatus (Uhc
, Td
, IsLow
, QhResult
);
580 // Transfer is OK or some error occured (TD inactive)
586 gBS
->Stall (UHC_SYNC_POLL_INTERVAL
);
590 DEBUG ((EFI_D_ERROR
, "UhciExecuteTransfer: execution not finished for %dms\n", TimeOut
));
594 Status
= EFI_TIMEOUT
;
596 } else if (QhResult
->Result
!= EFI_USB_NOERROR
) {
597 DEBUG ((EFI_D_ERROR
, "UhciExecuteTransfer: execution failed with result %x\n", QhResult
->Result
));
601 Status
= EFI_DEVICE_ERROR
;
609 Update Async Request, QH and TDs
611 @param AsyncReq The UHCI asynchronous transfer to update
612 @param Result Transfer reslut
613 @param ErrTdPos Error TD Position
621 IN UHCI_ASYNC_REQUEST
*AsyncReq
,
631 FirstTd
= AsyncReq
->FirstTd
;
633 if (Result
== EFI_USB_NOERROR
) {
635 // The last transfer succeeds. Then we need to update
636 // the Qh and Td for next round of transfer.
637 // 1. Update the TD's data toggle
638 // 2. Activate all the TDs
639 // 3. Link the TD to the queue head again since during
640 // execution, queue head's TD pointer is changed by
643 for (Td
= FirstTd
; Td
!= NULL
; Td
= Td
->NextTd
) {
644 Td
->TdHw
.DataToggle
= NextToggle
;
646 Td
->TdHw
.Status
|= USBTD_ACTIVE
;
649 UhciLinkTdToQh (Qh
, FirstTd
);
656 Create Async Request node, and Link to List
658 @param Uhc The UHCI device
659 @param Qh The queue head of the transfer
660 @param FirstTd First TD of the transfer
661 @param DevAddr Device Address
662 @param EndPoint EndPoint Address
663 @param DataLen Data length
664 @param Interval Polling Interval when inserted to frame list
665 @param Mapping Mapping value
666 @param Data Data buffer, unmapped
667 @param Callback Callback after interrupt transfeer
668 @param Context Callback Context passed as function parameter
669 @param IsLow Is Low Speed
671 @retval EFI_SUCCESS An asynchronous transfer is created
672 @retval EFI_INVALID_PARAMETER Paremeter is error
673 @retval EFI_OUT_OF_RESOURCES Failed because of resource shortage.
680 IN UHCI_TD_SW
*FirstTd
,
687 IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback
,
692 UHCI_ASYNC_REQUEST
*AsyncReq
;
694 AsyncReq
= AllocatePool (sizeof (UHCI_ASYNC_REQUEST
));
696 if (AsyncReq
== NULL
) {
697 return EFI_OUT_OF_RESOURCES
;
701 // Fill Request field. Data is allocated host memory, not mapped
703 AsyncReq
->Signature
= UHCI_ASYNC_INT_SIGNATURE
;
704 AsyncReq
->DevAddr
= DevAddr
;
705 AsyncReq
->EndPoint
= EndPoint
;
706 AsyncReq
->DataLen
= DataLen
;
707 AsyncReq
->Interval
= Interval
;
708 AsyncReq
->Mapping
= Mapping
;
709 AsyncReq
->Data
= Data
;
710 AsyncReq
->Callback
= Callback
;
711 AsyncReq
->Context
= Context
;
713 AsyncReq
->FirstTd
= FirstTd
;
714 AsyncReq
->IsLow
= IsLow
;
717 // Insert the new interrupt transfer to the head of the list.
718 // The interrupt transfer's monitor function scans the whole
719 // list from head to tail. The new interrupt transfer MUST be
720 // added to the head of the list.
722 InsertHeadList (&(Uhc
->AsyncIntList
), &(AsyncReq
->Link
));
730 Free an asynchronous request's resource such as memory
732 @param Uhc The UHCI device
733 @param AsyncReq The asynchronous request to free
742 IN UHCI_ASYNC_REQUEST
*AsyncReq
745 ASSERT ((Uhc
!= NULL
) && (AsyncReq
!= NULL
));
747 UhciDestoryTds (Uhc
, AsyncReq
->FirstTd
);
748 UsbHcFreeMem (Uhc
->MemPool
, AsyncReq
->QhSw
, sizeof (UHCI_QH_SW
));
750 if (AsyncReq
->Mapping
!= NULL
) {
751 Uhc
->PciIo
->Unmap (Uhc
->PciIo
, AsyncReq
->Mapping
);
754 if (AsyncReq
->Data
!= NULL
) {
755 gBS
->FreePool (AsyncReq
->Data
);
758 gBS
->FreePool (AsyncReq
);
763 Unlink an asynchronous request's from UHC's asynchronus list.
764 also remove the queue head from the frame list. If FreeNow,
765 release its resource also. Otherwise, add the request to the
766 UHC's recycle list to wait for a while before release the memory.
767 Until then, hardware won't hold point to the request.
769 @param Uhc The UHCI device
770 @param AsyncReq The asynchronous request to free
771 @param FreeNow If TRUE, free the resource immediately, otherwise
772 add the request to recycle wait list.
781 IN UHCI_ASYNC_REQUEST
*AsyncReq
,
785 ASSERT ((Uhc
!= NULL
) && (AsyncReq
!= NULL
));
787 RemoveEntryList (&(AsyncReq
->Link
));
788 UhciUnlinkQhFromFrameList (Uhc
->FrameBase
, AsyncReq
->QhSw
);
791 UhciFreeAsyncReq (Uhc
, AsyncReq
);
794 // To sychronize with hardware, mark the queue head as inactive
795 // then add AsyncReq to UHC's recycle list
797 AsyncReq
->QhSw
->QhHw
.VerticalLink
= QH_VLINK (NULL
, TRUE
);
798 AsyncReq
->Recycle
= Uhc
->RecycleWait
;
799 Uhc
->RecycleWait
= AsyncReq
;
805 Delete Async Interrupt QH and TDs
807 @param Uhc The UHCI device
808 @param DevAddr Device Address
809 @param EndPoint EndPoint Address
810 @param Toggle The next data toggle to use
812 @retval EFI_SUCCESS The request is deleted
813 @retval EFI_INVALID_PARAMETER Paremeter is error
814 @retval EFI_NOT_FOUND The asynchronous isn't found
826 UHCI_ASYNC_REQUEST
*AsyncReq
;
827 UHCI_QH_RESULT QhResult
;
831 Status
= EFI_SUCCESS
;
834 // If no asynchronous interrupt transaction exists
836 if (IsListEmpty (&(Uhc
->AsyncIntList
))) {
841 // Find the asynchronous transfer to this device/endpoint pair
844 Link
= Uhc
->AsyncIntList
.ForwardLink
;
847 AsyncReq
= UHCI_ASYNC_INT_FROM_LINK (Link
);
848 Link
= Link
->ForwardLink
;
850 if ((AsyncReq
->DevAddr
== DevAddr
) && (AsyncReq
->EndPoint
== EndPoint
)) {
855 } while (Link
!= &(Uhc
->AsyncIntList
));
858 return EFI_NOT_FOUND
;
862 // Check the result of the async transfer then update it
863 // to get the next data toggle to use.
865 UhciCheckTdStatus (Uhc
, AsyncReq
->FirstTd
, AsyncReq
->IsLow
, &QhResult
);
866 *Toggle
= QhResult
.NextToggle
;
869 // Don't release the request now, keep it to synchronize with hardware.
871 UhciUnlinkAsyncReq (Uhc
, AsyncReq
, FALSE
);
877 Recycle the asynchronouse request. When a queue head
878 is unlinked from frame list, host controller hardware
879 may still hold a cached pointer to it. To synchronize
880 with hardware, the request is released in two steps:
881 first it is linked to the UHC's RecycleWait list. At
882 the next time UhciMonitorAsyncReqList is fired, it is
883 moved to UHC's Recylelist. Then, at another timer
884 activation, all the requests on Recycle list is freed.
885 This guarrantes that each unlink queue head keeps
886 existing for at least 50ms, far enough for the hardware
889 @param Uhc The UHCI device
896 UhciRecycleAsyncReq (
900 UHCI_ASYNC_REQUEST
*Req
;
901 UHCI_ASYNC_REQUEST
*Next
;
905 while (Req
!= NULL
) {
907 UhciFreeAsyncReq (Uhc
, Req
);
911 Uhc
->Recycle
= Uhc
->RecycleWait
;
912 Uhc
->RecycleWait
= NULL
;
918 Release all the asynchronous transfers on the lsit.
920 @param Uhc The UHCI device
926 UhciFreeAllAsyncReq (
931 UHCI_ASYNC_REQUEST
*AsyncReq
;
934 // Call UhciRecycleAsyncReq twice. The requests on Recycle
935 // will be released at the first call; The requests on
936 // RecycleWait will be released at the second call.
938 UhciRecycleAsyncReq (Uhc
);
939 UhciRecycleAsyncReq (Uhc
);
941 Head
= &(Uhc
->AsyncIntList
);
943 if (IsListEmpty (Head
)) {
947 while (!IsListEmpty (Head
)) {
948 AsyncReq
= UHCI_ASYNC_INT_FROM_LINK (Head
->ForwardLink
);
949 UhciUnlinkAsyncReq (Uhc
, AsyncReq
, TRUE
);
955 Interrupt transfer periodic check handler
957 @param Event The event of the time
958 @param Context Context of the event, pointer to USB_HC_DEV
964 UhciMonitorAsyncReqList (
969 UHCI_ASYNC_REQUEST
*AsyncReq
;
974 UHCI_QH_RESULT QhResult
;
976 Uhc
= (USB_HC_DEV
*) Context
;
979 // Recycle the asynchronous requests expired, and promote
980 // requests waiting to be recycled the next time when this
983 UhciRecycleAsyncReq (Uhc
);
985 if (IsListEmpty (&(Uhc
->AsyncIntList
))) {
990 // This loop must be delete safe
992 Link
= Uhc
->AsyncIntList
.ForwardLink
;
995 AsyncReq
= UHCI_ASYNC_INT_FROM_LINK (Link
);
996 Link
= Link
->ForwardLink
;
998 Finished
= UhciCheckTdStatus (Uhc
, AsyncReq
->FirstTd
, AsyncReq
->IsLow
, &QhResult
);
1005 // Copy the data to temporary buffer if there are some
1006 // data transferred. We may have zero-length packet
1010 if (QhResult
.Complete
!= 0) {
1011 Data
= AllocatePool (QhResult
.Complete
);
1017 CopyMem (Data
, AsyncReq
->FirstTd
->Data
, QhResult
.Complete
);
1020 UhciUpdateAsyncReq (AsyncReq
, QhResult
.Result
, QhResult
.NextToggle
);
1023 // Now, either transfer is SUCCESS or met errors since
1024 // we have skipped to next transfer earlier if current
1025 // transfer is still active.
1027 if (QhResult
.Result
== EFI_USB_NOERROR
) {
1028 AsyncReq
->Callback (Data
, QhResult
.Complete
, AsyncReq
->Context
, QhResult
.Result
);
1031 // Leave error recovery to its related device driver.
1032 // A common case of the error recovery is to re-submit
1033 // the interrupt transfer. When an interrupt transfer
1034 // is re-submitted, its position in the linked list is
1035 // changed. It is inserted to the head of the linked
1036 // list, while this function scans the whole list from
1037 // head to tail. Thus, the re-submitted interrupt transfer's
1038 // callback function will not be called again in this round.
1040 AsyncReq
->Callback (NULL
, 0, AsyncReq
->Context
, QhResult
.Result
);
1044 gBS
->FreePool (Data
);
1046 } while (Link
!= &(Uhc
->AsyncIntList
));