3 The EHCI register operation routines.
5 Copyright (c) 2007 - 2011, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
20 Create Frame List Structure.
22 @param Uhc UHCI device.
24 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
25 @retval EFI_UNSUPPORTED Map memory fail.
26 @retval EFI_SUCCESS Success.
34 EFI_PHYSICAL_ADDRESS MappedAddr
;
41 EFI_PHYSICAL_ADDRESS PhyAddr
;
44 // The Frame List is a common buffer that will be
45 // accessed by both the cpu and the usb bus master
46 // at the same time. The Frame List ocupies 4K bytes,
47 // and must be aligned on 4-Kbyte boundaries.
50 Pages
= EFI_SIZE_TO_PAGES (Bytes
);
52 Status
= Uhc
->PciIo
->AllocateBuffer (
61 if (EFI_ERROR (Status
)) {
62 return EFI_OUT_OF_RESOURCES
;
65 Status
= Uhc
->PciIo
->Map (
67 EfiPciIoOperationBusMasterCommonBuffer
,
74 if (EFI_ERROR (Status
) || (Bytes
!= 4096)) {
75 Status
= EFI_UNSUPPORTED
;
79 Uhc
->FrameBase
= (UINT32
*) (UINTN
) Buffer
;
80 Uhc
->FrameMapping
= Mapping
;
83 // Tell the Host Controller where the Frame List lies,
84 // by set the Frame List Base Address Register.
86 UhciSetFrameListBaseAddr (Uhc
->PciIo
, (VOID
*) (UINTN
) MappedAddr
);
89 // Allocate the QH used by sync interrupt/control/bulk transfer.
90 // FS ctrl/bulk queue head is set to loopback so additional BW
91 // can be reclaimed. Notice, LS don't support bulk transfer and
92 // also doesn't support BW reclamation.
94 Uhc
->SyncIntQh
= UhciCreateQh (Uhc
, 1);
95 Uhc
->CtrlQh
= UhciCreateQh (Uhc
, 1);
96 Uhc
->BulkQh
= UhciCreateQh (Uhc
, 1);
98 if ((Uhc
->SyncIntQh
== NULL
) || (Uhc
->CtrlQh
== NULL
) || (Uhc
->BulkQh
== NULL
)) {
99 Uhc
->PciIo
->Unmap (Uhc
->PciIo
, Mapping
);
100 Status
= EFI_OUT_OF_RESOURCES
;
107 // Link the three together: SyncIntQh->CtrlQh->BulkQh <---------+
108 // Each frame entry is linked to this sequence of QH. These QH
109 // will remain on the schedul, never got removed
111 PhyAddr
= UsbHcGetPciAddressForHostMem (Uhc
->MemPool
, Uhc
->CtrlQh
, sizeof (UHCI_QH_HW
));
112 Uhc
->SyncIntQh
->QhHw
.HorizonLink
= QH_HLINK (PhyAddr
, FALSE
);
113 Uhc
->SyncIntQh
->NextQh
= Uhc
->CtrlQh
;
115 PhyAddr
= UsbHcGetPciAddressForHostMem (Uhc
->MemPool
, Uhc
->BulkQh
, sizeof (UHCI_QH_HW
));
116 Uhc
->CtrlQh
->QhHw
.HorizonLink
= QH_HLINK (PhyAddr
, 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 (PhyAddr
, FALSE
);
126 Uhc
->BulkQh
->NextQh
= NULL
;
128 Uhc
->FrameBaseHostAddr
= AllocateZeroPool (4096);
129 if (Uhc
->FrameBaseHostAddr
== NULL
) {
130 Status
= EFI_OUT_OF_RESOURCES
;
134 PhyAddr
= UsbHcGetPciAddressForHostMem (Uhc
->MemPool
, Uhc
->SyncIntQh
, sizeof (UHCI_QH_HW
));
135 for (Index
= 0; Index
< UHCI_FRAME_NUM
; Index
++) {
136 Uhc
->FrameBase
[Index
] = QH_HLINK (PhyAddr
, FALSE
);
137 Uhc
->FrameBaseHostAddr
[Index
] = (UINT32
)(UINTN
)Uhc
->SyncIntQh
;
143 if (Uhc
->SyncIntQh
!= NULL
) {
144 UsbHcFreeMem (Uhc
->MemPool
, Uhc
->SyncIntQh
, sizeof (UHCI_QH_SW
));
147 if (Uhc
->CtrlQh
!= NULL
) {
148 UsbHcFreeMem (Uhc
->MemPool
, Uhc
->CtrlQh
, sizeof (UHCI_QH_SW
));
151 if (Uhc
->BulkQh
!= NULL
) {
152 UsbHcFreeMem (Uhc
->MemPool
, Uhc
->BulkQh
, sizeof (UHCI_QH_SW
));
155 Uhc
->PciIo
->FreeBuffer (Uhc
->PciIo
, Pages
, Buffer
);
161 Destory FrameList buffer.
163 @param Uhc The UHCI device.
167 UhciDestoryFrameList (
172 // Unmap the common buffer for framelist entry,
173 // and free the common buffer.
174 // Uhci's frame list occupy 4k memory.
176 Uhc
->PciIo
->Unmap (Uhc
->PciIo
, Uhc
->FrameMapping
);
178 Uhc
->PciIo
->FreeBuffer (
180 EFI_SIZE_TO_PAGES (4096),
181 (VOID
*) Uhc
->FrameBase
184 if (Uhc
->FrameBaseHostAddr
!= NULL
) {
185 FreePool (Uhc
->FrameBaseHostAddr
);
188 if (Uhc
->SyncIntQh
!= NULL
) {
189 UsbHcFreeMem (Uhc
->MemPool
, Uhc
->SyncIntQh
, sizeof (UHCI_QH_SW
));
192 if (Uhc
->CtrlQh
!= NULL
) {
193 UsbHcFreeMem (Uhc
->MemPool
, Uhc
->CtrlQh
, sizeof (UHCI_QH_SW
));
196 if (Uhc
->BulkQh
!= NULL
) {
197 UsbHcFreeMem (Uhc
->MemPool
, Uhc
->BulkQh
, sizeof (UHCI_QH_SW
));
200 Uhc
->FrameBase
= NULL
;
201 Uhc
->FrameBaseHostAddr
= NULL
;
202 Uhc
->SyncIntQh
= NULL
;
209 Convert the poll rate to the maxium 2^n that is smaller
212 @param Interval The poll rate to convert.
214 @return The converted poll rate.
218 UhciConvertPollRate (
224 ASSERT (Interval
!= 0);
227 // Find the index (1 based) of the highest non-zero bit
231 while (Interval
!= 0) {
236 return (UINTN
)1 << (BitCount
- 1);
241 Link a queue head (for asynchronous interrupt transfer) to
244 @param Uhc The UHCI device.
245 @param Qh The queue head to link into.
249 UhciLinkQhToFrameList (
257 EFI_PHYSICAL_ADDRESS PhyAddr
;
258 EFI_PHYSICAL_ADDRESS QhPciAddr
;
260 ASSERT ((Uhc
->FrameBase
!= NULL
) && (Qh
!= NULL
));
262 QhPciAddr
= UsbHcGetPciAddressForHostMem (Uhc
->MemPool
, Qh
, sizeof (UHCI_QH_HW
));
264 for (Index
= 0; Index
< UHCI_FRAME_NUM
; Index
+= Qh
->Interval
) {
266 // First QH can't be NULL because we always keep static queue
267 // heads on the frame list
269 ASSERT (!LINK_TERMINATED (Uhc
->FrameBase
[Index
]));
270 Next
= (UHCI_QH_SW
*)(UINTN
)Uhc
->FrameBaseHostAddr
[Index
];
274 // Now, insert the queue head (Qh) into this frame:
275 // 1. Find a queue head with the same poll interval, just insert
276 // Qh after this queue head, then we are done.
278 // 2. Find the position to insert the queue head into:
279 // Previous head's interval is bigger than Qh's
280 // Next head's interval is less than Qh's
281 // Then, insert the Qh between then
283 // This method is very much the same as that used by EHCI.
284 // Because each QH's interval is round down to 2^n, poll
287 while (Next
->Interval
> Qh
->Interval
) {
290 ASSERT (Next
!= NULL
);
294 // The entry may have been linked into the frame by early insertation.
295 // For example: if insert a Qh with Qh.Interval == 4, and there is a Qh
296 // with Qh.Interval == 8 on the frame. If so, we are done with this frame.
297 // It isn't necessary to compare all the QH with the same interval to
298 // Qh. This is because if there is other QH with the same interval, Qh
299 // should has been inserted after that at FrameBase[0] and at FrameBase[0] it is
300 // impossible (Next == Qh)
306 if (Next
->Interval
== Qh
->Interval
) {
308 // If there is a QH with the same interval, it locates at
309 // FrameBase[0], and we can simply insert it after this QH. We
312 ASSERT ((Index
== 0) && (Qh
->NextQh
== NULL
));
320 Qh
->QhHw
.HorizonLink
= Prev
->QhHw
.HorizonLink
;
322 Prev
->QhHw
.HorizonLink
= QH_HLINK (QhPciAddr
, FALSE
);
327 // OK, find the right position, insert it in. If Qh's next
328 // link has already been set, it is in position. This is
329 // guarranted by 2^n polling interval.
331 if (Qh
->NextQh
== NULL
) {
333 PhyAddr
= UsbHcGetPciAddressForHostMem (Uhc
->MemPool
, Next
, sizeof (UHCI_QH_HW
));
334 Qh
->QhHw
.HorizonLink
= QH_HLINK (PhyAddr
, FALSE
);
338 Uhc
->FrameBase
[Index
] = QH_HLINK (QhPciAddr
, FALSE
);
339 Uhc
->FrameBaseHostAddr
[Index
] = (UINT32
)(UINTN
)Qh
;
342 Prev
->QhHw
.HorizonLink
= QH_HLINK (QhPciAddr
, FALSE
);
349 Unlink QH from the frame list is easier: find all
350 the precedence node, and pointer there next to QhSw's
353 @param Uhc The UHCI device.
354 @param Qh The queue head to unlink.
358 UhciUnlinkQhFromFrameList (
367 ASSERT ((Uhc
->FrameBase
!= NULL
) && (Qh
!= NULL
));
369 for (Index
= 0; Index
< UHCI_FRAME_NUM
; Index
+= Qh
->Interval
) {
371 // Frame link can't be NULL because we always keep static
372 // queue heads on the frame list
374 ASSERT (!LINK_TERMINATED (Uhc
->FrameBase
[Index
]));
375 This
= (UHCI_QH_SW
*)(UINTN
)Uhc
->FrameBaseHostAddr
[Index
];
379 // Walk through the frame's QH list to find the
380 // queue head to remove
382 while ((This
!= NULL
) && (This
!= Qh
)) {
388 // Qh may have already been unlinked from this frame
397 // Qh is the first entry in the frame
399 Uhc
->FrameBase
[Index
] = Qh
->QhHw
.HorizonLink
;
400 Uhc
->FrameBaseHostAddr
[Index
] = (UINT32
)(UINTN
)Qh
->NextQh
;
402 Prev
->NextQh
= Qh
->NextQh
;
403 Prev
->QhHw
.HorizonLink
= Qh
->QhHw
.HorizonLink
;
412 @param Uhc This UHCI device.
413 @param Td UHCI_TD_SW to check.
414 @param IsLow Is Low Speed Device.
415 @param QhResult Return the result of this TD list.
417 @return Whether the TD's result is finialized.
425 OUT UHCI_QH_RESULT
*QhResult
436 // Initialize the data toggle to that of the first
437 // TD. The next toggle to use is either:
438 // 1. first TD's toggle if no TD is executed OK
439 // 2. the next toggle of last executed-OK TD
441 QhResult
->Result
= EFI_USB_NOERROR
;
442 QhResult
->NextToggle
= (UINT8
)Td
->TdHw
.DataToggle
;
443 QhResult
->Complete
= 0;
447 State
= (UINT8
)TdHw
->Status
;
450 // UHCI will set STALLED bit when it abort the execution
451 // of TD list. There are several reasons:
452 // 1. BABBLE error happened
453 // 2. Received a STALL response
454 // 3. Error count decreased to zero.
456 // It also set CRC/Timeout/NAK/Buffer Error/BitStuff Error
457 // bits when corresponding conditions happen. But these
458 // conditions are not deadly, that is a TD can successfully
459 // completes even these bits are set. But it is likely that
460 // upper layer won't distinguish these condtions. So, only
461 // set these bits when TD is actually halted.
463 if ((State
& USBTD_STALLED
) != 0) {
464 if ((State
& USBTD_BABBLE
) != 0) {
465 QhResult
->Result
|= EFI_USB_ERR_BABBLE
;
467 } else if (TdHw
->ErrorCount
!= 0) {
468 QhResult
->Result
|= EFI_USB_ERR_STALL
;
471 if ((State
& USBTD_CRC
) != 0) {
472 QhResult
->Result
|= EFI_USB_ERR_CRC
;
475 if ((State
& USBTD_BUFFERR
) != 0) {
476 QhResult
->Result
|= EFI_USB_ERR_BUFFER
;
479 if ((Td
->TdHw
.Status
& USBTD_BITSTUFF
) != 0) {
480 QhResult
->Result
|= EFI_USB_ERR_BITSTUFF
;
483 if (TdHw
->ErrorCount
== 0) {
484 QhResult
->Result
|= EFI_USB_ERR_TIMEOUT
;
490 } else if ((State
& USBTD_ACTIVE
) != 0) {
492 // The TD is still active, no need to check further.
494 QhResult
->Result
|= EFI_USB_ERR_NOTEXECUTE
;
501 // Update the next data toggle, it is always the
502 // next to the last known-good TD's data toggle if
503 // any TD is executed OK
505 QhResult
->NextToggle
= (UINT8
) (1 - (UINT8
)TdHw
->DataToggle
);
508 // This TD is finished OK or met short packet read. Update the
509 // transfer length if it isn't a SETUP.
511 Len
= (TdHw
->ActualLen
+ 1) & 0x7FF;
513 if (TdHw
->PidCode
!= SETUP_PACKET_ID
) {
514 QhResult
->Complete
+= Len
;
518 // Short packet condition for full speed input TD, also
519 // terminate the transfer
521 if (!IsLow
&& (TdHw
->ShortPacket
== 1) && (Len
< Td
->DataLen
)) {
522 DEBUG ((EFI_D_INFO
, "UhciCheckTdStatus: short packet read occured\n"));
534 // Check whether HC is halted. Don't move this up. It must be
535 // called after data toggle is successfully updated.
537 if (!UhciIsHcWorking (Uhc
->PciIo
)) {
538 QhResult
->Result
|= EFI_USB_ERR_SYSTEM
;
543 Uhc
->PciIo
->Flush (Uhc
->PciIo
);
546 UhciAckAllInterrupt (Uhc
);
552 Check the result of the transfer.
554 @param Uhc The UHCI device.
555 @param Qh The queue head of the transfer.
556 @param Td The first TDs of the transfer.
557 @param TimeOut TimeOut value in milliseconds.
558 @param IsLow Is Low Speed Device.
559 @param QhResult The variable to return result.
561 @retval EFI_SUCCESS The transfer finished with success.
562 @retval EFI_DEVICE_ERROR Transfer failed.
566 UhciExecuteTransfer (
572 OUT UHCI_QH_RESULT
*QhResult
579 BOOLEAN InfiniteLoop
;
582 Status
= EFI_SUCCESS
;
583 Delay
= (TimeOut
* UHC_1_MILLISECOND
/ UHC_SYNC_POLL_INTERVAL
) + 1;
584 InfiniteLoop
= FALSE
;
587 // According to UEFI spec section 16.2.4, If Timeout is 0, then the caller
588 // must wait for the function to be completed until EFI_SUCCESS or EFI_DEVICE_ERROR
595 for (Index
= 0; InfiniteLoop
|| (Index
< Delay
); Index
++) {
596 Finished
= UhciCheckTdStatus (Uhc
, Td
, IsLow
, QhResult
);
599 // Transfer is OK or some error occured (TD inactive)
605 gBS
->Stall (UHC_SYNC_POLL_INTERVAL
);
609 DEBUG ((EFI_D_ERROR
, "UhciExecuteTransfer: execution not finished for %dms\n", (UINT32
)TimeOut
));
613 Status
= EFI_TIMEOUT
;
615 } else if (QhResult
->Result
!= EFI_USB_NOERROR
) {
616 DEBUG ((EFI_D_ERROR
, "UhciExecuteTransfer: execution failed with result %x\n", QhResult
->Result
));
620 Status
= EFI_DEVICE_ERROR
;
628 Update Async Request, QH and TDs.
630 @param Uhc The UHCI device.
631 @param AsyncReq The UHCI asynchronous transfer to update.
632 @param Result Transfer reslut.
633 @param NextToggle The toggle of next data.
639 IN UHCI_ASYNC_REQUEST
*AsyncReq
,
649 FirstTd
= AsyncReq
->FirstTd
;
651 if (Result
== EFI_USB_NOERROR
) {
653 // The last transfer succeeds. Then we need to update
654 // the Qh and Td for next round of transfer.
655 // 1. Update the TD's data toggle
656 // 2. Activate all the TDs
657 // 3. Link the TD to the queue head again since during
658 // execution, queue head's TD pointer is changed by
661 for (Td
= FirstTd
; Td
!= NULL
; Td
= Td
->NextTd
) {
662 Td
->TdHw
.DataToggle
= NextToggle
;
664 Td
->TdHw
.Status
|= USBTD_ACTIVE
;
667 UhciLinkTdToQh (Uhc
, Qh
, FirstTd
);
674 Create Async Request node, and Link to List.
676 @param Uhc The UHCI device.
677 @param Qh The queue head of the transfer.
678 @param FirstTd First TD of the transfer.
679 @param DevAddr Device Address.
680 @param EndPoint EndPoint Address.
681 @param DataLen Data length.
682 @param Interval Polling Interval when inserted to frame list.
683 @param Data Data buffer, unmapped.
684 @param Callback Callback after interrupt transfeer.
685 @param Context Callback Context passed as function parameter.
686 @param IsLow Is Low Speed.
688 @retval EFI_SUCCESS An asynchronous transfer is created.
689 @retval EFI_INVALID_PARAMETER Paremeter is error.
690 @retval EFI_OUT_OF_RESOURCES Failed because of resource shortage.
697 IN UHCI_TD_SW
*FirstTd
,
703 IN EFI_ASYNC_USB_TRANSFER_CALLBACK Callback
,
708 UHCI_ASYNC_REQUEST
*AsyncReq
;
710 AsyncReq
= AllocatePool (sizeof (UHCI_ASYNC_REQUEST
));
712 if (AsyncReq
== NULL
) {
713 return EFI_OUT_OF_RESOURCES
;
717 // Fill Request field. Data is allocated host memory, not mapped
719 AsyncReq
->Signature
= UHCI_ASYNC_INT_SIGNATURE
;
720 AsyncReq
->DevAddr
= DevAddr
;
721 AsyncReq
->EndPoint
= EndPoint
;
722 AsyncReq
->DataLen
= DataLen
;
723 AsyncReq
->Interval
= UhciConvertPollRate(Interval
);
724 AsyncReq
->Data
= Data
;
725 AsyncReq
->Callback
= Callback
;
726 AsyncReq
->Context
= Context
;
728 AsyncReq
->FirstTd
= FirstTd
;
729 AsyncReq
->IsLow
= IsLow
;
732 // Insert the new interrupt transfer to the head of the list.
733 // The interrupt transfer's monitor function scans the whole
734 // list from head to tail. The new interrupt transfer MUST be
735 // added to the head of the list.
737 InsertHeadList (&(Uhc
->AsyncIntList
), &(AsyncReq
->Link
));
744 Free an asynchronous request's resource such as memory.
746 @param Uhc The UHCI device.
747 @param AsyncReq The asynchronous request to free.
753 IN UHCI_ASYNC_REQUEST
*AsyncReq
756 ASSERT ((Uhc
!= NULL
) && (AsyncReq
!= NULL
));
758 UhciDestoryTds (Uhc
, AsyncReq
->FirstTd
);
759 UsbHcFreeMem (Uhc
->MemPool
, AsyncReq
->QhSw
, sizeof (UHCI_QH_SW
));
761 if (AsyncReq
->Data
!= NULL
) {
762 UsbHcFreeMem (Uhc
->MemPool
, AsyncReq
->Data
, AsyncReq
->DataLen
);
765 gBS
->FreePool (AsyncReq
);
770 Unlink an asynchronous request's from UHC's asynchronus list.
771 also remove the queue head from the frame list. If FreeNow,
772 release its resource also. Otherwise, add the request to the
773 UHC's recycle list to wait for a while before release the memory.
774 Until then, hardware won't hold point to the request.
776 @param Uhc The UHCI device.
777 @param AsyncReq The asynchronous request to free.
778 @param FreeNow If TRUE, free the resource immediately, otherwise
779 add the request to recycle wait list.
785 IN UHCI_ASYNC_REQUEST
*AsyncReq
,
789 ASSERT ((Uhc
!= NULL
) && (AsyncReq
!= NULL
));
791 RemoveEntryList (&(AsyncReq
->Link
));
792 UhciUnlinkQhFromFrameList (Uhc
, AsyncReq
->QhSw
);
795 UhciFreeAsyncReq (Uhc
, AsyncReq
);
798 // To sychronize with hardware, mark the queue head as inactive
799 // then add AsyncReq to UHC's recycle list
801 AsyncReq
->QhSw
->QhHw
.VerticalLink
= QH_VLINK (NULL
, TRUE
);
802 AsyncReq
->Recycle
= Uhc
->RecycleWait
;
803 Uhc
->RecycleWait
= AsyncReq
;
809 Delete Async Interrupt QH and TDs.
811 @param Uhc The UHCI device.
812 @param DevAddr Device Address.
813 @param EndPoint EndPoint Address.
814 @param Toggle The next data toggle to use.
816 @retval EFI_SUCCESS The request is deleted.
817 @retval EFI_INVALID_PARAMETER Paremeter is error.
818 @retval EFI_NOT_FOUND The asynchronous isn't found.
830 UHCI_ASYNC_REQUEST
*AsyncReq
;
831 UHCI_QH_RESULT QhResult
;
835 Status
= EFI_SUCCESS
;
838 // If no asynchronous interrupt transaction exists
840 if (IsListEmpty (&(Uhc
->AsyncIntList
))) {
845 // Find the asynchronous transfer to this device/endpoint pair
848 Link
= Uhc
->AsyncIntList
.ForwardLink
;
851 AsyncReq
= UHCI_ASYNC_INT_FROM_LINK (Link
);
852 Link
= Link
->ForwardLink
;
854 if ((AsyncReq
->DevAddr
== DevAddr
) && (AsyncReq
->EndPoint
== EndPoint
)) {
859 } while (Link
!= &(Uhc
->AsyncIntList
));
862 return EFI_NOT_FOUND
;
866 // Check the result of the async transfer then update it
867 // to get the next data toggle to use.
869 UhciCheckTdStatus (Uhc
, AsyncReq
->FirstTd
, AsyncReq
->IsLow
, &QhResult
);
870 *Toggle
= QhResult
.NextToggle
;
873 // Don't release the request now, keep it to synchronize with hardware.
875 UhciUnlinkAsyncReq (Uhc
, AsyncReq
, FALSE
);
881 Recycle the asynchronouse request. When a queue head
882 is unlinked from frame list, host controller hardware
883 may still hold a cached pointer to it. To synchronize
884 with hardware, the request is released in two steps:
885 first it is linked to the UHC's RecycleWait list. At
886 the next time UhciMonitorAsyncReqList is fired, it is
887 moved to UHC's Recylelist. Then, at another timer
888 activation, all the requests on Recycle list is freed.
889 This guarrantes that each unlink queue head keeps
890 existing for at least 50ms, far enough for the hardware
893 @param Uhc The UHCI device.
897 UhciRecycleAsyncReq (
901 UHCI_ASYNC_REQUEST
*Req
;
902 UHCI_ASYNC_REQUEST
*Next
;
906 while (Req
!= NULL
) {
908 UhciFreeAsyncReq (Uhc
, Req
);
912 Uhc
->Recycle
= Uhc
->RecycleWait
;
913 Uhc
->RecycleWait
= NULL
;
919 Release all the asynchronous transfers on the lsit.
921 @param Uhc The UHCI device.
925 UhciFreeAllAsyncReq (
930 UHCI_ASYNC_REQUEST
*AsyncReq
;
933 // Call UhciRecycleAsyncReq twice. The requests on Recycle
934 // will be released at the first call; The requests on
935 // RecycleWait will be released at the second call.
937 UhciRecycleAsyncReq (Uhc
);
938 UhciRecycleAsyncReq (Uhc
);
940 Head
= &(Uhc
->AsyncIntList
);
942 if (IsListEmpty (Head
)) {
946 while (!IsListEmpty (Head
)) {
947 AsyncReq
= UHCI_ASYNC_INT_FROM_LINK (Head
->ForwardLink
);
948 UhciUnlinkAsyncReq (Uhc
, AsyncReq
, TRUE
);
954 Interrupt transfer periodic check handler.
956 @param Event The event of the time.
957 @param Context Context of the event, pointer to USB_HC_DEV.
962 UhciMonitorAsyncReqList (
967 UHCI_ASYNC_REQUEST
*AsyncReq
;
972 UHCI_QH_RESULT QhResult
;
974 Uhc
= (USB_HC_DEV
*) Context
;
977 // Recycle the asynchronous requests expired, and promote
978 // requests waiting to be recycled the next time when this
981 UhciRecycleAsyncReq (Uhc
);
983 if (IsListEmpty (&(Uhc
->AsyncIntList
))) {
988 // This loop must be delete safe
990 Link
= Uhc
->AsyncIntList
.ForwardLink
;
993 AsyncReq
= UHCI_ASYNC_INT_FROM_LINK (Link
);
994 Link
= Link
->ForwardLink
;
996 Finished
= UhciCheckTdStatus (Uhc
, AsyncReq
->FirstTd
, AsyncReq
->IsLow
, &QhResult
);
1003 // Copy the data to temporary buffer if there are some
1004 // data transferred. We may have zero-length packet
1008 if (QhResult
.Complete
!= 0) {
1009 Data
= AllocatePool (QhResult
.Complete
);
1015 CopyMem (Data
, AsyncReq
->FirstTd
->Data
, QhResult
.Complete
);
1018 UhciUpdateAsyncReq (Uhc
, AsyncReq
, QhResult
.Result
, QhResult
.NextToggle
);
1021 // Now, either transfer is SUCCESS or met errors since
1022 // we have skipped to next transfer earlier if current
1023 // transfer is still active.
1025 if (QhResult
.Result
== EFI_USB_NOERROR
) {
1026 AsyncReq
->Callback (Data
, QhResult
.Complete
, AsyncReq
->Context
, QhResult
.Result
);
1029 // Leave error recovery to its related device driver.
1030 // A common case of the error recovery is to re-submit
1031 // the interrupt transfer. When an interrupt transfer
1032 // is re-submitted, its position in the linked list is
1033 // changed. It is inserted to the head of the linked
1034 // list, while this function scans the whole list from
1035 // head to tail. Thus, the re-submitted interrupt transfer's
1036 // callback function will not be called again in this round.
1038 AsyncReq
->Callback (NULL
, 0, AsyncReq
->Context
, QhResult
.Result
);
1042 gBS
->FreePool (Data
);
1044 } while (Link
!= &(Uhc
->AsyncIntList
));