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