]> git.proxmox.com Git - mirror_edk2.git/blob - EdkModulePkg/Bus/Pci/Ehci/Dxe/EhciSched.c
3dc1ff74af2cc30f0c4fa6db66a006342e457667
[mirror_edk2.git] / EdkModulePkg / Bus / Pci / Ehci / Dxe / EhciSched.c
1 /*++
2
3 Copyright (c) 2006, 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
8
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.
11
12 Module Name:
13
14 EhciSched.c
15
16 Abstract:
17
18
19 Revision History
20 --*/
21
22 #include "Ehci.h"
23
24 EFI_STATUS
25 InitialPeriodicFrameList (
26 IN USB2_HC_DEV *HcDev,
27 IN UINTN Length
28 )
29 /*++
30
31 Routine Description:
32
33 Initialize Periodic Schedule Frame List
34
35 Arguments:
36
37 HcDev - USB2_HC_DEV
38 Length - Frame List Length
39
40 Returns:
41
42 EFI_SUCCESS Success
43 EFI_DEVICE_ERROR Fail
44
45 --*/
46 {
47 EFI_STATUS Status;
48 VOID *CommonBuffer;
49 EFI_PHYSICAL_ADDRESS FrameBuffer;
50 VOID *Map;
51 UINTN BufferSizeInPages;
52 UINTN BufferSizeInBytes;
53 UINTN FrameIndex;
54 FRAME_LIST_ENTRY *FrameEntryPtr;
55
56 //
57 // The Frame List is a common buffer that will be
58 // accessed by both the cpu and the usb bus master
59 // at the same time.
60 // The Frame List ocupies 4K bytes,
61 // and must be aligned on 4-Kbyte boundaries.
62 //
63 if (EHCI_MAX_FRAME_LIST_LENGTH != Length && IsFrameListProgrammable (HcDev)) {
64 Status = SetFrameListLen (HcDev, Length);
65 if (EFI_ERROR (Status)) {
66 Status = EFI_INVALID_PARAMETER;
67 goto exit;
68 }
69 }
70
71 BufferSizeInBytes = EFI_PAGE_SIZE;
72 BufferSizeInPages = EFI_SIZE_TO_PAGES (BufferSizeInBytes);
73 Status = HcDev->PciIo->AllocateBuffer (
74 HcDev->PciIo,
75 AllocateAnyPages,
76 EfiBootServicesData,
77 BufferSizeInPages,
78 &CommonBuffer,
79 0
80 );
81 if (EFI_ERROR (Status)) {
82 DEBUG ((gEHCErrorLevel, "PciIo->AllocateBuffer Failed\n"));
83 Status = EFI_OUT_OF_RESOURCES;
84 goto exit;
85 }
86
87 Status = HcDev->PciIo->Map (
88 HcDev->PciIo,
89 EfiPciIoOperationBusMasterCommonBuffer,
90 CommonBuffer,
91 &BufferSizeInBytes,
92 &FrameBuffer,
93 &Map
94 );
95 if (EFI_ERROR (Status) || (BufferSizeInBytes != EFI_PAGE_SIZE)) {
96 DEBUG ((gEHCErrorLevel, "PciIo->MapBuffer Failed\n"));
97 Status = EFI_OUT_OF_RESOURCES;
98 goto free_buffer;
99 }
100
101 //
102 // Put high 32bit into CtrlDataStructSeg reg
103 // when 64bit addressing range capability
104 //
105 if (HcDev->Is64BitCapable != 0) {
106 HcDev->High32BitAddr = (UINT32) GET_32B_TO_63B (FrameBuffer);
107
108 Status = SetCtrlDataStructSeg (HcDev);
109 if (EFI_ERROR (Status)) {
110 DEBUG ((gEHCErrorLevel, "SetCtrlDataStructSeg Failed\n"));
111 Status = EFI_DEVICE_ERROR;
112 goto unmap_buffer;
113 }
114 }
115
116 //
117 // Tell the Host Controller where the Frame List lies,
118 // by set the Frame List Base Address Register.
119 //
120 Status = SetFrameListBaseAddr (HcDev, (UINT32) FrameBuffer);
121 if (EFI_ERROR (Status)) {
122 Status = EFI_DEVICE_ERROR;
123 goto unmap_buffer;
124 }
125
126 HcDev->PeriodicFrameListLength = Length;
127 HcDev->PeriodicFrameListBuffer = (VOID *) ((UINTN) FrameBuffer);
128 HcDev->PeriodicFrameListMap = Map;
129
130 //
131 // Init Frame List Array fields
132 //
133 FrameEntryPtr = (FRAME_LIST_ENTRY *) HcDev->PeriodicFrameListBuffer;
134 for (FrameIndex = 0; FrameIndex < HcDev->PeriodicFrameListLength; FrameIndex++) {
135 FrameEntryPtr->LinkPointer = 0;
136 FrameEntryPtr->Rsvd = 0;
137 FrameEntryPtr->SelectType = 0;
138 FrameEntryPtr->LinkTerminate = TRUE;
139 FrameEntryPtr++;
140 }
141
142 goto exit;
143
144 unmap_buffer:
145 HcDev->PciIo->Unmap (HcDev->PciIo, Map);
146 free_buffer:
147 HcDev->PciIo->FreeBuffer (HcDev->PciIo, BufferSizeInPages, CommonBuffer);
148 exit:
149 return Status;
150 }
151
152 VOID
153 DeinitialPeriodicFrameList (
154 IN USB2_HC_DEV *HcDev
155 )
156 /*++
157
158 Routine Description:
159
160 Deinitialize Periodic Schedule Frame List
161
162 Arguments:
163
164 HcDev - USB2_HC_DEV
165
166 Returns:
167
168 VOID
169
170 --*/
171 {
172 HcDev->PciIo->Unmap (HcDev->PciIo, HcDev->PeriodicFrameListMap);
173 HcDev->PciIo->FreeBuffer (HcDev->PciIo, EFI_SIZE_TO_PAGES (EFI_PAGE_SIZE), HcDev->PeriodicFrameListBuffer);
174 return ;
175 }
176
177 EFI_STATUS
178 CreatePollingTimer (
179 IN USB2_HC_DEV *HcDev,
180 IN EFI_EVENT_NOTIFY NotifyFunction
181 )
182 /*++
183
184 Routine Description:
185
186 Create Async Request Polling Timer
187
188 Arguments:
189
190 HcDev - USB2_HC_DEV
191 NotifyFunction - Timer Notify Function
192
193 Returns:
194
195 EFI_SUCCESS Success
196 EFI_DEVICE_ERROR Fail
197
198 --*/
199 {
200 return gBS->CreateEvent (
201 EFI_EVENT_TIMER | EFI_EVENT_NOTIFY_SIGNAL,
202 EFI_TPL_NOTIFY,
203 NotifyFunction,
204 HcDev,
205 &HcDev->AsyncRequestEvent
206 );
207 }
208
209 EFI_STATUS
210 DestoryPollingTimer (
211 IN USB2_HC_DEV *HcDev
212 )
213 /*++
214
215 Routine Description:
216
217 Destory Async Request Polling Timer
218
219 Arguments:
220
221 HcDev - USB2_HC_DEV
222
223 Returns:
224
225 EFI_SUCCESS Success
226 EFI_DEVICE_ERROR Fail
227
228 --*/
229 {
230 return gBS->CloseEvent (HcDev->AsyncRequestEvent);
231 }
232
233 EFI_STATUS
234 StartPollingTimer (
235 IN USB2_HC_DEV *HcDev
236 )
237 /*++
238
239 Routine Description:
240
241 Start Async Request Polling Timer
242
243 Arguments:
244
245 HcDev - USB2_HC_DEV
246
247 Returns:
248
249 EFI_SUCCESS Success
250 EFI_DEVICE_ERROR Fail
251
252 --*/
253 {
254 return gBS->SetTimer (
255 HcDev->AsyncRequestEvent,
256 TimerPeriodic,
257 EHCI_ASYNC_REQUEST_POLLING_TIME
258 );
259 }
260
261 EFI_STATUS
262 StopPollingTimer (
263 IN USB2_HC_DEV *HcDev
264 )
265 /*++
266
267 Routine Description:
268
269 Stop Async Request Polling Timer
270
271 Arguments:
272
273 HcDev - USB2_HC_DEV
274
275 Returns:
276
277 EFI_SUCCESS Success
278 EFI_DEVICE_ERROR Fail
279
280 --*/
281 {
282 return gBS->SetTimer (
283 HcDev->AsyncRequestEvent,
284 TimerCancel,
285 EHCI_ASYNC_REQUEST_POLLING_TIME
286 );
287 }
288
289 EFI_STATUS
290 CreateQh (
291 IN USB2_HC_DEV *HcDev,
292 IN UINT8 DeviceAddr,
293 IN UINT8 Endpoint,
294 IN UINT8 DeviceSpeed,
295 IN UINTN MaxPacketLen,
296 OUT EHCI_QH_ENTITY **QhPtrPtr
297 )
298 /*++
299
300 Routine Description:
301
302 Create Qh Structure and Pre-Initialize
303
304 Arguments:
305
306 HcDev - USB2_HC_DEV
307 DeviceAddr - Address of Device
308 Endpoint - Endpoint Number
309 DeviceSpeed - Device Speed
310 MaxPacketLen - Max Length of one Packet
311 QhPtrPtr - A pointer of pointer to Qh for return
312
313 Returns:
314
315 EFI_SUCCESS Success
316 EFI_OUT_OF_RESOURCES Cannot allocate resources
317
318 --*/
319 {
320 EFI_STATUS Status;
321 EHCI_QH_HW *QhHwPtr;
322
323 ASSERT (HcDev);
324 ASSERT (QhPtrPtr);
325
326 *QhPtrPtr = NULL;
327
328 //
329 // Allocate memory for Qh structure
330 //
331 Status = EhciAllocatePool (
332 HcDev,
333 (UINT8 **) QhPtrPtr,
334 sizeof (EHCI_QH_ENTITY)
335 );
336 if (EFI_ERROR (Status)) {
337 Status = EFI_OUT_OF_RESOURCES;
338 goto exit;
339 }
340 //
341 // Init fields in Qh
342 //
343 gBS->SetMem (*QhPtrPtr, sizeof (EHCI_QH_ENTITY), 0);
344
345 //
346 // Software field
347 //
348 (*QhPtrPtr)->Next = NULL;
349 (*QhPtrPtr)->Prev = NULL;
350 (*QhPtrPtr)->FirstQtdPtr = NULL;
351 (*QhPtrPtr)->AltQtdPtr = NULL;
352 (*QhPtrPtr)->LastQtdPtr = NULL;
353
354 //
355 // Hardware field
356 //
357 QhHwPtr = &((*QhPtrPtr)->Qh);
358 QhHwPtr->QhHorizontalPointer = 0;
359 QhHwPtr->SelectType = 0;
360 QhHwPtr->MaxPacketLen = (UINT32) MaxPacketLen;
361 QhHwPtr->EndpointSpeed = (DeviceSpeed & 0x3);
362 QhHwPtr->EndpointNum = (Endpoint & 0x0f);
363 QhHwPtr->DeviceAddr = (DeviceAddr & 0x7f);
364 QhHwPtr->Multiplier = HIGH_BANDWIDTH_PIPE_MULTIPLIER;
365 QhHwPtr->Rsvd1 = 0;
366 QhHwPtr->Rsvd2 = 0;
367 QhHwPtr->Rsvd3 = 0;
368 QhHwPtr->Rsvd4 = 0;
369 QhHwPtr->Rsvd5 = 0;
370 QhHwPtr->Rsvd6 = 0;
371
372 exit:
373 return Status;
374 }
375
376 VOID
377 DestoryQh (
378 IN USB2_HC_DEV *HcDev,
379 IN EHCI_QH_ENTITY *QhPtr
380 )
381 /*++
382
383 Routine Description:
384
385 Destory Qh Structure
386
387 Arguments:
388
389 HcDev - USB2_HC_DEV
390 QhPtr - A pointer to Qh
391
392 Returns:
393
394 EFI_SUCCESS Success
395 EFI_DEVICE_ERROR Fail
396
397 --*/
398 {
399 ASSERT (HcDev);
400 ASSERT (QhPtr);
401
402 EhciFreePool (HcDev, (UINT8 *) QhPtr, sizeof (EHCI_QH_ENTITY));
403 return ;
404 }
405
406 EFI_STATUS
407 CreateControlQh (
408 IN USB2_HC_DEV *HcDev,
409 IN UINT8 DeviceAddr,
410 IN UINT8 DeviceSpeed,
411 IN UINTN MaxPacketLen,
412 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
413 OUT EHCI_QH_ENTITY **QhPtrPtr
414 )
415 /*++
416
417 Routine Description:
418
419 Create Qh for Control Transfer
420
421 Arguments:
422
423 HcDev - USB2_HC_DEV
424 DeviceAddr - Address of Device
425 DeviceSpeed - Device Speed
426 MaxPacketLen - Max Length of one Packet
427 Translator - Translator Transaction for SplitX
428 QhPtrPtr - A pointer of pointer to Qh for return
429
430 Returns:
431
432 EFI_SUCCESS Success
433 EFI_OUT_OF_RESOURCES Cannot allocate resources
434
435 --*/
436 {
437 EFI_STATUS Status;
438
439 //
440 // Create and init Control Qh
441 //
442 Status = CreateQh (
443 HcDev,
444 DeviceAddr,
445 0,
446 DeviceSpeed,
447 MaxPacketLen,
448 QhPtrPtr
449 );
450 if (EFI_ERROR (Status)) {
451 Status = EFI_OUT_OF_RESOURCES;
452 goto exit;
453 }
454 //
455 // Software field
456 //
457 (*QhPtrPtr)->Next = (*QhPtrPtr);
458 (*QhPtrPtr)->Prev = (*QhPtrPtr);
459 (*QhPtrPtr)->TransferType = CONTROL_TRANSFER;
460
461 //
462 // Hardware field
463 //
464 // Control Transfer use DataToggleControl
465 //
466 (*QhPtrPtr)->Qh.DataToggleControl = TRUE;
467 (*QhPtrPtr)->Qh.QhHorizontalPointer = (UINT32) (GET_0B_TO_31B (&((*QhPtrPtr)->Qh)) >> 5);
468 (*QhPtrPtr)->Qh.SelectType = QH_SELECT_TYPE;
469 (*QhPtrPtr)->Qh.QhTerminate = FALSE;
470 (*QhPtrPtr)->Qh.ControlEndpointFlag = TRUE;
471 (*QhPtrPtr)->Qh.NakCountReload = NAK_COUNT_RELOAD;
472 if (NULL != Translator) {
473 (*QhPtrPtr)->Qh.PortNum = Translator->TranslatorPortNumber;
474 (*QhPtrPtr)->Qh.HubAddr = Translator->TranslatorHubAddress;
475 (*QhPtrPtr)->Qh.Status |= QTD_STATUS_DO_START_SPLIT;
476 }
477
478 exit:
479 return Status;
480 }
481
482 EFI_STATUS
483 CreateBulkQh (
484 IN USB2_HC_DEV *HcDev,
485 IN UINT8 DeviceAddr,
486 IN UINT8 EndPointAddr,
487 IN UINT8 DeviceSpeed,
488 IN UINT8 DataToggle,
489 IN UINTN MaxPacketLen,
490 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
491 OUT EHCI_QH_ENTITY **QhPtrPtr
492 )
493 /*++
494
495 Routine Description:
496
497 Create Qh for Bulk Transfer
498
499 Arguments:
500
501 HcDev - USB2_HC_DEV
502 DeviceAddr - Address of Device
503 EndPointAddr - Address of Endpoint
504 DeviceSpeed - Device Speed
505 MaxPacketLen - Max Length of one Packet
506 Translator - Translator Transaction for SplitX
507 QhPtrPtr - A pointer of pointer to Qh for return
508
509 Returns:
510
511 EFI_SUCCESS Success
512 EFI_OUT_OF_RESOURCES Cannot allocate resources
513
514 --*/
515 {
516 EFI_STATUS Status;
517
518 //
519 // Create and init Bulk Qh
520 //
521 Status = CreateQh (
522 HcDev,
523 DeviceAddr,
524 EndPointAddr,
525 DeviceSpeed,
526 MaxPacketLen,
527 QhPtrPtr
528 );
529 if (EFI_ERROR (Status)) {
530 Status = EFI_OUT_OF_RESOURCES;
531 goto exit;
532 }
533
534 //
535 // Software fields
536 //
537 (*QhPtrPtr)->Next = (*QhPtrPtr);
538 (*QhPtrPtr)->Prev = (*QhPtrPtr);
539 (*QhPtrPtr)->TransferType = BULK_TRANSFER;
540
541 //
542 // Hardware fields
543 //
544 // BulkTransfer don't use DataToggleControl
545 //
546 (*QhPtrPtr)->Qh.DataToggleControl = FALSE;
547 (*QhPtrPtr)->Qh.QhHorizontalPointer = (UINT32) (GET_0B_TO_31B (&((*QhPtrPtr)->Qh)) >> 5);
548 (*QhPtrPtr)->Qh.SelectType = QH_SELECT_TYPE;
549 (*QhPtrPtr)->Qh.QhTerminate = FALSE;
550 (*QhPtrPtr)->Qh.NakCountReload = NAK_COUNT_RELOAD;
551 (*QhPtrPtr)->Qh.DataToggle = DataToggle;
552 if (NULL != Translator) {
553 (*QhPtrPtr)->Qh.PortNum = Translator->TranslatorPortNumber;
554 (*QhPtrPtr)->Qh.HubAddr = Translator->TranslatorHubAddress;
555 (*QhPtrPtr)->Qh.Status |= QTD_STATUS_DO_START_SPLIT;
556 }
557
558 exit:
559 return Status;
560 }
561
562 EFI_STATUS
563 CreateInterruptQh (
564 IN USB2_HC_DEV *HcDev,
565 IN UINT8 DeviceAddr,
566 IN UINT8 EndPointAddr,
567 IN UINT8 DeviceSpeed,
568 IN UINT8 DataToggle,
569 IN UINTN MaxPacketLen,
570 IN UINTN Interval,
571 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
572 OUT EHCI_QH_ENTITY **QhPtrPtr
573 )
574 /*++
575
576 Routine Description:
577
578 Create Qh for Control Transfer
579
580 Arguments:
581
582 HcDev - USB2_HC_DEV
583 DeviceAddr - Address of Device
584 EndPointAddr - Address of Endpoint
585 DeviceSpeed - Device Speed
586 MaxPacketLen - Max Length of one Packet
587 Interval - value of interval
588 Translator - Translator Transaction for SplitX
589 QhPtrPtr - A pointer of pointer to Qh for return
590
591 Returns:
592
593 EFI_SUCCESS Success
594 EFI_OUT_OF_RESOURCES Cannot allocate resources
595
596 --*/
597 {
598 EFI_STATUS Status;
599
600 //
601 // Create and init InterruptQh
602 //
603 Status = CreateQh (
604 HcDev,
605 DeviceAddr,
606 EndPointAddr,
607 DeviceSpeed,
608 MaxPacketLen,
609 QhPtrPtr
610 );
611 if (EFI_ERROR (Status)) {
612 Status = EFI_OUT_OF_RESOURCES;
613 goto exit;
614 }
615
616 //
617 // Software fields
618 //
619 if (Interval == 0) {
620 (*QhPtrPtr)->TransferType = SYNC_INTERRUPT_TRANSFER;
621 } else {
622 (*QhPtrPtr)->TransferType = ASYNC_INTERRUPT_TRANSFER;
623 }
624 (*QhPtrPtr)->Interval = GetApproxiOfInterval (Interval);
625
626 //
627 // Hardware fields
628 //
629 // InterruptTranfer don't use DataToggleControl
630 //
631 (*QhPtrPtr)->Qh.DataToggleControl = FALSE;
632 (*QhPtrPtr)->Qh.QhHorizontalPointer = 0;
633 (*QhPtrPtr)->Qh.QhTerminate = TRUE;
634 (*QhPtrPtr)->Qh.NakCountReload = 0;
635 (*QhPtrPtr)->Qh.InerruptScheduleMask = MICRO_FRAME_0_CHANNEL;
636 (*QhPtrPtr)->Qh.SplitComletionMask = (MICRO_FRAME_2_CHANNEL | MICRO_FRAME_3_CHANNEL | MICRO_FRAME_4_CHANNEL);
637 (*QhPtrPtr)->Qh.DataToggle = DataToggle;
638 if (NULL != Translator) {
639 (*QhPtrPtr)->Qh.PortNum = Translator->TranslatorPortNumber;
640 (*QhPtrPtr)->Qh.HubAddr = Translator->TranslatorHubAddress;
641 (*QhPtrPtr)->Qh.Status |= QTD_STATUS_DO_START_SPLIT;
642 }
643
644 exit:
645 return Status;
646 }
647
648 EFI_STATUS
649 CreateQtd (
650 IN USB2_HC_DEV *HcDev,
651 IN UINT8 *DataPtr,
652 IN UINTN DataLen,
653 IN UINT8 PktId,
654 IN UINT8 Toggle,
655 IN UINT8 QtdStatus,
656 OUT EHCI_QTD_ENTITY **QtdPtrPtr
657 )
658 /*++
659
660 Routine Description:
661
662 Create Qtd Structure and Pre-Initialize it
663
664 Arguments:
665
666 HcDev - USB2_HC_DEV
667 DataPtr - A pointer to user data buffer to transfer
668 DataLen - Length of user data to transfer
669 PktId - Packet Identification of this Qtd
670 Toggle - Data Toggle of this Qtd
671 QtdStatus - Default value of status of this Qtd
672 QtdPtrPtr - A pointer of pointer to Qtd for return
673
674 Returns:
675
676 EFI_SUCCESS Success
677 EFI_OUT_OF_RESOURCES Cannot allocate resources
678
679 --*/
680 {
681 EFI_STATUS Status;
682 EHCI_QTD_HW *QtdHwPtr;
683
684 ASSERT (HcDev);
685 ASSERT (QtdPtrPtr);
686
687 //
688 // Create memory for Qtd structure
689 //
690 Status = EhciAllocatePool (
691 HcDev,
692 (UINT8 **) QtdPtrPtr,
693 sizeof (EHCI_QTD_ENTITY)
694 );
695 if (EFI_ERROR (Status)) {
696 Status = EFI_OUT_OF_RESOURCES;
697 goto exit;
698 }
699 //
700 // Init fields in Qtd
701 //
702 gBS->SetMem (*QtdPtrPtr, sizeof (EHCI_QTD_ENTITY), 0);
703
704 //
705 // Software field
706 //
707 (*QtdPtrPtr)->TotalBytes = (UINT32) DataLen;
708 (*QtdPtrPtr)->StaticTotalBytes = (UINT32) DataLen;
709 (*QtdPtrPtr)->Prev = NULL;
710 (*QtdPtrPtr)->Next = NULL;
711
712 //
713 // Hardware field
714 //
715 QtdHwPtr = &((*QtdPtrPtr)->Qtd);
716 QtdHwPtr->NextQtdPointer = 0;
717 QtdHwPtr->NextQtdTerminate = TRUE;
718 QtdHwPtr->AltNextQtdPointer = 0;
719 QtdHwPtr->AltNextQtdTerminate = TRUE;
720 QtdHwPtr->DataToggle = Toggle;
721 QtdHwPtr->TotalBytes = (UINT32) DataLen;
722 QtdHwPtr->CurrentPage = 0;
723 QtdHwPtr->ErrorCount = QTD_ERROR_COUNTER;
724 QtdHwPtr->Status = QtdStatus;
725 QtdHwPtr->Rsvd1 = 0;
726 QtdHwPtr->Rsvd2 = 0;
727 QtdHwPtr->Rsvd3 = 0;
728 QtdHwPtr->Rsvd4 = 0;
729 QtdHwPtr->Rsvd5 = 0;
730 QtdHwPtr->Rsvd6 = 0;
731
732 //
733 // Set PacketID [Setup/Data/Status]
734 //
735 switch (PktId) {
736 case SETUP_PACKET_ID:
737 QtdHwPtr->PidCode = SETUP_PACKET_PID_CODE;
738 break;
739
740 case INPUT_PACKET_ID:
741 QtdHwPtr->PidCode = INPUT_PACKET_PID_CODE;
742 break;
743
744 case OUTPUT_PACKET_ID:
745 QtdHwPtr->PidCode = OUTPUT_PACKET_PID_CODE;
746 break;
747
748 default:
749 Status = EFI_INVALID_PARAMETER;
750 goto exit;
751 }
752
753 //
754 // Set Data Buffer Pointers
755 //
756 if (NULL != DataPtr) {
757 SetQtdBufferPointer (
758 QtdHwPtr,
759 DataPtr,
760 DataLen
761 );
762 (*QtdPtrPtr)->StaticCurrentOffset = QtdHwPtr->CurrentOffset;
763 }
764
765 exit:
766 return Status;
767 }
768
769 EFI_STATUS
770 CreateSetupQtd (
771 IN USB2_HC_DEV *HcDev,
772 IN UINT8 *DevReqPtr,
773 OUT EHCI_QTD_ENTITY **QtdPtrPtr
774 )
775 /*++
776
777 Routine Description:
778
779 Create Qtd Structure for Setup
780
781 Arguments:
782
783 HcDev - USB2_HC_DEV
784 DevReqPtr - A pointer to Device Request Data
785 QtdPtrPtr - A pointer of pointer to Qtd for return
786
787 Returns:
788
789 EFI_SUCCESS Success
790 EFI_OUT_OF_RESOURCES Cannot allocate resources
791
792 --*/
793 {
794 return CreateQtd (
795 HcDev,
796 DevReqPtr,
797 sizeof (EFI_USB_DEVICE_REQUEST),
798 SETUP_PACKET_ID,
799 DATA0,
800 QTD_STATUS_ACTIVE,
801 QtdPtrPtr
802 );
803 }
804
805 EFI_STATUS
806 CreateDataQtd (
807 IN USB2_HC_DEV *HcDev,
808 IN UINT8 *DataPtr,
809 IN UINTN DataLen,
810 IN UINT8 PktId,
811 IN UINT8 Toggle,
812 OUT EHCI_QTD_ENTITY **QtdPtrPtr
813 )
814 /*++
815
816 Routine Description:
817
818 Create Qtd Structure for data
819
820 Arguments:
821
822 HcDev - USB2_HC_DEV
823 DataPtr - A pointer to user data buffer to transfer
824 DataLen - Length of user data to transfer
825 PktId - Packet Identification of this Qtd
826 Toggle - Data Toggle of this Qtd
827 QtdPtrPtr - A pointer of pointer to Qtd for return
828
829 Returns:
830
831 EFI_SUCCESS Success
832 EFI_OUT_OF_RESOURCES Cannot allocate resources
833
834 --*/
835 {
836 return CreateQtd (
837 HcDev,
838 DataPtr,
839 DataLen,
840 PktId,
841 Toggle,
842 QTD_STATUS_ACTIVE,
843 QtdPtrPtr
844 );
845 }
846
847 EFI_STATUS
848 CreateAltQtd (
849 IN USB2_HC_DEV *HcDev,
850 IN UINT8 PktId,
851 OUT EHCI_QTD_ENTITY **QtdPtrPtr
852 )
853 /*++
854
855 Routine Description:
856
857 Create Qtd Structure for Alternative
858
859 Arguments:
860
861 HcDev - USB2_HC_DEV
862 PktId - Packet Identification of this Qtd
863 QtdPtrPtr - A pointer of pointer to Qtd for return
864
865 Returns:
866
867 EFI_SUCCESS Success
868 EFI_OUT_OF_RESOURCES Cannot allocate resources
869
870 --*/
871 {
872 return CreateQtd (
873 HcDev,
874 NULL,
875 0,
876 PktId,
877 0,
878 QTD_STATUS_ACTIVE,
879 QtdPtrPtr
880 );
881 }
882
883 EFI_STATUS
884 CreateStatusQtd (
885 IN USB2_HC_DEV *HcDev,
886 IN UINT8 PktId,
887 OUT EHCI_QTD_ENTITY **QtdPtrPtr
888 )
889 /*++
890
891 Routine Description:
892
893 Create Qtd Structure for status
894
895 Arguments:
896
897 HcDev - USB2_HC_DEV
898 PktId - Packet Identification of this Qtd
899 QtdPtrPtr - A pointer of pointer to Qtd for return
900
901 Returns:
902
903 EFI_SUCCESS Success
904 EFI_OUT_OF_RESOURCES Cannot allocate resources
905
906 --*/
907 {
908 return CreateQtd (
909 HcDev,
910 NULL,
911 0,
912 PktId,
913 DATA1,
914 QTD_STATUS_ACTIVE,
915 QtdPtrPtr
916 );
917 }
918
919 EFI_STATUS
920 CreateControlQtds (
921 IN USB2_HC_DEV *HcDev,
922 IN UINT8 DataPktId,
923 IN UINT8 *RequestCursor,
924 IN UINT8 *DataCursor,
925 IN UINTN DataLen,
926 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
927 OUT EHCI_QTD_ENTITY **ControlQtdsHead
928 )
929 /*++
930
931 Routine Description:
932
933 Create Qtds list for Control Transfer
934
935 Arguments:
936
937 HcDev - USB2_HC_DEV
938 DataPktId - Packet Identification of Data Qtds
939 RequestCursor - A pointer to request structure buffer to transfer
940 DataCursor - A pointer to user data buffer to transfer
941 DataLen - Length of user data to transfer
942 ControlQtdsHead - A pointer of pointer to first Qtd for control tranfer for return
943
944 Returns:
945
946 EFI_SUCCESS Success
947 EFI_OUT_OF_RESOURCES Cannot allocate resources
948
949 --*/
950 {
951 EFI_STATUS Status;
952 EHCI_QTD_ENTITY *QtdPtr;
953 EHCI_QTD_ENTITY *PreQtdPtr;
954 EHCI_QTD_ENTITY *SetupQtdPtr;
955 EHCI_QTD_ENTITY *FirstDataQtdPtr;
956 EHCI_QTD_ENTITY *LastDataQtdPtr;
957 EHCI_QTD_ENTITY *StatusQtdPtr;
958 UINT8 DataToggle;
959 UINT8 StatusPktId;
960 UINTN CapacityOfQtd;
961 UINTN SizePerQtd;
962 UINTN DataCount;
963 UINTN Xnum;
964
965 QtdPtr = NULL;
966 PreQtdPtr = NULL;
967 SetupQtdPtr = NULL;
968 FirstDataQtdPtr = NULL;
969 LastDataQtdPtr = NULL;
970 StatusQtdPtr = NULL;
971 CapacityOfQtd = 0;
972
973 //
974 // Setup Stage of Control Transfer
975 //
976 Status = CreateSetupQtd (
977 HcDev,
978 RequestCursor,
979 &SetupQtdPtr
980 );
981 if (EFI_ERROR (Status)) {
982 Status = EFI_OUT_OF_RESOURCES;
983 goto exit;
984 }
985
986 //
987 // Data Stage of Control Transfer
988 //
989 DataToggle = 1;
990 DataCount = DataLen;
991
992 //
993 // Create Qtd structure and link together
994 //
995 while (DataCount > 0) {
996 //
997 // PktSize is the data load size that each Qtd.
998 //
999 CapacityOfQtd = GetCapacityOfQtd (DataCursor);
1000 SizePerQtd = DataCount;
1001 if (DataCount > CapacityOfQtd) {
1002 SizePerQtd = CapacityOfQtd;
1003 }
1004
1005 Status = CreateDataQtd (
1006 HcDev,
1007 DataCursor,
1008 SizePerQtd,
1009 DataPktId,
1010 DataToggle,
1011 &QtdPtr
1012 );
1013 if (EFI_ERROR (Status)) {
1014 Status = EFI_OUT_OF_RESOURCES;
1015 if (NULL == FirstDataQtdPtr) {
1016 goto destory_setup_qtd;
1017 } else {
1018 goto destory_qtds;
1019 }
1020 }
1021
1022 if (NULL == FirstDataQtdPtr) {
1023 FirstDataQtdPtr = QtdPtr;
1024 } else {
1025 LinkQtdToQtd (PreQtdPtr, QtdPtr);
1026 }
1027
1028 //
1029 // Reverse Data Toggle or not determined by parity of transactions of one qtd
1030 //
1031 Xnum = Translator ? GetNumberOfTransaction (SizePerQtd, EHCI_BLOCK_SIZE_WITH_TT) : GetNumberOfTransaction (SizePerQtd, EHCI_BLOCK_SIZE);
1032 if (Xnum % 2 != 0) {
1033 DataToggle ^= 1;
1034 }
1035
1036 PreQtdPtr = QtdPtr;
1037 DataCursor += SizePerQtd;
1038 DataCount -= SizePerQtd;
1039 }
1040
1041 LastDataQtdPtr = QtdPtr;
1042
1043 //
1044 // Status Stage of Control Transfer
1045 //
1046 if (OUTPUT_PACKET_ID == DataPktId) {
1047 StatusPktId = INPUT_PACKET_ID;
1048 } else {
1049 StatusPktId = OUTPUT_PACKET_ID;
1050 }
1051
1052 Status = CreateStatusQtd (
1053 HcDev,
1054 StatusPktId,
1055 &StatusQtdPtr
1056 );
1057 if (EFI_ERROR (Status)) {
1058 Status = EFI_OUT_OF_RESOURCES;
1059 goto destory_qtds;
1060 }
1061
1062 //
1063 // Link setup Qtd -> data Qtds -> status Qtd
1064 //
1065 if (FirstDataQtdPtr != NULL) {
1066 LinkQtdToQtd (SetupQtdPtr, FirstDataQtdPtr);
1067 LinkQtdToQtd (LastDataQtdPtr, StatusQtdPtr);
1068 } else {
1069 LinkQtdToQtd (SetupQtdPtr, StatusQtdPtr);
1070 }
1071
1072 *ControlQtdsHead = SetupQtdPtr;
1073
1074 goto exit;
1075
1076 destory_qtds:
1077 DestoryQtds (HcDev, FirstDataQtdPtr);
1078 destory_setup_qtd:
1079 DestoryQtds (HcDev, SetupQtdPtr);
1080 exit:
1081 return Status;
1082 }
1083
1084 EFI_STATUS
1085 CreateBulkOrInterruptQtds (
1086 IN USB2_HC_DEV *HcDev,
1087 IN UINT8 PktId,
1088 IN UINT8 *DataCursor,
1089 IN UINTN DataLen,
1090 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
1091 OUT EHCI_QTD_ENTITY **QtdsHead
1092 )
1093 /*++
1094
1095 Routine Description:
1096
1097 Create Qtds list for Bulk or Interrupt Transfer
1098
1099 Arguments:
1100
1101 HcDev - USB2_HC_DEV
1102 PktId - Packet Identification of Qtds
1103 DataCursor - A pointer to user data buffer to transfer
1104 DataLen - Length of user data to transfer
1105 DataToggle - Data Toggle to start
1106 Translator - Translator Transaction for SplitX
1107 QtdsHead - A pointer of pointer to first Qtd for control tranfer for return
1108
1109 Returns:
1110
1111 EFI_SUCCESS Success
1112 EFI_OUT_OF_RESOURCES Cannot allocate resources
1113
1114 --*/
1115 {
1116 EFI_STATUS Status;
1117 EHCI_QTD_ENTITY *QtdPtr;
1118 EHCI_QTD_ENTITY *PreQtdPtr;
1119 EHCI_QTD_ENTITY *FirstQtdPtr;
1120 EHCI_QTD_ENTITY *AltQtdPtr;
1121 UINTN DataCount;
1122 UINTN CapacityOfQtd;
1123 UINTN SizePerQtd;
1124
1125 Status = EFI_SUCCESS;
1126 QtdPtr = NULL;
1127 PreQtdPtr = NULL;
1128 FirstQtdPtr = NULL;
1129 AltQtdPtr = NULL;
1130 CapacityOfQtd = 0;
1131
1132 DataCount = DataLen;
1133 while (DataCount > 0) {
1134
1135 CapacityOfQtd = GetCapacityOfQtd (DataCursor);
1136 SizePerQtd = DataCount;
1137 if (DataCount > CapacityOfQtd) {
1138 SizePerQtd = CapacityOfQtd;
1139 }
1140
1141 Status = CreateDataQtd (
1142 HcDev,
1143 DataCursor,
1144 SizePerQtd,
1145 PktId,
1146 0,
1147 &QtdPtr
1148 );
1149 if (EFI_ERROR (Status)) {
1150 Status = EFI_OUT_OF_RESOURCES;
1151 if (NULL == FirstQtdPtr) {
1152 goto exit;
1153 } else {
1154 goto destory_qtds;
1155 }
1156 }
1157
1158 if (NULL == FirstQtdPtr) {
1159 FirstQtdPtr = QtdPtr;
1160 } else {
1161 LinkQtdToQtd (PreQtdPtr, QtdPtr);
1162 }
1163
1164 PreQtdPtr = QtdPtr;
1165 DataCursor += SizePerQtd;
1166 DataCount -= SizePerQtd;
1167 }
1168
1169 //
1170 // Set Alternate Qtd
1171 //
1172 if (INPUT_PACKET_ID == PktId && 1 < GetNumberOfQtd (FirstQtdPtr)) {
1173 Status = CreateAltQtd (
1174 HcDev,
1175 PktId,
1176 &AltQtdPtr
1177 );
1178 if (EFI_ERROR (Status)) {
1179 Status = EFI_OUT_OF_RESOURCES;
1180 goto destory_qtds;
1181 }
1182
1183 LinkQtdsToAltQtd (FirstQtdPtr, AltQtdPtr);
1184 }
1185
1186 *QtdsHead = FirstQtdPtr;
1187 goto exit;
1188
1189 destory_qtds:
1190 DestoryQtds (HcDev, FirstQtdPtr);
1191 exit:
1192 return Status;
1193 }
1194
1195 VOID
1196 DestoryQtds (
1197 IN USB2_HC_DEV *HcDev,
1198 IN EHCI_QTD_ENTITY *FirstQtdPtr
1199 )
1200 /*++
1201
1202 Routine Description:
1203
1204 Destory all Qtds in the list
1205
1206 Arguments:
1207
1208 HcDev - USB2_HC_DEV
1209 FirstQtdPtr - A pointer to first Qtd in the list
1210
1211 Returns:
1212
1213 VOID
1214
1215 --*/
1216 {
1217 EHCI_QTD_ENTITY *PrevQtd;
1218 EHCI_QTD_ENTITY *NextQtd;
1219
1220 if (!FirstQtdPtr) {
1221 goto exit;
1222 }
1223
1224 PrevQtd = FirstQtdPtr;
1225
1226 //
1227 // Delete all the Qtds.
1228 //
1229 do {
1230 NextQtd = PrevQtd->Next;
1231 EhciFreePool (HcDev, (UINT8 *) PrevQtd, sizeof (EHCI_QTD_ENTITY));
1232 PrevQtd = NextQtd;
1233 } while (NULL != PrevQtd);
1234
1235 exit:
1236 return ;
1237 }
1238
1239 UINTN
1240 GetNumberOfQtd (
1241 IN EHCI_QTD_ENTITY *FirstQtdPtr
1242 )
1243 /*++
1244
1245 Routine Description:
1246
1247 Number of Qtds in the list
1248
1249 Arguments:
1250
1251 FirstQtdPtr - A pointer to first Qtd in the list
1252
1253 Returns:
1254
1255 Number of Qtds in the list
1256
1257 --*/
1258 {
1259 UINTN Count;
1260 EHCI_QTD_ENTITY *QtdPtr;
1261 Count = 0;
1262 QtdPtr = FirstQtdPtr;
1263
1264 ;
1265
1266 while (NULL != QtdPtr) {
1267 Count++;
1268 QtdPtr = QtdPtr->Next;
1269 }
1270
1271 return Count;
1272 }
1273
1274 UINTN
1275 GetNumberOfTransaction (
1276 IN UINTN SizeOfData,
1277 IN UINTN SizeOfTransaction
1278 )
1279 /*++
1280
1281 Routine Description:
1282
1283 Number of Transactions in one Qtd
1284
1285 Arguments:
1286
1287 SizeOfData - Size of one Qtd
1288 SizeOfTransaction - Size of one Transaction
1289
1290 Returns:
1291
1292 Number of Transactions in this Qtd
1293
1294 --*/
1295 {
1296
1297 return ((SizeOfData & (SizeOfTransaction - 1)) ? SizeOfData / SizeOfTransaction + 1 : SizeOfData / SizeOfTransaction);
1298
1299 }
1300
1301 UINTN
1302 GetCapacityOfQtd (
1303 IN UINT8 *BufferCursor
1304 )
1305 /*++
1306
1307 Routine Description:
1308
1309 Get Size of First Qtd
1310
1311 Arguments:
1312
1313 BufferCursor - BufferCursor of the Qtd
1314
1315 Returns:
1316
1317 Size of First Qtd
1318
1319 --*/
1320 {
1321
1322 return (EHCI_MAX_QTD_CAPACITY - (EHCI_BLOCK_SIZE * GetNumberOfTransaction (EFI_PAGE_MASK & GET_0B_TO_31B (BufferCursor), EHCI_BLOCK_SIZE)));
1323
1324 }
1325
1326 UINTN
1327 GetApproxiOfInterval (
1328 IN UINTN Interval
1329 )
1330 /*++
1331
1332 Routine Description:
1333
1334 Get the approximate value in the 2 index sequence
1335
1336 Arguments:
1337
1338 Interval - the value of interval
1339
1340 Returns:
1341
1342 approximate value of interval in the 2 index sequence
1343
1344 --*/
1345 {
1346 UINTN Orignate;
1347 UINTN Approxi;
1348
1349 Orignate = Interval;
1350 Approxi = 1;
1351
1352 while (Orignate != 1 && Orignate != 0) {
1353 Orignate = Orignate >> 1;
1354 Approxi = Approxi << 1;
1355 }
1356
1357 if (Interval & (Approxi >> 1)) {
1358 Approxi = Approxi << 1;
1359 }
1360
1361 return Approxi;
1362 }
1363
1364 EHCI_QTD_HW *
1365 GetQtdAlternateNextPointer (
1366 IN EHCI_QTD_HW *HwQtdPtr
1367 )
1368 /*++
1369
1370 Routine Description:
1371
1372 Get Qtd alternate next pointer field
1373
1374 Arguments:
1375
1376 HwQtdPtr - A pointer to hardware Qtd structure
1377
1378 Returns:
1379
1380 A pointer to hardware alternate Qtd
1381
1382 --*/
1383 {
1384 EHCI_QTD_HW *Value;
1385
1386 Value = NULL;
1387
1388 if (!HwQtdPtr->AltNextQtdTerminate) {
1389 Value = (EHCI_QTD_HW *) GET_0B_TO_31B (HwQtdPtr->AltNextQtdPointer << 5);
1390 }
1391
1392 return Value;
1393 }
1394
1395 EHCI_QTD_HW *
1396 GetQtdNextPointer (
1397 IN EHCI_QTD_HW *HwQtdPtr
1398 )
1399 /*++
1400
1401 Routine Description:
1402
1403 Get Qtd next pointer field
1404
1405 Arguments:
1406
1407 HwQtdPtr - A pointer to hardware Qtd structure
1408
1409 Returns:
1410
1411 A pointer to next hardware Qtd structure
1412
1413 --*/
1414 {
1415 EHCI_QTD_HW *Value;
1416
1417 Value = NULL;
1418
1419 if (!HwQtdPtr->NextQtdTerminate) {
1420 Value = (EHCI_QTD_HW *) GET_0B_TO_31B (HwQtdPtr->NextQtdPointer << 5);
1421 }
1422
1423 return Value;
1424 }
1425
1426 VOID LinkQtdToQtd (
1427 IN EHCI_QTD_ENTITY * PreQtdPtr,
1428 IN EHCI_QTD_ENTITY * QtdPtr
1429 )
1430 /*++
1431
1432 Routine Description:
1433
1434 Link Qtds together
1435
1436 Arguments:
1437
1438 PreQtdPtr - A pointer to pre Qtd
1439 QtdPtr - A pointer to next Qtd
1440
1441 Returns:
1442
1443 VOID
1444
1445 --*/
1446 {
1447 EHCI_QTD_HW *QtdHwPtr;
1448
1449 ASSERT(PreQtdPtr);
1450 ASSERT(QtdPtr);
1451
1452 //
1453 // Software link
1454 //
1455 PreQtdPtr->Next = QtdPtr;
1456 QtdPtr->Prev = PreQtdPtr;
1457
1458 //
1459 // Hardware link
1460 //
1461 QtdHwPtr = &(QtdPtr->Qtd);
1462 PreQtdPtr->Qtd.NextQtdPointer = (UINT32) (GET_0B_TO_31B(QtdHwPtr) >> 5);
1463 PreQtdPtr->Qtd.NextQtdTerminate = FALSE;
1464
1465 return ;
1466 }
1467
1468
1469 VOID LinkQtdsToAltQtd (
1470 IN EHCI_QTD_ENTITY * FirstQtdPtr,
1471 IN EHCI_QTD_ENTITY * AltQtdPtr
1472 )
1473 /*++
1474
1475 Routine Description:
1476
1477 Link AlterQtds together
1478
1479 Arguments:
1480
1481 FirstQtdPtr - A pointer to first Qtd in the list
1482 AltQtdPtr - A pointer to alternative Qtd
1483
1484 Returns:
1485
1486 VOID
1487
1488 --*/
1489 {
1490 EHCI_QTD_ENTITY *QtdPtr;
1491 EHCI_QTD_HW *AltQtdHwPtr;
1492
1493 ASSERT(FirstQtdPtr);
1494 ASSERT(AltQtdPtr);
1495
1496 AltQtdHwPtr = &(AltQtdPtr->Qtd);
1497 QtdPtr = FirstQtdPtr;
1498
1499 while (NULL != QtdPtr) {
1500 //
1501 // Software link
1502 //
1503 QtdPtr->AltNext = AltQtdPtr;
1504 //
1505 // Hardware link
1506 //
1507 QtdPtr->Qtd.AltNextQtdPointer = (UINT32) (GET_0B_TO_31B(AltQtdHwPtr) >> 5);
1508 QtdPtr->Qtd.AltNextQtdTerminate = FALSE;
1509 QtdPtr = QtdPtr->Next;
1510 }
1511
1512 return ;
1513 }
1514
1515 VOID
1516 LinkQtdToQh (
1517 IN EHCI_QH_ENTITY *QhPtr,
1518 IN EHCI_QTD_ENTITY *QtdPtr
1519 )
1520 /*++
1521
1522 Routine Description:
1523
1524 Link Qtds list to Qh
1525
1526 Arguments:
1527
1528 QhPtr - A pointer to Qh
1529 QtdPtr - A pointer to first Qtd in the list
1530
1531 Returns:
1532
1533 VOID
1534
1535 --*/
1536 {
1537 EHCI_QTD_ENTITY *Cursor;
1538 EHCI_QTD_HW *QtdHwPtr;
1539
1540 ASSERT (QhPtr);
1541 ASSERT (QtdPtr);
1542
1543 QhPtr->FirstQtdPtr = QtdPtr;
1544 if (NULL != QtdPtr->AltNext) {
1545 QhPtr->AltQtdPtr = QtdPtr->AltNext;
1546 }
1547
1548 Cursor = QtdPtr;
1549 while (NULL != Cursor) {
1550 Cursor->SelfQh = QhPtr;
1551 if (NULL == Cursor->Next) {
1552 QhPtr->LastQtdPtr = Cursor;
1553 }
1554
1555 Cursor = Cursor->Next;
1556 }
1557
1558 QtdHwPtr = &(QtdPtr->Qtd);
1559 QhPtr->Qh.NextQtdPointer = (UINT32) (GET_0B_TO_31B (QtdHwPtr) >> 5);
1560 QhPtr->Qh.NextQtdTerminate = FALSE;
1561
1562 return ;
1563 }
1564
1565 EFI_STATUS
1566 LinkQhToAsyncList (
1567 IN USB2_HC_DEV *HcDev,
1568 IN EHCI_QH_ENTITY *QhPtr
1569 )
1570 /*++
1571
1572 Routine Description:
1573
1574 Link Qh to Async Schedule List
1575
1576 Arguments:
1577
1578 HcDev - USB2_HC_DEV
1579 QhPtr - A pointer to Qh
1580
1581 Returns:
1582
1583 EFI_SUCCESS Success
1584 EFI_DEVICE_ERROR Fail
1585
1586 --*/
1587 {
1588 EFI_STATUS Status;
1589
1590 ASSERT (HcDev);
1591 ASSERT (QhPtr);
1592
1593 QhPtr->Qh.HeadReclamationFlag = TRUE;
1594
1595 Status = SetAsyncListAddr (HcDev, QhPtr);
1596 if (EFI_ERROR (Status)) {
1597 Status = EFI_DEVICE_ERROR;
1598 goto exit;
1599 }
1600
1601 if (!IsAsyncScheduleEnabled (HcDev)) {
1602
1603 Status = EnableAsynchronousSchedule (HcDev);
1604 if (EFI_ERROR (Status)) {
1605 Status = EFI_DEVICE_ERROR;
1606 goto exit;
1607 }
1608
1609 Status = WaitForAsyncScheduleEnable (HcDev, EHCI_GENERIC_TIMEOUT);
1610 if (EFI_ERROR (Status)) {
1611 DEBUG ((gEHCDebugLevel, "WaitForAsyncScheduleEnable TimeOut"));
1612 Status = EFI_TIMEOUT;
1613 goto exit;
1614 }
1615
1616 if (IsEhcHalted (HcDev)) {
1617 Status = StartScheduleExecution (HcDev);
1618 if (EFI_ERROR (Status)) {
1619 Status = EFI_DEVICE_ERROR;
1620 }
1621 }
1622
1623 }
1624
1625 exit:
1626 return Status;
1627 }
1628
1629 EFI_STATUS
1630 UnlinkQhFromAsyncList (
1631 IN USB2_HC_DEV *HcDev,
1632 IN EHCI_QH_ENTITY *QhPtr
1633 )
1634 /*++
1635
1636 Routine Description:
1637
1638 Unlink Qh from Async Schedule List
1639
1640 Arguments:
1641
1642 HcDev - USB2_HC_DEV
1643 QhPtr - A pointer to Qh
1644
1645 Returns:
1646
1647 EFI_SUCCESS Success
1648 EFI_DEVICE_ERROR Fail
1649
1650 --*/
1651 {
1652 EFI_STATUS Status;
1653
1654 Status = EFI_SUCCESS;
1655
1656 ASSERT (HcDev);
1657 ASSERT (QhPtr);
1658
1659 if (QhPtr == QhPtr->Next) {
1660
1661 Status = DisableAsynchronousSchedule (HcDev);
1662 if (EFI_ERROR (Status)) {
1663 Status = EFI_DEVICE_ERROR;
1664 goto exit;
1665 }
1666
1667 Status = WaitForAsyncScheduleDisable (HcDev, EHCI_GENERIC_TIMEOUT);
1668 if (EFI_ERROR (Status)) {
1669 DEBUG ((gEHCErrorLevel, "WaitForAsyncScheduleDisable TimeOut\n"));
1670 Status = EFI_TIMEOUT;
1671 goto exit;
1672 }
1673
1674 }
1675
1676 exit:
1677 return Status;
1678 }
1679
1680 VOID
1681 LinkQhToPeriodicList (
1682 IN USB2_HC_DEV *HcDev,
1683 IN EHCI_QH_ENTITY *QhPtr
1684 )
1685 /*++
1686
1687 Routine Description:
1688
1689 Link Qh to Periodic Schedule List
1690
1691 Arguments:
1692
1693 HcDev - USB2_HC_DEV
1694 QhPtr - A pointer to Qh
1695
1696 Returns:
1697
1698 VOID
1699
1700 --*/
1701 {
1702 FRAME_LIST_ENTRY *FrameEntryPtr;
1703 EHCI_QH_ENTITY *FindQhPtr;
1704 EHCI_QH_HW *FindQhHwPtr;
1705 UINTN FrameIndex;
1706
1707 ASSERT (HcDev);
1708 ASSERT (QhPtr);
1709
1710 FindQhPtr = NULL;
1711 FindQhHwPtr = NULL;
1712 FrameIndex = 0;
1713 FrameEntryPtr = (FRAME_LIST_ENTRY *) HcDev->PeriodicFrameListBuffer;
1714
1715 QhPtr->Qh.HeadReclamationFlag = FALSE;
1716
1717 if (QhPtr->TransferType == ASYNC_INTERRUPT_TRANSFER) {
1718
1719 //
1720 // AsyncInterruptTransfer Qh
1721 //
1722
1723 //
1724 // Link to Frame[0] List
1725 //
1726 if (!FrameEntryPtr->LinkTerminate) {
1727 //
1728 // Not Null FrameList
1729 //
1730 FindQhHwPtr = (EHCI_QH_HW *) GET_0B_TO_31B (FrameEntryPtr->LinkPointer << 5);
1731 FindQhPtr = (EHCI_QH_ENTITY *) GET_QH_ENTITY_ADDR (FindQhHwPtr);
1732 //
1733 // FindQh is Left/Right to Qh
1734 //
1735 while ((NULL != FindQhPtr->Next) && (FindQhPtr->Interval > QhPtr->Interval)) {
1736 FindQhPtr = FindQhPtr->Next;
1737 }
1738
1739 if (FindQhPtr->Interval == QhPtr->Interval) {
1740 //
1741 // Link Qh after FindQh
1742 //
1743 if (NULL != FindQhPtr->Next) {
1744 FindQhPtr->Next->Prev = QhPtr;
1745 QhPtr->Qh.QhHorizontalPointer = (UINT32) GET_0B_TO_31B (&(FindQhPtr->Next->Qh) >> 5);
1746 QhPtr->Qh.SelectType = QH_SELECT_TYPE;
1747 QhPtr->Qh.QhTerminate = FALSE;
1748 }
1749
1750 FindQhPtr->Qh.QhHorizontalPointer = (UINT32) GET_0B_TO_31B (&(QhPtr->Qh) >> 5);
1751 FindQhPtr->Qh.SelectType = QH_SELECT_TYPE;
1752 FindQhPtr->Qh.QhTerminate = FALSE;
1753
1754 QhPtr->Prev = FindQhPtr;
1755 QhPtr->Next = FindQhPtr->Next;
1756 FindQhPtr->Next = QhPtr;
1757 } else if (FindQhPtr->Interval < QhPtr->Interval) {
1758 //
1759 // Link Qh before FindQh
1760 //
1761 if (NULL == FindQhPtr->Prev) {
1762 //
1763 // Qh is the First one in Frame[0] List
1764 //
1765 FrameEntryPtr->LinkPointer = (UINT32) GET_0B_TO_31B (&(QhPtr->Qh) >> 5);
1766 FrameEntryPtr->SelectType = QH_SELECT_TYPE;
1767 FrameEntryPtr->LinkTerminate = FALSE;
1768 } else {
1769 //
1770 // Qh is not the First one in Frame[0] List
1771 //
1772 FindQhPtr->Prev->Next = QhPtr;
1773 FindQhPtr->Prev->Qh.QhHorizontalPointer = (UINT32) GET_0B_TO_31B (&(QhPtr->Qh) >> 5);
1774 FindQhPtr->Prev->Qh.SelectType = QH_SELECT_TYPE;
1775 FindQhPtr->Prev->Qh.QhTerminate = FALSE;
1776 }
1777
1778 QhPtr->Qh.QhHorizontalPointer = (UINT32) GET_0B_TO_31B (&(FindQhPtr->Qh) >> 5);
1779 QhPtr->Qh.SelectType = QH_SELECT_TYPE;
1780 QhPtr->Qh.QhTerminate = FALSE;
1781
1782 QhPtr->Next = FindQhPtr;
1783 QhPtr->Prev = FindQhPtr->Prev;
1784 FindQhPtr->Prev = QhPtr;
1785 } else {
1786 //
1787 // Link Qh after FindQh, Qh is the Last one
1788 //
1789 FindQhPtr->Qh.QhHorizontalPointer = (UINT32) GET_0B_TO_31B (&(QhPtr->Qh) >> 5);
1790 FindQhPtr->Prev->Qh.SelectType = QH_SELECT_TYPE;
1791 FindQhPtr->Qh.QhTerminate = FALSE;
1792
1793 QhPtr->Prev = FindQhPtr;
1794 QhPtr->Next = NULL;
1795 FindQhPtr->Next = QhPtr;
1796 }
1797 } else {
1798 //
1799 // Null FrameList
1800 //
1801 FrameEntryPtr->LinkPointer = (UINT32) GET_0B_TO_31B (&(QhPtr->Qh) >> 5);
1802 FrameEntryPtr->SelectType = QH_SELECT_TYPE;
1803 FrameEntryPtr->LinkTerminate = FALSE;
1804 }
1805 //
1806 // Other Frame[X]
1807 //
1808 if (NULL == QhPtr->Prev) {
1809 //
1810 // Qh is the First one in Frame[0] List
1811 //
1812 FrameIndex += QhPtr->Interval;
1813 while (FrameIndex < HcDev->PeriodicFrameListLength) {
1814 FrameEntryPtr = (FRAME_LIST_ENTRY *) (FrameEntryPtr + QhPtr->Interval);
1815 FrameEntryPtr->LinkPointer = (UINT32) GET_0B_TO_31B (&(QhPtr->Qh) >> 5);
1816 FrameEntryPtr->SelectType = QH_SELECT_TYPE;
1817 FrameEntryPtr->LinkTerminate = FALSE;
1818 FrameIndex += QhPtr->Interval;
1819 }
1820 } else if (QhPtr->Interval < QhPtr->Prev->Interval) {
1821 //
1822 // Qh is not the First one in Frame[0] List, and Prev.interval > Qh.interval
1823 //
1824 FrameIndex += QhPtr->Interval;
1825 while (FrameIndex < HcDev->PeriodicFrameListLength) {
1826 FrameEntryPtr = (FRAME_LIST_ENTRY *) (FrameEntryPtr + QhPtr->Interval);
1827 if ((FrameIndex % QhPtr->Prev->Interval) != 0) {
1828 FrameEntryPtr->LinkPointer = (UINT32) GET_0B_TO_31B (&(QhPtr->Qh) >> 5);
1829 FrameEntryPtr->SelectType = QH_SELECT_TYPE;
1830 FrameEntryPtr->LinkTerminate = FALSE;
1831 }
1832
1833 FrameIndex += QhPtr->Interval;
1834 }
1835 }
1836 } else {
1837
1838 //
1839 // SyncInterruptTransfer Qh
1840 //
1841
1842 if (!FrameEntryPtr->LinkTerminate) {
1843 //
1844 // Not Null FrameList
1845 //
1846 FindQhHwPtr = (EHCI_QH_HW *) GET_0B_TO_31B (FrameEntryPtr->LinkPointer << 5);
1847 FindQhPtr = (EHCI_QH_ENTITY *) GET_QH_ENTITY_ADDR (FindQhHwPtr);
1848 //
1849 // FindQh is Last Qh in the Asynchronous List, Link Qh after FindQh
1850 //
1851 while (NULL != FindQhPtr->Next) {
1852 FindQhPtr = FindQhPtr->Next;
1853 }
1854
1855 FindQhPtr->Qh.QhHorizontalPointer = (UINT32) GET_0B_TO_31B (&(QhPtr->Qh) >> 5);
1856 FindQhPtr->Qh.SelectType = QH_SELECT_TYPE;
1857 FindQhPtr->Qh.QhTerminate = FALSE;
1858
1859 FindQhPtr->Next = QhPtr;
1860 QhPtr->Prev = FindQhPtr;
1861 } else {
1862 //
1863 // Null FrameList
1864 //
1865 FrameEntryPtr->LinkPointer = (UINT32) GET_0B_TO_31B (&(QhPtr->Qh) >> 5);
1866 FrameEntryPtr->SelectType = QH_SELECT_TYPE;
1867 FrameEntryPtr->LinkTerminate = FALSE;
1868 }
1869 }
1870
1871 return ;
1872 }
1873
1874 VOID
1875 UnlinkQhFromPeriodicList (
1876 IN USB2_HC_DEV *HcDev,
1877 IN EHCI_QH_ENTITY *QhPtr,
1878 IN UINTN Interval
1879 )
1880 /*++
1881
1882 Routine Description:
1883
1884 Unlink Qh from Periodic Schedule List
1885
1886 Arguments:
1887
1888 HcDev - USB2_HC_DEV
1889 QhPtr - A pointer to Qh
1890 Interval - Interval of this periodic transfer
1891
1892 Returns:
1893
1894 VOID
1895
1896 --*/
1897 {
1898 FRAME_LIST_ENTRY *FrameEntryPtr;
1899 UINTN FrameIndex;
1900
1901 FrameIndex = 0;
1902
1903 ASSERT (HcDev);
1904 ASSERT (QhPtr);
1905
1906 FrameIndex = 0;
1907 FrameEntryPtr = (FRAME_LIST_ENTRY *) HcDev->PeriodicFrameListBuffer;
1908
1909 if (QhPtr->TransferType == ASYNC_INTERRUPT_TRANSFER) {
1910
1911 //
1912 // AsyncInterruptTransfer Qh
1913 //
1914
1915 if (NULL == QhPtr->Prev) {
1916 //
1917 // Qh is the First one on Frame[0] List
1918 //
1919 if (NULL == QhPtr->Next) {
1920 //
1921 // Only one on Frame[0] List
1922 //
1923 while (FrameIndex < HcDev->PeriodicFrameListLength) {
1924 FrameEntryPtr->LinkPointer = 0;
1925 FrameEntryPtr->SelectType = 0;
1926 FrameEntryPtr->LinkTerminate = TRUE;
1927 FrameEntryPtr += Interval;
1928 FrameIndex += Interval;
1929 }
1930 } else {
1931 while (FrameIndex < HcDev->PeriodicFrameListLength) {
1932 FrameEntryPtr->LinkPointer = (UINT32) GET_0B_TO_31B (&(QhPtr->Next->Qh) >> 5);
1933 FrameEntryPtr->SelectType = QH_SELECT_TYPE;
1934 FrameEntryPtr->LinkTerminate = FALSE;
1935 FrameEntryPtr += Interval;
1936 FrameIndex += Interval;
1937 }
1938 }
1939 } else {
1940
1941 //
1942 // Not First one on Frame[0] List
1943 //
1944 if (NULL == QhPtr->Next) {
1945 //
1946 // Qh is the Last one on Frame[0] List
1947 //
1948 QhPtr->Prev->Qh.QhHorizontalPointer = 0;
1949 QhPtr->Prev->Qh.SelectType = 0;
1950 QhPtr->Prev->Qh.QhTerminate = TRUE;
1951 } else {
1952 QhPtr->Prev->Qh.QhHorizontalPointer = (UINT32) GET_0B_TO_31B (&(QhPtr->Next->Qh) >> 5);
1953 QhPtr->Prev->Qh.SelectType = QH_SELECT_TYPE;
1954 QhPtr->Prev->Qh.QhTerminate = FALSE;
1955 }
1956
1957 if (Interval == QhPtr->Prev->Interval) {
1958 //
1959 // Interval is the same as Prev
1960 // Not involed Frame[X]
1961 //
1962 } else {
1963 //
1964 // Other Frame[X]
1965 //
1966 while (FrameIndex < HcDev->PeriodicFrameListLength) {
1967 if ((FrameIndex % QhPtr->Prev->Interval) != 0) {
1968 FrameEntryPtr->LinkPointer = QhPtr->Prev->Qh.QhHorizontalPointer;
1969 FrameEntryPtr->SelectType = QhPtr->Prev->Qh.SelectType;
1970 FrameEntryPtr->LinkTerminate = QhPtr->Prev->Qh.QhTerminate;
1971 }
1972 FrameEntryPtr += Interval;
1973 FrameIndex += Interval;
1974 }
1975 }
1976 }
1977
1978 if (NULL != QhPtr->Next) {
1979 QhPtr->Next->Prev = QhPtr->Prev;
1980 }
1981
1982 if (NULL != QhPtr->Prev) {
1983 QhPtr->Prev->Next = QhPtr->Next;
1984 }
1985 } else {
1986 //
1987 // SyncInterruptTransfer Qh
1988 //
1989 if (NULL == QhPtr->Prev) {
1990 //
1991 // Qh is the only one Qh on Frame[0] List
1992 //
1993 FrameEntryPtr->LinkPointer = 0;
1994 FrameEntryPtr->SelectType = 0;
1995 FrameEntryPtr->LinkTerminate = TRUE;
1996 } else {
1997 QhPtr->Prev->Qh.QhHorizontalPointer = 0;
1998 QhPtr->Prev->Qh.SelectType = 0;
1999 QhPtr->Prev->Qh.QhTerminate = TRUE;
2000 }
2001
2002 if (NULL != QhPtr->Prev) {
2003 QhPtr->Prev->Next = NULL;
2004 }
2005 }
2006
2007 return ;
2008 }
2009
2010 VOID
2011 LinkToAsyncReqeust (
2012 IN USB2_HC_DEV *HcDev,
2013 IN EHCI_ASYNC_REQUEST *AsyncRequestPtr
2014 )
2015 /*++
2016
2017 Routine Description:
2018
2019 Llink AsyncRequest Entry to Async Request List
2020
2021 Arguments:
2022
2023 HcDev - USB2_HC_DEV
2024 AsyncRequestPtr - A pointer to Async Request Entry
2025
2026 Returns:
2027
2028 VOID
2029
2030 --*/
2031 {
2032 EHCI_ASYNC_REQUEST *CurrentPtr;
2033
2034 CurrentPtr = HcDev->AsyncRequestList;
2035 HcDev->AsyncRequestList = AsyncRequestPtr;
2036 AsyncRequestPtr->Prev = NULL;
2037 AsyncRequestPtr->Next = CurrentPtr;
2038
2039 if (NULL != CurrentPtr) {
2040 CurrentPtr->Prev = AsyncRequestPtr;
2041 }
2042
2043 return ;
2044 }
2045
2046 VOID
2047 UnlinkFromAsyncReqeust (
2048 IN USB2_HC_DEV *HcDev,
2049 IN EHCI_ASYNC_REQUEST *AsyncRequestPtr
2050 )
2051 /*++
2052
2053 Routine Description:
2054
2055 Unlink AsyncRequest Entry from Async Request List
2056
2057 Arguments:
2058
2059 HcDev - USB2_HC_DEV
2060 AsyncRequestPtr - A pointer to Async Request Entry
2061
2062 Returns:
2063
2064 VOID
2065
2066 --*/
2067 {
2068 if (NULL == AsyncRequestPtr->Prev) {
2069 HcDev->AsyncRequestList = AsyncRequestPtr->Next;
2070 if (NULL != AsyncRequestPtr->Next) {
2071 AsyncRequestPtr->Next->Prev = NULL;
2072 }
2073 } else {
2074 AsyncRequestPtr->Prev->Next = AsyncRequestPtr->Next;
2075 if (NULL != AsyncRequestPtr->Next) {
2076 AsyncRequestPtr->Next->Prev = AsyncRequestPtr->Prev;
2077 }
2078 }
2079
2080 return ;
2081 }
2082
2083 VOID
2084 SetQtdBufferPointer (
2085 IN EHCI_QTD_HW *QtdHwPtr,
2086 IN VOID *DataPtr,
2087 IN UINTN DataLen
2088 )
2089 /*++
2090
2091 Routine Description:
2092
2093 Set data buffer pointers in Qtd
2094
2095 Arguments:
2096
2097 QtdHwPtr - A pointer to Qtd hardware structure
2098 DataPtr - A pointer to user data buffer
2099 DataLen - Length of the user data buffer
2100
2101 Returns:
2102
2103 VOID
2104
2105 --*/
2106 {
2107 UINTN RemainLen;
2108
2109 RemainLen = DataLen;
2110 ASSERT (QtdHwPtr);
2111
2112 //
2113 // Set BufferPointer0, ExtBufferPointer0 and Offset
2114 //
2115 QtdHwPtr->BufferPointer0 = (UINT32) (GET_0B_TO_31B (DataPtr) >> 12);
2116 QtdHwPtr->CurrentOffset = (UINT32) (GET_0B_TO_31B (DataPtr) & EFI_PAGE_MASK);
2117 QtdHwPtr->ExtBufferPointer0 = (UINT32) GET_32B_TO_63B (DataPtr);
2118
2119 //
2120 // Set BufferPointer1 and ExtBufferPointer1
2121 //
2122 RemainLen = RemainLen > (EFI_PAGE_SIZE - QtdHwPtr->CurrentOffset) ? (RemainLen - (EFI_PAGE_SIZE - QtdHwPtr->CurrentOffset)) : 0;
2123 if (RemainLen == 0) {
2124 goto exit;
2125 }
2126
2127 QtdHwPtr->BufferPointer1 = QtdHwPtr->BufferPointer0 + 1;
2128 QtdHwPtr->ExtBufferPointer1 = QtdHwPtr->ExtBufferPointer0;
2129
2130 //
2131 // Set BufferPointer2 and ExtBufferPointer2
2132 //
2133 RemainLen = RemainLen > EFI_PAGE_SIZE ? (RemainLen - EFI_PAGE_SIZE) : 0;
2134 if (RemainLen == 0) {
2135 goto exit;
2136 }
2137
2138 QtdHwPtr->BufferPointer2 = QtdHwPtr->BufferPointer1 + 1;
2139 QtdHwPtr->ExtBufferPointer2 = QtdHwPtr->ExtBufferPointer0;
2140
2141 //
2142 // Set BufferPointer3 and ExtBufferPointer3
2143 //
2144 RemainLen = RemainLen > EFI_PAGE_SIZE ? (RemainLen - EFI_PAGE_SIZE) : 0;
2145 if (RemainLen == 0) {
2146 goto exit;
2147 }
2148
2149 QtdHwPtr->BufferPointer3 = QtdHwPtr->BufferPointer2 + 1;
2150 QtdHwPtr->ExtBufferPointer3 = QtdHwPtr->ExtBufferPointer0;
2151
2152 //
2153 // Set BufferPointer4 and ExtBufferPointer4
2154 //
2155 RemainLen = RemainLen > EFI_PAGE_SIZE ? (RemainLen - EFI_PAGE_SIZE) : 0;
2156 if (RemainLen == 0) {
2157 goto exit;
2158 }
2159
2160 QtdHwPtr->BufferPointer4 = QtdHwPtr->BufferPointer3 + 1;
2161 QtdHwPtr->ExtBufferPointer4 = QtdHwPtr->ExtBufferPointer0;
2162
2163 exit:
2164 return ;
2165 }
2166
2167 BOOLEAN
2168 IsQtdStatusActive (
2169 IN EHCI_QTD_HW *HwQtdPtr
2170 )
2171 /*++
2172
2173 Routine Description:
2174
2175 Whether Qtd status is active or not
2176
2177 Arguments:
2178
2179 HwQtdPtr - A pointer to hardware Qtd structure
2180
2181 Returns:
2182
2183 TRUE Active
2184 FALSE Inactive
2185
2186 --*/
2187 {
2188 UINT8 QtdStatus;
2189 BOOLEAN Value;
2190
2191 QtdStatus = (UINT8) (HwQtdPtr->Status);
2192 Value = (BOOLEAN) (QtdStatus & QTD_STATUS_ACTIVE);
2193
2194 return Value;
2195 }
2196
2197 BOOLEAN
2198 IsQtdStatusHalted (
2199 IN EHCI_QTD_HW *HwQtdPtr
2200 )
2201 /*++
2202
2203 Routine Description:
2204
2205 Whether Qtd status is halted or not
2206
2207 Arguments:
2208
2209 HwQtdPtr - A pointer to hardware Qtd structure
2210
2211 Returns:
2212
2213 TRUE Halted
2214 FALSE Not halted
2215
2216 --*/
2217 {
2218 UINT8 QtdStatus;
2219 BOOLEAN Value;
2220
2221 QtdStatus = (UINT8) (HwQtdPtr->Status);
2222 Value = (BOOLEAN) (QtdStatus & QTD_STATUS_HALTED);
2223
2224 return Value;
2225 }
2226
2227 BOOLEAN
2228 IsQtdStatusBufferError (
2229 IN EHCI_QTD_HW *HwQtdPtr
2230 )
2231 /*++
2232
2233 Routine Description:
2234
2235 Whether Qtd status is buffer error or not
2236
2237 Arguments:
2238
2239 HwQtdPtr - A pointer to hardware Qtd structure
2240
2241 Returns:
2242
2243 TRUE Buffer error
2244 FALSE No buffer error
2245
2246 --*/
2247 {
2248 UINT8 QtdStatus;
2249 BOOLEAN Value;
2250
2251 QtdStatus = (UINT8) (HwQtdPtr->Status);
2252 Value = (BOOLEAN) (QtdStatus & QTD_STATUS_BUFFER_ERR);
2253
2254 return Value;
2255 }
2256
2257 BOOLEAN
2258 IsQtdStatusBabbleError (
2259 IN EHCI_QTD_HW *HwQtdPtr
2260 )
2261 /*++
2262
2263 Routine Description:
2264
2265 Whether Qtd status is babble error or not
2266
2267 Arguments:
2268
2269 HwQtdPtr - A pointer to hardware Qtd structure
2270
2271 Returns:
2272
2273 TRUE Babble error
2274 FALSE No babble error
2275
2276 --*/
2277 {
2278 UINT8 QtdStatus;
2279 BOOLEAN Value;
2280
2281 QtdStatus = (UINT8) (HwQtdPtr->Status);
2282 Value = (BOOLEAN) (QtdStatus & QTD_STATUS_BABBLE_ERR);
2283
2284 return Value;
2285 }
2286
2287 BOOLEAN
2288 IsQtdStatusTransactionError (
2289 IN EHCI_QTD_HW *HwQtdPtr
2290 )
2291 /*++
2292
2293 Routine Description:
2294
2295 Whether Qtd status is transaction error or not
2296
2297 Arguments:
2298
2299 HwQtdPtr - A pointer to hardware Qtd structure
2300
2301 Returns:
2302
2303 TRUE Transaction error
2304 FALSE No transaction error
2305
2306 --*/
2307 {
2308 UINT8 QtdStatus;
2309 BOOLEAN Value;
2310
2311 QtdStatus = (UINT8) (HwQtdPtr->Status);
2312 Value = (BOOLEAN) (QtdStatus & QTD_STATUS_TRANSACTION_ERR);
2313
2314 return Value;
2315 }
2316
2317 BOOLEAN
2318 IsDataInTransfer (
2319 IN UINT8 EndPointAddress
2320 )
2321 /*++
2322
2323 Routine Description:
2324
2325 Whether is a DataIn direction transfer
2326
2327 Arguments:
2328
2329 EndPointAddress - address of the endpoint
2330
2331 Returns:
2332
2333 TRUE DataIn
2334 FALSE DataOut
2335
2336 --*/
2337 {
2338 BOOLEAN Value;
2339
2340 if (EndPointAddress & 0x80) {
2341 Value = TRUE;
2342 } else {
2343 Value = FALSE;
2344 }
2345
2346 return Value;
2347 }
2348
2349 EFI_STATUS
2350 MapDataBuffer (
2351 IN USB2_HC_DEV *HcDev,
2352 IN EFI_USB_DATA_DIRECTION TransferDirection,
2353 IN VOID *Data,
2354 IN OUT UINTN *DataLength,
2355 OUT UINT8 *PktId,
2356 OUT UINT8 **DataCursor,
2357 OUT VOID **DataMap
2358 )
2359 /*++
2360
2361 Routine Description:
2362
2363 Map address of user data buffer
2364
2365 Arguments:
2366
2367 HcDev - USB2_HC_DEV
2368 TransferDirection - direction of transfer
2369 Data - A pointer to user data buffer
2370 DataLength - length of user data
2371 PktId - Packte Identificaion
2372 DataCursor - mapped address to return
2373 DataMap - identificaion of this mapping to return
2374
2375 Returns:
2376
2377 EFI_SUCCESS Success
2378 EFI_DEVICE_ERROR Fail
2379
2380 --*/
2381 {
2382 EFI_STATUS Status;
2383 EFI_PHYSICAL_ADDRESS TempPhysicalAddr;
2384
2385 Status = EFI_SUCCESS;
2386
2387 switch (TransferDirection) {
2388
2389 case EfiUsbDataIn:
2390
2391 *PktId = INPUT_PACKET_ID;
2392 //
2393 // BusMasterWrite means cpu read
2394 //
2395 Status = HcDev->PciIo->Map (
2396 HcDev->PciIo,
2397 EfiPciIoOperationBusMasterWrite,
2398 Data,
2399 DataLength,
2400 &TempPhysicalAddr,
2401 DataMap
2402 );
2403 if (EFI_ERROR (Status)) {
2404 DEBUG ((gEHCDebugLevel, "MapDataBuffer Failed\n"));
2405 Status = EFI_DEVICE_ERROR;
2406 goto exit;
2407 }
2408
2409 *DataCursor = (UINT8 *) ((UINTN) TempPhysicalAddr);
2410 break;
2411
2412 case EfiUsbDataOut:
2413
2414 *PktId = OUTPUT_PACKET_ID;
2415 //
2416 // BusMasterRead means cpu write
2417 //
2418 Status = HcDev->PciIo->Map (
2419 HcDev->PciIo,
2420 EfiPciIoOperationBusMasterRead,
2421 Data,
2422 DataLength,
2423 &TempPhysicalAddr,
2424 DataMap
2425 );
2426 if (EFI_ERROR (Status)) {
2427 Status = EFI_DEVICE_ERROR;
2428 goto exit;
2429 }
2430
2431 *DataCursor = (UINT8 *) ((UINTN) TempPhysicalAddr);
2432 break;
2433
2434 case EfiUsbNoData:
2435
2436 *PktId = OUTPUT_PACKET_ID;
2437 Data = NULL;
2438 *DataLength = 0;
2439 *DataCursor = NULL;
2440 *DataMap = NULL;
2441 break;
2442
2443 default:
2444
2445 Status = EFI_INVALID_PARAMETER;
2446 }
2447
2448 exit:
2449 return Status;
2450 }
2451
2452 EFI_STATUS
2453 MapRequestBuffer (
2454 IN USB2_HC_DEV *HcDev,
2455 IN OUT VOID *Request,
2456 OUT UINT8 **RequestCursor,
2457 OUT VOID **RequestMap
2458 )
2459 /*++
2460
2461 Routine Description:
2462
2463 Map address of request structure buffer
2464
2465 Arguments:
2466
2467 HcDev - USB2_HC_DEV
2468 Request - A pointer to request structure
2469 RequestCursor - Mapped address of request structure to return
2470 RequestMap - Identificaion of this mapping to return
2471
2472 Returns:
2473
2474 EFI_SUCCESS Success
2475 EFI_DEVICE_ERROR Fail
2476
2477 --*/
2478 {
2479 EFI_STATUS Status;
2480 UINTN RequestLen;
2481 EFI_PHYSICAL_ADDRESS TempPhysicalAddr;
2482
2483 RequestLen = sizeof (EFI_USB_DEVICE_REQUEST);
2484 Status = HcDev->PciIo->Map (
2485 HcDev->PciIo,
2486 EfiPciIoOperationBusMasterRead,
2487 (UINT8 *) Request,
2488 (UINTN *) &RequestLen,
2489 &TempPhysicalAddr,
2490 RequestMap
2491 );
2492 if (EFI_ERROR (Status)) {
2493 Status = EFI_DEVICE_ERROR;
2494 goto exit;
2495 }
2496
2497 *RequestCursor = (UINT8 *) ((UINTN) TempPhysicalAddr);
2498
2499 exit:
2500 return Status;
2501 }
2502
2503 EFI_STATUS
2504 DeleteAsyncRequestTransfer (
2505 IN USB2_HC_DEV *HcDev,
2506 IN UINT8 DeviceAddress,
2507 IN UINT8 EndPointAddress,
2508 OUT UINT8 *DataToggle
2509 )
2510 /*++
2511
2512 Routine Description:
2513
2514 Delete all asynchronous request transfer
2515
2516 Arguments:
2517
2518 HcDev - USB2_HC_DEV
2519 DeviceAddress - address of usb device
2520 EndPointAddress - address of endpoint
2521 DataToggle - stored data toggle
2522
2523 Returns:
2524
2525 EFI_SUCCESS Success
2526 EFI_DEVICE_ERROR Fail
2527
2528 --*/
2529 {
2530 EFI_STATUS Status;
2531 EHCI_ASYNC_REQUEST *AsyncRequestPtr;
2532 EHCI_ASYNC_REQUEST *MatchPtr;
2533 EHCI_QH_HW *QhHwPtr;
2534 UINT8 EndPointNum;
2535
2536 if (NULL == HcDev->AsyncRequestList) {
2537 Status = EFI_INVALID_PARAMETER;
2538 goto exit;
2539 }
2540
2541 MatchPtr = NULL;
2542 QhHwPtr = NULL;
2543 EndPointNum = EndPointAddress & 0x0f;
2544 AsyncRequestPtr = HcDev->AsyncRequestList;
2545
2546 //
2547 // Find QH of AsyncRequest by DeviceAddress and EndPointNum
2548 //
2549 do {
2550
2551 QhHwPtr = &(AsyncRequestPtr->QhPtr->Qh);
2552 if (QhHwPtr->DeviceAddr == DeviceAddress && QhHwPtr->EndpointNum == EndPointNum) {
2553 MatchPtr = AsyncRequestPtr;
2554 break;
2555 }
2556
2557 AsyncRequestPtr = AsyncRequestPtr->Next;
2558
2559 } while (NULL != AsyncRequestPtr);
2560
2561 if (NULL == MatchPtr) {
2562 Status = EFI_INVALID_PARAMETER;
2563 goto exit;
2564 }
2565
2566 Status = DisablePeriodicSchedule (HcDev);
2567 if (EFI_ERROR (Status)) {
2568 Status = EFI_DEVICE_ERROR;
2569 goto exit;
2570 }
2571
2572 Status = WaitForPeriodicScheduleDisable (HcDev, EHCI_GENERIC_TIMEOUT);
2573 if (EFI_ERROR (Status)) {
2574 DEBUG ((gEHCErrorLevel, "WaitForPeriodicScheduleDisable TimeOut\n"));
2575 Status = EFI_TIMEOUT;
2576 goto exit;
2577 }
2578
2579 *DataToggle = (UINT8) MatchPtr->QhPtr->Qh.DataToggle;
2580 UnlinkQhFromPeriodicList (HcDev, MatchPtr->QhPtr, MatchPtr->QhPtr->Interval);
2581 UnlinkFromAsyncReqeust (HcDev, MatchPtr);
2582
2583 if (NULL == HcDev->AsyncRequestList) {
2584
2585 Status = StopPollingTimer (HcDev);
2586 if (EFI_ERROR (Status)) {
2587 Status = EFI_DEVICE_ERROR;
2588 goto exit;
2589 }
2590
2591 } else {
2592
2593 Status = EnablePeriodicSchedule (HcDev);
2594 if (EFI_ERROR (Status)) {
2595 Status = EFI_DEVICE_ERROR;
2596 goto exit;
2597 }
2598
2599 Status = WaitForPeriodicScheduleEnable (HcDev, EHCI_GENERIC_TIMEOUT);
2600 if (EFI_ERROR (Status)) {
2601 DEBUG ((gEHCErrorLevel, "WaitForPeriodicScheduleEnable TimeOut\n"));
2602 Status = EFI_TIMEOUT;
2603 goto exit;
2604 }
2605
2606 if (IsEhcHalted (HcDev)) {
2607 Status = StartScheduleExecution (HcDev);
2608 if (EFI_ERROR (Status)) {
2609 Status = EFI_DEVICE_ERROR;
2610 goto exit;
2611 }
2612 }
2613
2614 }
2615
2616 DestoryQtds (HcDev, MatchPtr->QhPtr->FirstQtdPtr);
2617 DestoryQh (HcDev, MatchPtr->QhPtr);
2618 EhciFreePool (HcDev, (UINT8 *) MatchPtr, sizeof (EHCI_ASYNC_REQUEST));
2619
2620 exit:
2621 return Status;
2622 }
2623
2624 VOID
2625 CleanUpAllAsyncRequestTransfer (
2626 IN USB2_HC_DEV *HcDev
2627 )
2628 /*++
2629
2630 Routine Description:
2631
2632 Clean up all asynchronous request transfer
2633
2634 Arguments:
2635
2636 HcDev - USB2_HC_DEV
2637
2638 Returns:
2639
2640 VOID
2641
2642 --*/
2643 {
2644 EHCI_ASYNC_REQUEST *AsyncRequestPtr;
2645 EHCI_ASYNC_REQUEST *FreePtr;
2646
2647 AsyncRequestPtr = NULL;
2648 FreePtr = NULL;
2649
2650 StopPollingTimer (HcDev);
2651
2652 AsyncRequestPtr = HcDev->AsyncRequestList;
2653 while (NULL != AsyncRequestPtr) {
2654
2655 FreePtr = AsyncRequestPtr;
2656 AsyncRequestPtr = AsyncRequestPtr->Next;
2657 UnlinkFromAsyncReqeust (HcDev, FreePtr);
2658 UnlinkQhFromPeriodicList (HcDev, FreePtr->QhPtr, FreePtr->QhPtr->Interval);
2659 DestoryQtds (HcDev, FreePtr->QhPtr->FirstQtdPtr);
2660 DestoryQh (HcDev, FreePtr->QhPtr);
2661 EhciFreePool (HcDev, (UINT8 *) FreePtr, sizeof (EHCI_ASYNC_REQUEST));
2662
2663 }
2664
2665 return ;
2666 }
2667
2668 VOID
2669 ZeroOutQhOverlay (
2670 IN EHCI_QH_ENTITY *QhPtr
2671 )
2672 /*++
2673
2674 Routine Description:
2675
2676 Zero out the fields in Qh structure
2677
2678 Arguments:
2679
2680 QhPtr - A pointer to Qh structure
2681
2682 Returns:
2683
2684 VOID
2685
2686 --*/
2687 {
2688 QhPtr->Qh.CurrentQtdPointer = 0;
2689 QhPtr->Qh.AltNextQtdPointer = 0;
2690 QhPtr->Qh.NakCount = 0;
2691 QhPtr->Qh.AltNextQtdTerminate = 0;
2692 QhPtr->Qh.TotalBytes = 0;
2693 QhPtr->Qh.InterruptOnComplete = 0;
2694 QhPtr->Qh.CurrentPage = 0;
2695 QhPtr->Qh.ErrorCount = 0;
2696 QhPtr->Qh.PidCode = 0;
2697 QhPtr->Qh.Status = 0;
2698 QhPtr->Qh.BufferPointer0 = 0;
2699 QhPtr->Qh.CurrentOffset = 0;
2700 QhPtr->Qh.BufferPointer1 = 0;
2701 QhPtr->Qh.CompleteSplitMask = 0;
2702 QhPtr->Qh.BufferPointer2 = 0;
2703 QhPtr->Qh.SplitBytes = 0;
2704 QhPtr->Qh.FrameTag = 0;
2705 QhPtr->Qh.BufferPointer3 = 0;
2706 QhPtr->Qh.BufferPointer4 = 0;
2707 QhPtr->Qh.ExtBufferPointer0 = 0;
2708 QhPtr->Qh.ExtBufferPointer1 = 0;
2709 QhPtr->Qh.ExtBufferPointer2 = 0;
2710 QhPtr->Qh.ExtBufferPointer3 = 0;
2711 QhPtr->Qh.ExtBufferPointer4 = 0;
2712 }
2713
2714 VOID
2715 UpdateAsyncRequestTransfer (
2716 IN EHCI_ASYNC_REQUEST *AsyncRequestPtr,
2717 IN UINT32 TransferResult,
2718 IN UINTN ErrQtdPos
2719 )
2720 /*++
2721
2722 Routine Description:
2723
2724 Update asynchronous request transfer
2725
2726 Arguments:
2727
2728 AsyncRequestPtr - A pointer to async request
2729 TransferResult - transfer result
2730 ErrQtdPos - postion of error Qtd
2731
2732 Returns:
2733
2734 VOID
2735
2736 --*/
2737 {
2738 EHCI_QTD_ENTITY *QtdPtr;
2739
2740 QtdPtr = NULL;
2741
2742 if (EFI_USB_NOERROR == TransferResult) {
2743
2744 //
2745 // Update Qh for next trigger
2746 //
2747
2748 QtdPtr = AsyncRequestPtr->QhPtr->FirstQtdPtr;
2749
2750 //
2751 // Update fields in Qh
2752 //
2753
2754 //
2755 // Get DataToggle from Overlay in Qh
2756 //
2757 // ZeroOut Overlay in Qh except DataToggle, HostController will update this field
2758 //
2759 ZeroOutQhOverlay (AsyncRequestPtr->QhPtr);
2760 AsyncRequestPtr->QhPtr->Qh.NextQtdPointer = (UINT32) (GET_0B_TO_31B (&(QtdPtr->Qtd)) >> 5);
2761 AsyncRequestPtr->QhPtr->Qh.NextQtdTerminate = FALSE;
2762
2763 //
2764 // Update fields in Qtd
2765 //
2766 while (NULL != QtdPtr) {
2767 QtdPtr->Qtd.TotalBytes = QtdPtr->StaticTotalBytes;
2768 QtdPtr->Qtd.CurrentOffset = QtdPtr->StaticCurrentOffset;
2769 QtdPtr->Qtd.CurrentPage = 0;
2770 QtdPtr->Qtd.ErrorCount = QTD_ERROR_COUNTER;
2771 QtdPtr->Qtd.Status = QTD_STATUS_ACTIVE;
2772
2773 QtdPtr->TotalBytes = QtdPtr->StaticTotalBytes;
2774 QtdPtr = QtdPtr->Next;
2775 }
2776 }
2777
2778 return ;
2779 }
2780
2781 BOOLEAN
2782 CheckQtdsTransferResult (
2783 IN BOOLEAN IsControl,
2784 IN EHCI_QH_ENTITY *QhPtr,
2785 OUT UINT32 *Result,
2786 OUT UINTN *ErrQtdPos,
2787 OUT UINTN *ActualLen
2788 )
2789 /*++
2790
2791 Routine Description:
2792
2793 Check transfer result of Qtds
2794
2795 Arguments:
2796
2797 IsControl - Is control transfer or not
2798 QhPtr - A pointer to Qh
2799 Result - Transfer result
2800 ErrQtdPos - Error TD Position
2801 ActualLen - Actual Transfer Size
2802
2803 Returns:
2804
2805 TRUE Qtds finished
2806 FALSE Not finish
2807
2808 --*/
2809 {
2810 UINTN ActualLenPerQtd;
2811 EHCI_QTD_ENTITY *QtdPtr;
2812 EHCI_QTD_HW *QtdHwPtr;
2813 BOOLEAN Value;
2814
2815 ASSERT (QhPtr);
2816 ASSERT (Result);
2817 ASSERT (ErrQtdPos);
2818 ASSERT (ActualLen);
2819
2820 Value = TRUE;
2821 QtdPtr = QhPtr->FirstQtdPtr;
2822 QtdHwPtr = &(QtdPtr->Qtd);
2823
2824 while (NULL != QtdHwPtr) {
2825
2826 if (IsQtdStatusActive (QtdHwPtr)) {
2827 *Result |= EFI_USB_ERR_NOTEXECUTE;
2828 }
2829
2830 if (IsQtdStatusHalted (QtdHwPtr)) {
2831 *Result |= EFI_USB_ERR_STALL;
2832 }
2833
2834 if (IsQtdStatusBufferError (QtdHwPtr)) {
2835 *Result |= EFI_USB_ERR_BUFFER;
2836 }
2837
2838 if (IsQtdStatusBabbleError (QtdHwPtr)) {
2839 *Result |= EFI_USB_ERR_BABBLE;
2840 }
2841
2842 if (IsQtdStatusTransactionError (QtdHwPtr)) {
2843 *Result |= EFI_USB_ERR_TIMEOUT;
2844 }
2845
2846 ActualLenPerQtd = QtdPtr->TotalBytes - QtdHwPtr->TotalBytes;
2847 QtdPtr->TotalBytes = QtdHwPtr->TotalBytes;
2848 //
2849 // Accumulate actual transferred data length in each DataQtd.
2850 //
2851 if (SETUP_PACKET_PID_CODE != QtdHwPtr->PidCode) {
2852 *ActualLen += ActualLenPerQtd;
2853 }
2854
2855 if (*Result) {
2856 Value = FALSE;
2857 break;
2858 }
2859
2860 if ((!IsControl) && (QtdPtr->TotalBytes > 0)) {
2861 //
2862 // Did something, but isn't full workload
2863 //
2864 break;
2865 }
2866
2867 (*ErrQtdPos)++;
2868 QtdHwPtr = GetQtdNextPointer (QtdHwPtr);
2869 QtdPtr = (EHCI_QTD_ENTITY *) GET_QTD_ENTITY_ADDR (QtdHwPtr);
2870
2871 }
2872
2873 return Value;
2874 }
2875
2876 EFI_STATUS
2877 ExecuteTransfer (
2878 IN USB2_HC_DEV *HcDev,
2879 IN BOOLEAN IsControl,
2880 IN EHCI_QH_ENTITY *QhPtr,
2881 IN OUT UINTN *ActualLen,
2882 OUT UINT8 *DataToggle,
2883 IN UINTN TimeOut,
2884 OUT UINT32 *TransferResult
2885 )
2886 /*++
2887
2888 Routine Description:
2889
2890 Execute Bulk or SyncInterrupt Transfer
2891
2892 Arguments:
2893
2894 HcDev - USB2_HC_DEV
2895 IsControl - Is control transfer or not
2896 QhPtr - A pointer to Qh
2897 ActualLen - Actual transfered Len
2898 DataToggle - Data Toggle
2899 TimeOut - TimeOut threshold
2900 TransferResult - Transfer result
2901
2902 Returns:
2903
2904 EFI_SUCCESS Sucess
2905 EFI_DEVICE_ERROR Fail
2906
2907 --*/
2908 {
2909 EFI_STATUS Status;
2910 UINTN ErrQtdPos;
2911 UINTN Delay;
2912 UINTN RequireLen;
2913 BOOLEAN Finished;
2914
2915 Status = EFI_SUCCESS;
2916 ErrQtdPos = 0;
2917 *TransferResult = EFI_USB_NOERROR;
2918 RequireLen = *ActualLen;
2919 *ActualLen = 0;
2920 Finished = FALSE;
2921
2922 Delay = (TimeOut * STALL_1_MILLI_SECOND / 50) + 1;
2923
2924 do {
2925 *TransferResult = 0;
2926 Finished = CheckQtdsTransferResult (
2927 IsControl,
2928 QhPtr,
2929 TransferResult,
2930 &ErrQtdPos,
2931 ActualLen
2932 );
2933 if (Finished) {
2934 break;
2935 }
2936 //
2937 // Qtd is inactive, which means bulk or interrupt transfer's end.
2938 //
2939 if (!(*TransferResult & EFI_USB_ERR_NOTEXECUTE)) {
2940 break;
2941 }
2942
2943 gBS->Stall (EHCI_SYNC_REQUEST_POLLING_TIME);
2944
2945 } while (--Delay);
2946
2947 if (EFI_USB_NOERROR != *TransferResult) {
2948 if (0 == Delay) {
2949 Status = EFI_TIMEOUT;
2950 } else {
2951 Status = EFI_DEVICE_ERROR;
2952 }
2953 }
2954
2955 //
2956 // Special for Bulk and Interrupt Transfer
2957 //
2958 *DataToggle = (UINT8) QhPtr->Qh.DataToggle;
2959
2960 return Status;
2961 }
2962
2963 EFI_STATUS
2964 AsyncRequestMoniter (
2965 IN EFI_EVENT Event,
2966 IN VOID *Context
2967 )
2968 /*++
2969 Routine Description:
2970
2971 Interrupt transfer periodic check handler
2972
2973 Arguments:
2974 Event - Interrupt event
2975 Context - Pointer to USB2_HC_DEV
2976
2977 Returns:
2978
2979 EFI_SUCCESS Success
2980 EFI_DEVICE_ERROR Fail
2981
2982 --*/
2983 {
2984 EFI_STATUS Status;
2985 USB2_HC_DEV *HcDev;
2986 EHCI_ASYNC_REQUEST *AsyncRequestPtr;
2987 EHCI_QTD_HW *QtdHwPtr;
2988 UINTN ErrQtdPos;
2989 UINTN ActualLen;
2990 UINT32 TransferResult;
2991 UINT8 *ReceiveBuffer;
2992 UINT8 *ProcessBuffer;
2993
2994 Status = EFI_SUCCESS;
2995 QtdHwPtr = NULL;
2996 ReceiveBuffer = NULL;
2997 ProcessBuffer = NULL;
2998 HcDev = (USB2_HC_DEV *) Context;
2999 AsyncRequestPtr = HcDev->AsyncRequestList;
3000
3001 while (NULL != AsyncRequestPtr) {
3002
3003 TransferResult = 0;
3004 ErrQtdPos = 0;
3005 ActualLen = 0;
3006
3007 CheckQtdsTransferResult (
3008 FALSE,
3009 AsyncRequestPtr->QhPtr,
3010 &TransferResult,
3011 &ErrQtdPos,
3012 &ActualLen
3013 );
3014
3015 if ((TransferResult & EFI_USB_ERR_NAK) || (TransferResult & EFI_USB_ERR_NOTEXECUTE)) {
3016 AsyncRequestPtr = AsyncRequestPtr->Next;
3017 continue;
3018 }
3019 //
3020 // Allocate memory for EHC private data structure
3021 //
3022 ProcessBuffer = AllocateZeroPool (ActualLen);
3023 if (NULL == ProcessBuffer) {
3024 Status = EFI_OUT_OF_RESOURCES;
3025 goto exit;
3026 }
3027
3028 QtdHwPtr = &(AsyncRequestPtr->QhPtr->FirstQtdPtr->Qtd);
3029 ReceiveBuffer = (UINT8 *) GET_0B_TO_31B ((QtdHwPtr->BufferPointer0 << 12) | AsyncRequestPtr->QhPtr->FirstQtdPtr->StaticCurrentOffset);
3030 CopyMem (
3031 ProcessBuffer,
3032 ReceiveBuffer,
3033 ActualLen
3034 );
3035
3036 UpdateAsyncRequestTransfer (AsyncRequestPtr, TransferResult, ErrQtdPos);
3037
3038 if (EFI_USB_NOERROR == TransferResult) {
3039
3040 if (AsyncRequestPtr->CallBackFunc != NULL) {
3041 (AsyncRequestPtr->CallBackFunc) (ProcessBuffer, ActualLen, AsyncRequestPtr->Context, TransferResult);
3042 }
3043
3044 } else {
3045
3046 //
3047 // leave error recovery to its related device driver. A common case of
3048 // the error recovery is to re-submit the interrupt transfer.
3049 // When an interrupt transfer is re-submitted, its position in the linked
3050 // list is changed. It is inserted to the head of the linked list, while
3051 // this function scans the whole list from head to tail. Thus, the
3052 // re-submitted interrupt transfer's callback function will not be called
3053 // again in this round.
3054 //
3055 if (AsyncRequestPtr->CallBackFunc != NULL) {
3056 (AsyncRequestPtr->CallBackFunc) (NULL, 0, AsyncRequestPtr->Context, TransferResult);
3057 }
3058
3059 }
3060
3061 if (NULL != ProcessBuffer) {
3062 gBS->FreePool (ProcessBuffer);
3063 }
3064
3065 AsyncRequestPtr = AsyncRequestPtr->Next;
3066
3067 }
3068
3069 exit:
3070 return Status;
3071 }
3072