TianoCore EDK2 master
Loading...
Searching...
No Matches
UhcPeim.c
Go to the documentation of this file.
1
11#include "UhcPeim.h"
12
25 IN USB_UHC_DEV *Uhc,
26 IN UINTN Timeout
27 )
28{
29 UINT16 CommandContent;
30 UINT16 UsbSts;
31 UINTN Index;
32
33 CommandContent = USBReadPortW (Uhc, Uhc->UsbHostControllerBaseAddress + USBCMD);
34 CommandContent &= USBCMD_RS;
35 USBWritePortW (Uhc, Uhc->UsbHostControllerBaseAddress + USBCMD, CommandContent);
36
37 //
38 // ensure the HC is in halt status after send the stop command
39 // Timeout is in us unit.
40 //
41 for (Index = 0; Index < (Timeout / 50) + 1; Index++) {
42 UsbSts = USBReadPortW (Uhc, Uhc->UsbHostControllerBaseAddress + USBSTS);
43
44 if ((UsbSts & USBSTS_HCH) == USBSTS_HCH) {
45 return EFI_SUCCESS;
46 }
47
49 }
50
51 return EFI_TIMEOUT;
52}
53
66EFIAPI
68 IN EFI_PEI_SERVICES **PeiServices,
69 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
70 IN VOID *Ppi
71 )
72{
73 USB_UHC_DEV *Uhc;
74
75 Uhc = PEI_RECOVERY_USB_UHC_DEV_FROM_THIS_NOTIFY (NotifyDescriptor);
76
77 //
78 // Stop the Host Controller
79 //
80 UhciStopHc (Uhc, 1000 * 1000);
81
82 return EFI_SUCCESS;
83}
84
96EFIAPI
98 IN EFI_PEI_FILE_HANDLE FileHandle,
99 IN CONST EFI_PEI_SERVICES **PeiServices
100 )
101{
102 PEI_USB_CONTROLLER_PPI *ChipSetUsbControllerPpi;
103 EFI_STATUS Status;
104 UINT8 Index;
105 UINTN ControllerType;
106 UINTN BaseAddress;
107 UINTN MemPages;
108 USB_UHC_DEV *UhcDev;
109 EFI_PHYSICAL_ADDRESS TempPtr;
110
111 //
112 // Shadow this PEIM to run from memory
113 //
114 if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {
115 return EFI_SUCCESS;
116 }
117
118 Status = PeiServicesLocatePpi (
119 &gPeiUsbControllerPpiGuid,
120 0,
121 NULL,
122 (VOID **)&ChipSetUsbControllerPpi
123 );
124 //
125 // If failed to locate, it is a bug in dispather as depex has gPeiUsbControllerPpiGuid.
126 //
127 ASSERT_EFI_ERROR (Status);
128
129 Index = 0;
130 while (TRUE) {
131 Status = ChipSetUsbControllerPpi->GetUsbController (
132 (EFI_PEI_SERVICES **)PeiServices,
133 ChipSetUsbControllerPpi,
134 Index,
135 &ControllerType,
136 &BaseAddress
137 );
138 //
139 // When status is error, meant no controller is found
140 //
141 if (EFI_ERROR (Status)) {
142 break;
143 }
144
145 //
146 // This PEIM is for UHC type controller.
147 //
148 if (ControllerType != PEI_UHCI_CONTROLLER) {
149 Index++;
150 continue;
151 }
152
153 MemPages = sizeof (USB_UHC_DEV) / EFI_PAGE_SIZE + 1;
154
155 Status = PeiServicesAllocatePages (
157 MemPages,
158 &TempPtr
159 );
160 if (EFI_ERROR (Status)) {
161 return EFI_OUT_OF_RESOURCES;
162 }
163
164 UhcDev = (USB_UHC_DEV *)((UINTN)TempPtr);
165 UhcDev->Signature = USB_UHC_DEV_SIGNATURE;
166 IoMmuInit (&UhcDev->IoMmu);
167 UhcDev->UsbHostControllerBaseAddress = (UINT32)BaseAddress;
168
169 //
170 // Init local memory management service
171 //
172 Status = InitializeMemoryManagement (UhcDev);
173 if (EFI_ERROR (Status)) {
174 return Status;
175 }
176
177 //
178 // Initialize Uhc's hardware
179 //
180 Status = InitializeUsbHC (UhcDev);
181 if (EFI_ERROR (Status)) {
182 return Status;
183 }
184
185 UhcDev->UsbHostControllerPpi.ControlTransfer = UhcControlTransfer;
186 UhcDev->UsbHostControllerPpi.BulkTransfer = UhcBulkTransfer;
187 UhcDev->UsbHostControllerPpi.GetRootHubPortNumber = UhcGetRootHubPortNumber;
188 UhcDev->UsbHostControllerPpi.GetRootHubPortStatus = UhcGetRootHubPortStatus;
189 UhcDev->UsbHostControllerPpi.SetRootHubPortFeature = UhcSetRootHubPortFeature;
190 UhcDev->UsbHostControllerPpi.ClearRootHubPortFeature = UhcClearRootHubPortFeature;
191
192 UhcDev->PpiDescriptor.Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);
193 UhcDev->PpiDescriptor.Guid = &gPeiUsbHostControllerPpiGuid;
194 UhcDev->PpiDescriptor.Ppi = &UhcDev->UsbHostControllerPpi;
195
196 Status = PeiServicesInstallPpi (&UhcDev->PpiDescriptor);
197 if (EFI_ERROR (Status)) {
198 Index++;
199 continue;
200 }
201
202 UhcDev->EndOfPeiNotifyList.Flags = (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);
203 UhcDev->EndOfPeiNotifyList.Guid = &gEfiEndOfPeiSignalPpiGuid;
204 UhcDev->EndOfPeiNotifyList.Notify = UhcEndOfPei;
205
206 PeiServicesNotifyPpi (&UhcDev->EndOfPeiNotifyList);
207
208 Index++;
209 }
210
211 return EFI_SUCCESS;
212}
213
240EFIAPI
242 IN EFI_PEI_SERVICES **PeiServices,
244 IN UINT8 DeviceAddress,
245 IN UINT8 DeviceSpeed,
246 IN UINT8 MaximumPacketLength,
247 IN EFI_USB_DEVICE_REQUEST *Request,
248 IN EFI_USB_DATA_DIRECTION TransferDirection,
249 IN OUT VOID *Data OPTIONAL,
250 IN OUT UINTN *DataLength OPTIONAL,
251 IN UINTN TimeOut,
252 OUT UINT32 *TransferResult
253 )
254{
255 USB_UHC_DEV *UhcDev;
256 UINT32 StatusReg;
257 UINT8 PktID;
258 QH_STRUCT *PtrQH;
259 TD_STRUCT *PtrTD;
260 TD_STRUCT *PtrPreTD;
261 TD_STRUCT *PtrSetupTD;
262 TD_STRUCT *PtrStatusTD;
263 EFI_STATUS Status;
264 UINT32 DataLen;
265 UINT8 DataToggle;
266 UINT8 *RequestPhy;
267 VOID *RequestMap;
268 UINT8 *DataPhy;
269 VOID *DataMap;
270
271 UhcDev = PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This);
272
273 StatusReg = UhcDev->UsbHostControllerBaseAddress + USBSTS;
274
275 PktID = INPUT_PACKET_ID;
276
277 RequestMap = NULL;
278
279 if ((Request == NULL) || (TransferResult == NULL)) {
280 return EFI_INVALID_PARAMETER;
281 }
282
283 //
284 // if errors exist that cause host controller halt,
285 // then return EFI_DEVICE_ERROR.
286 //
287
288 if (!IsStatusOK (UhcDev, StatusReg)) {
289 ClearStatusReg (UhcDev, StatusReg);
290 *TransferResult = EFI_USB_ERR_SYSTEM;
291 return EFI_DEVICE_ERROR;
292 }
293
294 ClearStatusReg (UhcDev, StatusReg);
295
296 //
297 // Map the Request and data for bus master access,
298 // then create a list of TD for this transfer
299 //
300 Status = UhciMapUserRequest (UhcDev, Request, &RequestPhy, &RequestMap);
301 if (EFI_ERROR (Status)) {
302 return Status;
303 }
304
305 Status = UhciMapUserData (UhcDev, TransferDirection, Data, DataLength, &PktID, &DataPhy, &DataMap);
306
307 if (EFI_ERROR (Status)) {
308 if (RequestMap != NULL) {
309 IoMmuUnmap (UhcDev->IoMmu, RequestMap);
310 }
311
312 return Status;
313 }
314
315 //
316 // generate Setup Stage TD
317 //
318
319 PtrQH = UhcDev->ConfigQH;
320
322 UhcDev,
323 DeviceAddress,
324 0,
325 DeviceSpeed,
326 (UINT8 *)Request,
327 RequestPhy,
328 (UINT8)sizeof (EFI_USB_DEVICE_REQUEST),
329 &PtrSetupTD
330 );
331
332 //
333 // link setup TD structures to QH structure
334 //
335 LinkTDToQH (PtrQH, PtrSetupTD);
336
337 PtrPreTD = PtrSetupTD;
338
339 //
340 // Data Stage of Control Transfer
341 //
342
343 if (TransferDirection == EfiUsbNoData) {
344 DataLen = 0;
345 } else {
346 DataLen = (UINT32)*DataLength;
347 }
348
349 DataToggle = 1;
350
351 PtrTD = PtrSetupTD;
352 while (DataLen > 0) {
353 //
354 // create TD structures and link together
355 //
356 UINT8 PacketSize;
357
358 //
359 // PacketSize is the data load size of each TD carries.
360 //
361 PacketSize = (UINT8)DataLen;
362 if (DataLen > MaximumPacketLength) {
363 PacketSize = MaximumPacketLength;
364 }
365
366 GenDataTD (
367 UhcDev,
368 DeviceAddress,
369 0,
370 Data,
371 DataPhy,
372 PacketSize,
373 PktID,
374 DataToggle,
375 DeviceSpeed,
376 &PtrTD
377 );
378
379 //
380 // Link two TDs in vertical depth
381 //
382 LinkTDToTD (PtrPreTD, PtrTD);
383 PtrPreTD = PtrTD;
384
385 DataToggle ^= 1;
386 Data = (VOID *)((UINT8 *)Data + PacketSize);
387 DataPhy += PacketSize;
388 DataLen -= PacketSize;
389 }
390
391 //
392 // PtrPreTD points to the last TD before the Setup-Stage TD.
393 //
394 PtrPreTD = PtrTD;
395
396 //
397 // Status Stage of Control Transfer
398 //
399 if (PktID == OUTPUT_PACKET_ID) {
400 PktID = INPUT_PACKET_ID;
401 } else {
402 PktID = OUTPUT_PACKET_ID;
403 }
404
405 //
406 // create Status Stage TD structure
407 //
409 UhcDev,
410 DeviceAddress,
411 0,
412 PktID,
413 DeviceSpeed,
414 &PtrStatusTD
415 );
416
417 LinkTDToTD (PtrPreTD, PtrStatusTD);
418
419 //
420 // Poll QH-TDs execution and get result.
421 // detail status is returned
422 //
423 Status = ExecuteControlTransfer (
424 UhcDev,
425 PtrSetupTD,
426 DataLength,
427 TimeOut,
428 TransferResult
429 );
430
431 //
432 // TRUE means must search other framelistindex
433 //
435 DeleteQueuedTDs (UhcDev, PtrSetupTD);
436
437 //
438 // if has errors that cause host controller halt, then return EFI_DEVICE_ERROR directly.
439 //
440 if (!IsStatusOK (UhcDev, StatusReg)) {
441 *TransferResult |= EFI_USB_ERR_SYSTEM;
442 Status = EFI_DEVICE_ERROR;
443 }
444
445 ClearStatusReg (UhcDev, StatusReg);
446
447 if (DataMap != NULL) {
448 IoMmuUnmap (UhcDev->IoMmu, DataMap);
449 }
450
451 if (RequestMap != NULL) {
452 IoMmuUnmap (UhcDev->IoMmu, RequestMap);
453 }
454
455 return Status;
456}
457
488EFIAPI
490 IN EFI_PEI_SERVICES **PeiServices,
492 IN UINT8 DeviceAddress,
493 IN UINT8 EndPointAddress,
494 IN UINT8 MaximumPacketLength,
495 IN OUT VOID *Data,
496 IN OUT UINTN *DataLength,
497 IN OUT UINT8 *DataToggle,
498 IN UINTN TimeOut,
499 OUT UINT32 *TransferResult
500 )
501{
502 USB_UHC_DEV *UhcDev;
503 UINT32 StatusReg;
504
505 UINT32 DataLen;
506
507 QH_STRUCT *PtrQH;
508 TD_STRUCT *PtrFirstTD;
509 TD_STRUCT *PtrTD;
510 TD_STRUCT *PtrPreTD;
511
512 UINT8 PktID;
513
514 BOOLEAN IsFirstTD;
515
516 EFI_STATUS Status;
517
518 EFI_USB_DATA_DIRECTION TransferDirection;
519
520 BOOLEAN ShortPacketEnable;
521
522 UINT16 CommandContent;
523
524 UINT8 *DataPhy;
525 VOID *DataMap;
526
527 UhcDev = PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This);
528
529 //
530 // Enable the maximum packet size (64bytes)
531 // that can be used for full speed bandwidth reclamation
532 // at the end of a frame.
533 //
534 CommandContent = USBReadPortW (UhcDev, UhcDev->UsbHostControllerBaseAddress + USBCMD);
535 if ((CommandContent & USBCMD_MAXP) != USBCMD_MAXP) {
536 CommandContent |= USBCMD_MAXP;
537 USBWritePortW (UhcDev, UhcDev->UsbHostControllerBaseAddress + USBCMD, CommandContent);
538 }
539
540 StatusReg = UhcDev->UsbHostControllerBaseAddress + USBSTS;
541
542 //
543 // these code lines are added here per complier's strict demand
544 //
545 PktID = INPUT_PACKET_ID;
546 PtrTD = NULL;
547 PtrFirstTD = NULL;
548 PtrPreTD = NULL;
549 DataLen = 0;
550
551 ShortPacketEnable = FALSE;
552
553 if ((DataLength == 0) || (Data == NULL) || (TransferResult == NULL)) {
554 return EFI_INVALID_PARAMETER;
555 }
556
557 if ((*DataToggle != 1) && (*DataToggle != 0)) {
558 return EFI_INVALID_PARAMETER;
559 }
560
561 if ( (MaximumPacketLength != 8) && (MaximumPacketLength != 16)
562 && (MaximumPacketLength != 32) && (MaximumPacketLength != 64))
563 {
564 return EFI_INVALID_PARAMETER;
565 }
566
567 //
568 // if has errors that cause host controller halt, then return EFI_DEVICE_ERROR directly.
569 //
570 if (!IsStatusOK (UhcDev, StatusReg)) {
571 ClearStatusReg (UhcDev, StatusReg);
572 *TransferResult = EFI_USB_ERR_SYSTEM;
573 return EFI_DEVICE_ERROR;
574 }
575
576 ClearStatusReg (UhcDev, StatusReg);
577
578 //
579 // Map the source data buffer for bus master access,
580 // then create a list of TDs
581 //
582 if ((EndPointAddress & 0x80) != 0) {
583 TransferDirection = EfiUsbDataIn;
584 } else {
585 TransferDirection = EfiUsbDataOut;
586 }
587
588 Status = UhciMapUserData (UhcDev, TransferDirection, Data, DataLength, &PktID, &DataPhy, &DataMap);
589
590 if (EFI_ERROR (Status)) {
591 return Status;
592 }
593
594 DataLen = (UINT32)*DataLength;
595
596 PtrQH = UhcDev->BulkQH;
597
598 IsFirstTD = TRUE;
599 while (DataLen > 0) {
600 //
601 // create TD structures and link together
602 //
603 UINT8 PacketSize;
604
605 PacketSize = (UINT8)DataLen;
606 if (DataLen > MaximumPacketLength) {
607 PacketSize = MaximumPacketLength;
608 }
609
610 GenDataTD (
611 UhcDev,
612 DeviceAddress,
613 EndPointAddress,
614 Data,
615 DataPhy,
616 PacketSize,
617 PktID,
618 *DataToggle,
619 USB_FULL_SPEED_DEVICE,
620 &PtrTD
621 );
622
623 //
624 // Enable short packet detection.
625 // (default action is disabling short packet detection)
626 //
627 if (ShortPacketEnable) {
629 }
630
631 if (IsFirstTD) {
632 PtrFirstTD = PtrTD;
633 PtrFirstTD->PtrNextTD = NULL;
634 IsFirstTD = FALSE;
635 } else {
636 //
637 // Link two TDs in vertical depth
638 //
639 LinkTDToTD (PtrPreTD, PtrTD);
640 }
641
642 PtrPreTD = PtrTD;
643
644 *DataToggle ^= 1;
645 Data = (VOID *)((UINT8 *)Data + PacketSize);
646 DataPhy += PacketSize;
647 DataLen -= PacketSize;
648 }
649
650 //
651 // link TD structures to QH structure
652 //
653 LinkTDToQH (PtrQH, PtrFirstTD);
654
655 //
656 // Execute QH-TD and get result
657 //
658 //
659 // detail status is put into the Result field in the pIRP
660 // the Data Toggle value is also re-updated to the value
661 // of the last successful TD
662 //
663 Status = ExecBulkTransfer (
664 UhcDev,
665 PtrFirstTD,
666 DataLength,
667 DataToggle,
668 TimeOut,
669 TransferResult
670 );
671
672 //
673 // Delete Bulk transfer TD structure
674 //
675 DeleteQueuedTDs (UhcDev, PtrFirstTD);
676
677 //
678 // if has errors that cause host controller halt, then return EFI_DEVICE_ERROR directly.
679 //
680 if (!IsStatusOK (UhcDev, StatusReg)) {
681 *TransferResult |= EFI_USB_ERR_SYSTEM;
682 Status = EFI_DEVICE_ERROR;
683 }
684
685 ClearStatusReg (UhcDev, StatusReg);
686
687 if (DataMap != NULL) {
688 IoMmuUnmap (UhcDev->IoMmu, DataMap);
689 }
690
691 return Status;
692}
693
707EFIAPI
709 IN EFI_PEI_SERVICES **PeiServices,
711 OUT UINT8 *PortNumber
712 )
713{
714 USB_UHC_DEV *UhcDev;
715 UINT32 PSAddr;
716 UINT16 RHPortControl;
717 UINT32 Index;
718
719 UhcDev = PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This);
720
721 if (PortNumber == NULL) {
722 return EFI_INVALID_PARAMETER;
723 }
724
725 *PortNumber = 0;
726
727 for (Index = 0; Index < 2; Index++) {
728 PSAddr = UhcDev->UsbHostControllerBaseAddress + USBPORTSC1 + Index * 2;
729 RHPortControl = USBReadPortW (UhcDev, PSAddr);
730 //
731 // Port Register content is valid
732 //
733 if (RHPortControl != 0xff) {
734 (*PortNumber)++;
735 }
736 }
737
738 return EFI_SUCCESS;
739}
740
755EFIAPI
757 IN EFI_PEI_SERVICES **PeiServices,
759 IN UINT8 PortNumber,
760 OUT EFI_USB_PORT_STATUS *PortStatus
761 )
762{
763 USB_UHC_DEV *UhcDev;
764 UINT32 PSAddr;
765 UINT16 RHPortStatus;
766 UINT8 TotalPortNumber;
767
768 if (PortStatus == NULL) {
769 return EFI_INVALID_PARAMETER;
770 }
771
772 UhcGetRootHubPortNumber (PeiServices, This, &TotalPortNumber);
773 if (PortNumber > TotalPortNumber) {
774 return EFI_INVALID_PARAMETER;
775 }
776
777 UhcDev = PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This);
778 PSAddr = UhcDev->UsbHostControllerBaseAddress + USBPORTSC1 + PortNumber * 2;
779
780 PortStatus->PortStatus = 0;
781 PortStatus->PortChangeStatus = 0;
782
783 RHPortStatus = USBReadPortW (UhcDev, PSAddr);
784
785 //
786 // Current Connect Status
787 //
788 if ((RHPortStatus & USBPORTSC_CCS) != 0) {
789 PortStatus->PortStatus |= USB_PORT_STAT_CONNECTION;
790 }
791
792 //
793 // Port Enabled/Disabled
794 //
795 if ((RHPortStatus & USBPORTSC_PED) != 0) {
796 PortStatus->PortStatus |= USB_PORT_STAT_ENABLE;
797 }
798
799 //
800 // Port Suspend
801 //
802 if ((RHPortStatus & USBPORTSC_SUSP) != 0) {
803 PortStatus->PortStatus |= USB_PORT_STAT_SUSPEND;
804 }
805
806 //
807 // Port Reset
808 //
809 if ((RHPortStatus & USBPORTSC_PR) != 0) {
810 PortStatus->PortStatus |= USB_PORT_STAT_RESET;
811 }
812
813 //
814 // Low Speed Device Attached
815 //
816 if ((RHPortStatus & USBPORTSC_LSDA) != 0) {
817 PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;
818 }
819
820 //
821 // Fill Port Status Change bits
822 //
823 //
824 // Connect Status Change
825 //
826 if ((RHPortStatus & USBPORTSC_CSC) != 0) {
827 PortStatus->PortChangeStatus |= USB_PORT_STAT_C_CONNECTION;
828 }
829
830 //
831 // Port Enabled/Disabled Change
832 //
833 if ((RHPortStatus & USBPORTSC_PEDC) != 0) {
834 PortStatus->PortChangeStatus |= USB_PORT_STAT_C_ENABLE;
835 }
836
837 return EFI_SUCCESS;
838}
839
854EFIAPI
856 IN EFI_PEI_SERVICES **PeiServices,
858 IN UINT8 PortNumber,
859 IN EFI_USB_PORT_FEATURE PortFeature
860 )
861{
862 USB_UHC_DEV *UhcDev;
863 UINT32 PSAddr;
864 UINT32 CommandRegAddr;
865 UINT16 RHPortControl;
866 UINT8 TotalPortNumber;
867
868 UhcGetRootHubPortNumber (PeiServices, This, &TotalPortNumber);
869 if (PortNumber > TotalPortNumber) {
870 return EFI_INVALID_PARAMETER;
871 }
872
873 UhcDev = PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This);
874 PSAddr = UhcDev->UsbHostControllerBaseAddress + USBPORTSC1 + PortNumber * 2;
875 CommandRegAddr = UhcDev->UsbHostControllerBaseAddress + USBCMD;
876
877 RHPortControl = USBReadPortW (UhcDev, PSAddr);
878
879 switch (PortFeature) {
880 case EfiUsbPortSuspend:
881 if ((USBReadPortW (UhcDev, CommandRegAddr) & USBCMD_EGSM) == 0) {
882 //
883 // if global suspend is not active, can set port suspend
884 //
885 RHPortControl &= 0xfff5;
886 RHPortControl |= USBPORTSC_SUSP;
887 }
888
889 break;
890
891 case EfiUsbPortReset:
892 RHPortControl &= 0xfff5;
893 RHPortControl |= USBPORTSC_PR;
894 //
895 // Set the reset bit
896 //
897 break;
898
899 case EfiUsbPortPower:
900 break;
901
902 case EfiUsbPortEnable:
903 RHPortControl &= 0xfff5;
904 RHPortControl |= USBPORTSC_PED;
905 break;
906
907 default:
908 return EFI_INVALID_PARAMETER;
909 }
910
911 USBWritePortW (UhcDev, PSAddr, RHPortControl);
912
913 return EFI_SUCCESS;
914}
915
932EFIAPI
934 IN EFI_PEI_SERVICES **PeiServices,
936 IN UINT8 PortNumber,
937 IN EFI_USB_PORT_FEATURE PortFeature
938 )
939{
940 USB_UHC_DEV *UhcDev;
941 UINT32 PSAddr;
942 UINT16 RHPortControl;
943 UINT8 TotalPortNumber;
944
945 UhcGetRootHubPortNumber (PeiServices, This, &TotalPortNumber);
946
947 if (PortNumber > TotalPortNumber) {
948 return EFI_INVALID_PARAMETER;
949 }
950
951 UhcDev = PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This);
952 PSAddr = UhcDev->UsbHostControllerBaseAddress + USBPORTSC1 + PortNumber * 2;
953
954 RHPortControl = USBReadPortW (UhcDev, PSAddr);
955
956 switch (PortFeature) {
957 //
958 // clear PORT_ENABLE feature means disable port.
959 //
960 case EfiUsbPortEnable:
961 RHPortControl &= 0xfff5;
962 RHPortControl &= ~USBPORTSC_PED;
963 break;
964
965 //
966 // clear PORT_SUSPEND feature means resume the port.
967 // (cause a resume on the specified port if in suspend mode)
968 //
969 case EfiUsbPortSuspend:
970 RHPortControl &= 0xfff5;
971 RHPortControl &= ~USBPORTSC_SUSP;
972 break;
973
974 //
975 // no operation
976 //
977 case EfiUsbPortPower:
978 break;
979
980 //
981 // clear PORT_RESET means clear the reset signal.
982 //
983 case EfiUsbPortReset:
984 RHPortControl &= 0xfff5;
985 RHPortControl &= ~USBPORTSC_PR;
986 break;
987
988 //
989 // clear connect status change
990 //
991 case EfiUsbPortConnectChange:
992 RHPortControl &= 0xfff5;
993 RHPortControl |= USBPORTSC_CSC;
994 break;
995
996 //
997 // clear enable/disable status change
998 //
999 case EfiUsbPortEnableChange:
1000 RHPortControl &= 0xfff5;
1001 RHPortControl |= USBPORTSC_PEDC;
1002 break;
1003
1004 //
1005 // root hub does not support this request
1006 //
1007 case EfiUsbPortSuspendChange:
1008 break;
1009
1010 //
1011 // root hub does not support this request
1012 //
1013 case EfiUsbPortOverCurrentChange:
1014 break;
1015
1016 //
1017 // root hub does not support this request
1018 //
1019 case EfiUsbPortResetChange:
1020 break;
1021
1022 default:
1023 return EFI_INVALID_PARAMETER;
1024 }
1025
1026 USBWritePortW (UhcDev, PSAddr, RHPortControl);
1027
1028 return EFI_SUCCESS;
1029}
1030
1042 IN USB_UHC_DEV *UhcDev
1043 )
1044{
1045 EFI_STATUS Status;
1046 UINT32 FrameListBaseAddrReg;
1047 UINT32 CommandReg;
1048 UINT16 Command;
1049
1050 //
1051 // Create and Initialize Frame List For the Host Controller.
1052 //
1053 Status = CreateFrameList (UhcDev);
1054 if (EFI_ERROR (Status)) {
1055 return Status;
1056 }
1057
1058 FrameListBaseAddrReg = UhcDev->UsbHostControllerBaseAddress + USBFLBASEADD;
1059 CommandReg = UhcDev->UsbHostControllerBaseAddress + USBCMD;
1060
1061 //
1062 // Set Frame List Base Address to the specific register to inform the hardware.
1063 //
1064 SetFrameListBaseAddress (UhcDev, FrameListBaseAddrReg, (UINT32)(UINTN)(UhcDev->FrameListEntry));
1065
1066 Command = USBReadPortW (UhcDev, CommandReg);
1067 Command |= USBCMD_GRESET;
1068 USBWritePortW (UhcDev, CommandReg, Command);
1069
1070 MicroSecondDelay (50 * 1000);
1071
1072 Command &= ~USBCMD_GRESET;
1073
1074 USBWritePortW (UhcDev, CommandReg, Command);
1075
1076 //
1077 // UHCI spec page120 reset recovery time
1078 //
1079 MicroSecondDelay (20 * 1000);
1080
1081 //
1082 // Set Run/Stop bit to 1.
1083 //
1084 Command = USBReadPortW (UhcDev, CommandReg);
1085 Command |= USBCMD_RS | USBCMD_MAXP;
1086 USBWritePortW (UhcDev, CommandReg, Command);
1087
1088 return EFI_SUCCESS;
1089}
1090
1102 USB_UHC_DEV *UhcDev
1103 )
1104{
1105 EFI_STATUS Status;
1106 EFI_PHYSICAL_ADDRESS FrameListBaseAddr;
1107 FRAMELIST_ENTRY *FrameListPtr;
1108 UINTN Index;
1109
1110 //
1111 // The Frame List ocupies 4K bytes,
1112 // and must be aligned on 4-Kbyte boundaries.
1113 //
1114 Status = PeiServicesAllocatePages (
1116 1,
1117 &FrameListBaseAddr
1118 );
1119
1120 if (Status != EFI_SUCCESS) {
1121 return EFI_OUT_OF_RESOURCES;
1122 }
1123
1124 //
1125 // Create Control QH and Bulk QH and link them into Framelist Entry
1126 //
1127 Status = CreateQH (UhcDev, &UhcDev->ConfigQH);
1128 if (Status != EFI_SUCCESS) {
1129 return EFI_OUT_OF_RESOURCES;
1130 }
1131
1132 ASSERT (UhcDev->ConfigQH != NULL);
1133
1134 Status = CreateQH (UhcDev, &UhcDev->BulkQH);
1135 if (Status != EFI_SUCCESS) {
1136 return EFI_OUT_OF_RESOURCES;
1137 }
1138
1139 ASSERT (UhcDev->BulkQH != NULL);
1140
1141 //
1142 // Set the corresponding QH pointer
1143 //
1144 SetQHHorizontalLinkPtr (UhcDev->ConfigQH, UhcDev->BulkQH);
1145 SetQHHorizontalQHorTDSelect (UhcDev->ConfigQH, TRUE);
1146 SetQHHorizontalValidorInvalid (UhcDev->ConfigQH, TRUE);
1147
1148 UhcDev->FrameListEntry = (FRAMELIST_ENTRY *)((UINTN)FrameListBaseAddr);
1149
1150 FrameListPtr = UhcDev->FrameListEntry;
1151
1152 for (Index = 0; Index < 1024; Index++) {
1153 FrameListPtr->FrameListPtrTerminate = 0;
1154 FrameListPtr->FrameListPtr = (UINT32)(UINTN)UhcDev->ConfigQH >> 4;
1155 FrameListPtr->FrameListPtrQSelect = 1;
1156 FrameListPtr->FrameListRsvd = 0;
1157 FrameListPtr++;
1158 }
1159
1160 return EFI_SUCCESS;
1161}
1162
1172UINT16
1174 IN USB_UHC_DEV *UhcDev,
1175 IN UINT32 Port
1176 )
1177{
1178 return IoRead16 (Port);
1179}
1180
1189VOID
1191 IN USB_UHC_DEV *UhcDev,
1192 IN UINT32 Port,
1193 IN UINT16 Data
1194 )
1195{
1196 IoWrite16 (Port, Data);
1197}
1198
1207VOID
1209 IN USB_UHC_DEV *UhcDev,
1210 IN UINT32 Port,
1211 IN UINT32 Data
1212 )
1213{
1214 IoWrite32 (Port, Data);
1215}
1216
1224VOID
1226 IN USB_UHC_DEV *UhcDev,
1227 IN UINT32 StatusAddr
1228 )
1229{
1230 //
1231 // Clear the content of UHCI's Status Register
1232 //
1233 USBWritePortW (UhcDev, StatusAddr, 0x003F);
1234}
1235
1246BOOLEAN
1248 IN USB_UHC_DEV *UhcDev,
1249 IN UINT32 StatusRegAddr
1250 )
1251{
1252 UINT16 StatusValue;
1253
1254 StatusValue = USBReadPortW (UhcDev, StatusRegAddr);
1255
1256 if ((StatusValue & (USBSTS_HCPE | USBSTS_HSE | USBSTS_HCH)) != 0) {
1257 return FALSE;
1258 } else {
1259 return TRUE;
1260 }
1261}
1262
1271VOID
1273 IN USB_UHC_DEV *UhcDev,
1274 IN UINT32 FrameListRegAddr,
1275 IN UINT32 Addr
1276 )
1277{
1278 //
1279 // Sets value in the USB Frame List Base Address register.
1280 //
1281 USBWritePortDW (UhcDev, FrameListRegAddr, (UINT32)(Addr & 0xFFFFF000));
1282}
1283
1296 IN USB_UHC_DEV *UhcDev,
1297 OUT QH_STRUCT **PtrQH
1298 )
1299{
1300 EFI_STATUS Status;
1301
1302 //
1303 // allocate align memory for QH_STRUCT
1304 //
1305 Status = AllocateTDorQHStruct (UhcDev, sizeof (QH_STRUCT), (void **)PtrQH);
1306 if (EFI_ERROR (Status)) {
1307 return EFI_OUT_OF_RESOURCES;
1308 }
1309
1310 //
1311 // init each field of the QH_STRUCT
1312 //
1315
1316 return EFI_SUCCESS;
1317}
1318
1326VOID
1328 IN QH_STRUCT *PtrQH,
1329 IN VOID *PtrNext
1330 )
1331{
1332 //
1333 // Since the QH_STRUCT is aligned on 16-byte boundaries,
1334 // Only the highest 28bit of the address is valid
1335 // (take 32bit address as an example).
1336 //
1337 PtrQH->QueueHead.QHHorizontalPtr = (UINT32)(UINTN)PtrNext >> 4;
1338}
1339
1347VOID
1349 IN QH_STRUCT *PtrQH,
1350 IN BOOLEAN IsQH
1351 )
1352{
1353 //
1354 // if QH is connected, the specified bit is set,
1355 // if TD is connected, the specified bit is cleared.
1356 //
1357 PtrQH->QueueHead.QHHorizontalQSelect = IsQH ? 1 : 0;
1358}
1359
1367VOID
1369 IN QH_STRUCT *PtrQH,
1370 IN BOOLEAN IsValid
1371 )
1372{
1373 //
1374 // Valid means the horizontal link pointer is valid,
1375 // else, it's invalid.
1376 //
1377 PtrQH->QueueHead.QHHorizontalTerminate = IsValid ? 0 : 1;
1378}
1379
1387VOID
1389 IN QH_STRUCT *PtrQH,
1390 IN VOID *PtrNext
1391 )
1392{
1393 //
1394 // Since the QH_STRUCT is aligned on 16-byte boundaries,
1395 // Only the highest 28bit of the address is valid
1396 // (take 32bit address as an example).
1397 //
1398 PtrQH->QueueHead.QHVerticalPtr = (UINT32)(UINTN)PtrNext >> 4;
1399}
1400
1408VOID
1410 IN QH_STRUCT *PtrQH,
1411 IN BOOLEAN IsQH
1412 )
1413{
1414 //
1415 // Set the specified bit if the Vertical Link Pointer pointing to a QH,
1416 // Clear the specified bit if the Vertical Link Pointer pointing to a TD.
1417 //
1418 PtrQH->QueueHead.QHVerticalQSelect = IsQH ? 1 : 0;
1419}
1420
1428VOID
1430 IN QH_STRUCT *PtrQH,
1431 IN BOOLEAN IsValid
1432 )
1433{
1434 //
1435 // If TRUE, meaning the Vertical Link Pointer field is valid,
1436 // else, the field is invalid.
1437 //
1438 PtrQH->QueueHead.QHVerticalTerminate = IsValid ? 0 : 1;
1439}
1440
1454 IN USB_UHC_DEV *UhcDev,
1455 IN UINT32 Size,
1456 OUT VOID **PtrStruct
1457 )
1458{
1459 EFI_STATUS Status;
1460
1461 Status = EFI_SUCCESS;
1462 *PtrStruct = NULL;
1463
1464 Status = UhcAllocatePool (
1465 UhcDev,
1466 (UINT8 **)PtrStruct,
1467 Size
1468 );
1469 if (EFI_ERROR (Status)) {
1470 return Status;
1471 }
1472
1473 ZeroMem (*PtrStruct, Size);
1474
1475 return Status;
1476}
1477
1490 IN USB_UHC_DEV *UhcDev,
1491 OUT TD_STRUCT **PtrTD
1492 )
1493{
1494 EFI_STATUS Status;
1495
1496 //
1497 // create memory for TD_STRUCT, and align the memory.
1498 //
1499 Status = AllocateTDorQHStruct (UhcDev, sizeof (TD_STRUCT), (void **)PtrTD);
1500 if (EFI_ERROR (Status)) {
1501 return Status;
1502 }
1503
1504 //
1505 // Make TD ready.
1506 //
1508
1509 return EFI_SUCCESS;
1510}
1511
1530 IN USB_UHC_DEV *UhcDev,
1531 IN UINT8 DevAddr,
1532 IN UINT8 Endpoint,
1533 IN UINT8 DeviceSpeed,
1534 IN UINT8 *DevRequest,
1535 IN UINT8 *RequestPhy,
1536 IN UINT8 RequestLen,
1537 OUT TD_STRUCT **PtrTD
1538 )
1539{
1540 TD_STRUCT *TdStruct;
1541 EFI_STATUS Status;
1542
1543 Status = CreateTD (UhcDev, &TdStruct);
1544 if (EFI_ERROR (Status)) {
1545 return Status;
1546 }
1547
1548 SetTDLinkPtr (TdStruct, NULL);
1549
1550 //
1551 // Depth first fashion
1552 //
1553 SetTDLinkPtrDepthorBreadth (TdStruct, TRUE);
1554
1555 //
1556 // initialize as the last TD in the QH context,
1557 // this field will be updated in the TD linkage process.
1558 //
1560
1561 //
1562 // Disable Short Packet Detection by default
1563 //
1565
1566 //
1567 // Max error counter is 3, retry 3 times when error encountered.
1568 //
1569 SetTDControlErrorCounter (TdStruct, 3);
1570
1571 //
1572 // set device speed attribute
1573 // (TRUE - Slow Device; FALSE - Full Speed Device)
1574 //
1575 switch (DeviceSpeed) {
1576 case USB_SLOW_SPEED_DEVICE:
1577 SetTDLoworFullSpeedDevice (TdStruct, TRUE);
1578 break;
1579
1580 case USB_FULL_SPEED_DEVICE:
1581 SetTDLoworFullSpeedDevice (TdStruct, FALSE);
1582 break;
1583 }
1584
1585 //
1586 // Non isochronous transfer TD
1587 //
1589
1590 //
1591 // Interrupt On Complete bit be set to zero,
1592 // Disable IOC interrupt.
1593 //
1594 SetorClearTDControlIOC (TdStruct, FALSE);
1595
1596 //
1597 // Set TD Active bit
1598 //
1600
1601 SetTDTokenMaxLength (TdStruct, RequestLen);
1602
1603 SetTDTokenDataToggle0 (TdStruct);
1604
1605 SetTDTokenEndPoint (TdStruct, Endpoint);
1606
1607 SetTDTokenDeviceAddress (TdStruct, DevAddr);
1608
1609 SetTDTokenPacketID (TdStruct, SETUP_PACKET_ID);
1610
1611 TdStruct->PtrTDBuffer = (UINT8 *)DevRequest;
1612 TdStruct->TDBufferLength = RequestLen;
1613 //
1614 // Set the beginning address of the buffer that will be used
1615 // during the transaction.
1616 //
1617 TdStruct->TDData.TDBufferPtr = (UINT32)(UINTN)RequestPhy;
1618
1619 *PtrTD = TdStruct;
1620
1621 return EFI_SUCCESS;
1622}
1623
1644 IN USB_UHC_DEV *UhcDev,
1645 IN UINT8 DevAddr,
1646 IN UINT8 Endpoint,
1647 IN UINT8 *PtrData,
1648 IN UINT8 *DataPhy,
1649 IN UINT8 Len,
1650 IN UINT8 PktID,
1651 IN UINT8 Toggle,
1652 IN UINT8 DeviceSpeed,
1653 OUT TD_STRUCT **PtrTD
1654 )
1655{
1656 TD_STRUCT *TdStruct;
1657 EFI_STATUS Status;
1658
1659 Status = CreateTD (UhcDev, &TdStruct);
1660 if (EFI_ERROR (Status)) {
1661 return Status;
1662 }
1663
1664 SetTDLinkPtr (TdStruct, NULL);
1665
1666 //
1667 // Depth first fashion
1668 //
1669 SetTDLinkPtrDepthorBreadth (TdStruct, TRUE);
1670
1671 //
1672 // Link pointer pointing to TD struct
1673 //
1674 SetTDLinkPtrQHorTDSelect (TdStruct, FALSE);
1675
1676 //
1677 // initialize as the last TD in the QH context,
1678 // this field will be updated in the TD linkage process.
1679 //
1681
1682 //
1683 // Disable short packet detect
1684 //
1686 //
1687 // Max error counter is 3
1688 //
1689 SetTDControlErrorCounter (TdStruct, 3);
1690
1691 //
1692 // set device speed attribute
1693 // (TRUE - Slow Device; FALSE - Full Speed Device)
1694 //
1695 switch (DeviceSpeed) {
1696 case USB_SLOW_SPEED_DEVICE:
1697 SetTDLoworFullSpeedDevice (TdStruct, TRUE);
1698 break;
1699
1700 case USB_FULL_SPEED_DEVICE:
1701 SetTDLoworFullSpeedDevice (TdStruct, FALSE);
1702 break;
1703 }
1704
1705 //
1706 // Non isochronous transfer TD
1707 //
1709
1710 //
1711 // Disable Interrupt On Complete
1712 // Disable IOC interrupt.
1713 //
1714 SetorClearTDControlIOC (TdStruct, FALSE);
1715
1716 //
1717 // Set Active bit
1718 //
1720
1721 SetTDTokenMaxLength (TdStruct, Len);
1722
1723 if (Toggle != 0) {
1724 SetTDTokenDataToggle1 (TdStruct);
1725 } else {
1726 SetTDTokenDataToggle0 (TdStruct);
1727 }
1728
1729 SetTDTokenEndPoint (TdStruct, Endpoint);
1730
1731 SetTDTokenDeviceAddress (TdStruct, DevAddr);
1732
1733 SetTDTokenPacketID (TdStruct, PktID);
1734
1735 TdStruct->PtrTDBuffer = (UINT8 *)PtrData;
1736 TdStruct->TDBufferLength = Len;
1737 //
1738 // Set the beginning address of the buffer that will be used
1739 // during the transaction.
1740 //
1741 TdStruct->TDData.TDBufferPtr = (UINT32)(UINTN)DataPhy;
1742
1743 *PtrTD = TdStruct;
1744
1745 return EFI_SUCCESS;
1746}
1747
1764 IN USB_UHC_DEV *UhcDev,
1765 IN UINT8 DevAddr,
1766 IN UINT8 Endpoint,
1767 IN UINT8 PktID,
1768 IN UINT8 DeviceSpeed,
1769 OUT TD_STRUCT **PtrTD
1770 )
1771{
1772 TD_STRUCT *PtrTDStruct;
1773 EFI_STATUS Status;
1774
1775 Status = CreateTD (UhcDev, &PtrTDStruct);
1776 if (EFI_ERROR (Status)) {
1777 return Status;
1778 }
1779
1780 SetTDLinkPtr (PtrTDStruct, NULL);
1781
1782 //
1783 // Depth first fashion
1784 //
1785 SetTDLinkPtrDepthorBreadth (PtrTDStruct, TRUE);
1786
1787 //
1788 // initialize as the last TD in the QH context,
1789 // this field will be updated in the TD linkage process.
1790 //
1791 SetTDLinkPtrValidorInvalid (PtrTDStruct, FALSE);
1792
1793 //
1794 // Disable short packet detect
1795 //
1796 EnableorDisableTDShortPacket (PtrTDStruct, FALSE);
1797
1798 //
1799 // Max error counter is 3
1800 //
1801 SetTDControlErrorCounter (PtrTDStruct, 3);
1802
1803 //
1804 // set device speed attribute
1805 // (TRUE - Slow Device; FALSE - Full Speed Device)
1806 //
1807 switch (DeviceSpeed) {
1808 case USB_SLOW_SPEED_DEVICE:
1809 SetTDLoworFullSpeedDevice (PtrTDStruct, TRUE);
1810 break;
1811
1812 case USB_FULL_SPEED_DEVICE:
1813 SetTDLoworFullSpeedDevice (PtrTDStruct, FALSE);
1814 break;
1815 }
1816
1817 //
1818 // Non isochronous transfer TD
1819 //
1820 SetTDControlIsochronousorNot (PtrTDStruct, FALSE);
1821
1822 //
1823 // Disable Interrupt On Complete
1824 // Disable IOC interrupt.
1825 //
1826 SetorClearTDControlIOC (PtrTDStruct, FALSE);
1827
1828 //
1829 // Set TD Active bit
1830 //
1831 SetTDStatusActiveorInactive (PtrTDStruct, TRUE);
1832
1833 SetTDTokenMaxLength (PtrTDStruct, 0);
1834
1835 SetTDTokenDataToggle1 (PtrTDStruct);
1836
1837 SetTDTokenEndPoint (PtrTDStruct, Endpoint);
1838
1839 SetTDTokenDeviceAddress (PtrTDStruct, DevAddr);
1840
1841 SetTDTokenPacketID (PtrTDStruct, PktID);
1842
1843 PtrTDStruct->PtrTDBuffer = NULL;
1844 PtrTDStruct->TDBufferLength = 0;
1845 //
1846 // Set the beginning address of the buffer that will be used
1847 // during the transaction.
1848 //
1849 PtrTDStruct->TDData.TDBufferPtr = 0;
1850
1851 *PtrTD = PtrTDStruct;
1852
1853 return EFI_SUCCESS;
1854}
1855
1863VOID
1865 IN TD_STRUCT *PtrTDStruct,
1866 IN BOOLEAN IsValid
1867 )
1868{
1869 //
1870 // Valid means the link pointer is valid,
1871 // else, it's invalid.
1872 //
1873 PtrTDStruct->TDData.TDLinkPtrTerminate = (IsValid ? 0 : 1);
1874}
1875
1883VOID
1885 IN TD_STRUCT *PtrTDStruct,
1886 IN BOOLEAN IsQH
1887 )
1888{
1889 //
1890 // Indicate whether the Link Pointer pointing to a QH or TD
1891 //
1892 PtrTDStruct->TDData.TDLinkPtrQSelect = (IsQH ? 1 : 0);
1893}
1894
1902VOID
1904 IN TD_STRUCT *PtrTDStruct,
1905 IN BOOLEAN IsDepth
1906 )
1907{
1908 //
1909 // If TRUE, indicating the host controller should process in depth first fashion,
1910 // else, the host controller should process in breadth first fashion
1911 //
1912 PtrTDStruct->TDData.TDLinkPtrDepthSelect = (IsDepth ? 1 : 0);
1913}
1914
1922VOID
1924 IN TD_STRUCT *PtrTDStruct,
1925 IN VOID *PtrNext
1926 )
1927{
1928 //
1929 // Set TD Link Pointer. Since QH,TD align on 16-byte boundaries,
1930 // only the highest 28 bits are valid. (if take 32bit address as an example)
1931 //
1932 PtrTDStruct->TDData.TDLinkPtr = (UINT32)(UINTN)PtrNext >> 4;
1933}
1934
1943VOID *
1945 IN TD_STRUCT *PtrTDStruct
1946 )
1947{
1948 //
1949 // Get TD Link Pointer. Restore it back to 32bit
1950 // (if take 32bit address as an example)
1951 //
1952 return (VOID *)(UINTN)((PtrTDStruct->TDData.TDLinkPtr) << 4);
1953}
1954
1962VOID
1964 IN TD_STRUCT *PtrTDStruct,
1965 IN BOOLEAN IsEnable
1966 )
1967{
1968 //
1969 // TRUE means enable short packet detection mechanism.
1970 //
1971 PtrTDStruct->TDData.TDStatusSPD = (IsEnable ? 1 : 0);
1972}
1973
1981VOID
1983 IN TD_STRUCT *PtrTDStruct,
1984 IN UINT8 MaxErrors
1985 )
1986{
1987 //
1988 // valid value of MaxErrors is 0,1,2,3
1989 //
1990 if (MaxErrors > 3) {
1991 MaxErrors = 3;
1992 }
1993
1994 PtrTDStruct->TDData.TDStatusErr = MaxErrors;
1995}
1996
2004VOID
2006 IN TD_STRUCT *PtrTDStruct,
2007 IN BOOLEAN IsLowSpeedDevice
2008 )
2009{
2010 //
2011 // TRUE means the TD is targeting at a Low-speed device
2012 //
2013 PtrTDStruct->TDData.TDStatusLS = (IsLowSpeedDevice ? 1 : 0);
2014}
2015
2023VOID
2025 IN TD_STRUCT *PtrTDStruct,
2026 IN BOOLEAN IsIsochronous
2027 )
2028{
2029 //
2030 // TRUE means the TD belongs to Isochronous transfer type.
2031 //
2032 PtrTDStruct->TDData.TDStatusIOS = (IsIsochronous ? 1 : 0);
2033}
2034
2043VOID
2045 IN TD_STRUCT *PtrTDStruct,
2046 IN BOOLEAN IsSet
2047 )
2048{
2049 //
2050 // If this bit is set, it indicates that the host controller should issue
2051 // an interrupt on completion of the frame in which this TD is executed.
2052 //
2053 PtrTDStruct->TDData.TDStatusIOC = IsSet ? 1 : 0;
2054}
2055
2063VOID
2065 IN TD_STRUCT *PtrTDStruct,
2066 IN BOOLEAN IsActive
2067 )
2068{
2069 //
2070 // If this bit is set, it indicates that the TD is active and can be
2071 // executed.
2072 //
2073 if (IsActive) {
2074 PtrTDStruct->TDData.TDStatus |= 0x80;
2075 } else {
2076 PtrTDStruct->TDData.TDStatus &= 0x7F;
2077 }
2078}
2079
2088UINT16
2090 IN TD_STRUCT *PtrTDStruct,
2091 IN UINT16 MaxLen
2092 )
2093{
2094 //
2095 // Specifies the maximum number of data bytes allowed for the transfer.
2096 // the legal value extent is 0 ~ 0x500.
2097 //
2098 if (MaxLen > 0x500) {
2099 MaxLen = 0x500;
2100 }
2101
2102 PtrTDStruct->TDData.TDTokenMaxLen = MaxLen - 1;
2103
2104 return MaxLen;
2105}
2106
2113VOID
2115 IN TD_STRUCT *PtrTDStruct
2116 )
2117{
2118 //
2119 // Set the data toggle bit to DATA1
2120 //
2121 PtrTDStruct->TDData.TDTokenDataToggle = 1;
2122}
2123
2130VOID
2132 IN TD_STRUCT *PtrTDStruct
2133 )
2134{
2135 //
2136 // Set the data toggle bit to DATA0
2137 //
2138 PtrTDStruct->TDData.TDTokenDataToggle = 0;
2139}
2140
2148VOID
2150 IN TD_STRUCT *PtrTDStruct,
2151 IN UINTN EndPoint
2152 )
2153{
2154 //
2155 // Set EndPoint Number the TD is targeting at.
2156 //
2157 PtrTDStruct->TDData.TDTokenEndPt = (UINT8)EndPoint;
2158}
2159
2167VOID
2169 IN TD_STRUCT *PtrTDStruct,
2170 IN UINTN DevAddr
2171 )
2172{
2173 //
2174 // Set Device Address the TD is targeting at.
2175 //
2176 PtrTDStruct->TDData.TDTokenDevAddr = (UINT8)DevAddr;
2177}
2178
2186VOID
2188 IN TD_STRUCT *PtrTDStruct,
2189 IN UINT8 PacketID
2190 )
2191{
2192 //
2193 // Set the Packet Identification to be used for this transaction.
2194 //
2195 PtrTDStruct->TDData.TDTokenPID = PacketID;
2196}
2197
2206BOOLEAN
2208 IN TD_STRUCT *PtrTDStruct
2209 )
2210{
2211 UINT8 TDStatus;
2212
2213 //
2214 // Detect whether the TD is active.
2215 //
2216 TDStatus = (UINT8)(PtrTDStruct->TDData.TDStatus);
2217 return (BOOLEAN)(TDStatus & 0x80);
2218}
2219
2228BOOLEAN
2230 IN TD_STRUCT *PtrTDStruct
2231 )
2232{
2233 UINT8 TDStatus;
2234
2235 //
2236 // Detect whether the device/endpoint addressed by this TD is stalled.
2237 //
2238 TDStatus = (UINT8)(PtrTDStruct->TDData.TDStatus);
2239 return (BOOLEAN)(TDStatus & 0x40);
2240}
2241
2250BOOLEAN
2252 IN TD_STRUCT *PtrTDStruct
2253 )
2254{
2255 UINT8 TDStatus;
2256
2257 //
2258 // Detect whether Data Buffer Error is happened.
2259 //
2260 TDStatus = (UINT8)(PtrTDStruct->TDData.TDStatus);
2261 return (BOOLEAN)(TDStatus & 0x20);
2262}
2263
2272BOOLEAN
2274 IN TD_STRUCT *PtrTDStruct
2275 )
2276{
2277 UINT8 TDStatus;
2278
2279 //
2280 // Detect whether Babble Error is happened.
2281 //
2282 TDStatus = (UINT8)(PtrTDStruct->TDData.TDStatus);
2283 return (BOOLEAN)(TDStatus & 0x10);
2284}
2285
2294BOOLEAN
2296 IN TD_STRUCT *PtrTDStruct
2297 )
2298{
2299 UINT8 TDStatus;
2300
2301 //
2302 // Detect whether NAK is received.
2303 //
2304 TDStatus = (UINT8)(PtrTDStruct->TDData.TDStatus);
2305 return (BOOLEAN)(TDStatus & 0x08);
2306}
2307
2316BOOLEAN
2318 IN TD_STRUCT *PtrTDStruct
2319 )
2320{
2321 UINT8 TDStatus;
2322
2323 //
2324 // Detect whether CRC/Time Out Error is encountered.
2325 //
2326 TDStatus = (UINT8)(PtrTDStruct->TDData.TDStatus);
2327 return (BOOLEAN)(TDStatus & 0x04);
2328}
2329
2338BOOLEAN
2340 IN TD_STRUCT *PtrTDStruct
2341 )
2342{
2343 UINT8 TDStatus;
2344
2345 //
2346 // Detect whether Bitstuff Error is received.
2347 //
2348 TDStatus = (UINT8)(PtrTDStruct->TDData.TDStatus);
2349 return (BOOLEAN)(TDStatus & 0x02);
2350}
2351
2360UINT16
2362 IN TD_STRUCT *PtrTDStruct
2363 )
2364{
2365 //
2366 // Retrieve the actual number of bytes that were tansferred.
2367 // the value is encoded as n-1. so return the decoded value.
2368 //
2369 return (UINT16)((PtrTDStruct->TDData.TDStatusActualLength) + 1);
2370}
2371
2380BOOLEAN
2382 IN TD_STRUCT *PtrTDStruct
2383 )
2384{
2385 //
2386 // Retrieve the information of whether the Link Pointer field
2387 // is valid or not.
2388 //
2389 if ((PtrTDStruct->TDData.TDLinkPtrTerminate & BIT0) != 0) {
2390 return FALSE;
2391 } else {
2392 return TRUE;
2393 }
2394}
2395
2404UINTN
2406 IN TD_STRUCT *PtrFirstTD
2407 )
2408{
2409 UINTN Number;
2410 TD_STRUCT *Ptr;
2411
2412 //
2413 // Count the queued TDs number.
2414 //
2415 Number = 0;
2416 Ptr = PtrFirstTD;
2417 while (Ptr != 0) {
2418 Ptr = (TD_STRUCT *)Ptr->PtrNextTD;
2419 Number++;
2420 }
2421
2422 return Number;
2423}
2424
2432VOID
2434 IN QH_STRUCT *PtrQH,
2435 IN TD_STRUCT *PtrTD
2436 )
2437{
2438 if ((PtrQH == NULL) || (PtrTD == NULL)) {
2439 return;
2440 }
2441
2442 //
2443 // Validate QH Vertical Ptr field
2444 //
2446
2447 //
2448 // Vertical Ptr pointing to TD structure
2449 //
2451
2452 SetQHVerticalLinkPtr (PtrQH, (VOID *)PtrTD);
2453
2454 PtrQH->PtrDown = (VOID *)PtrTD;
2455}
2456
2464VOID
2466 IN TD_STRUCT *PtrPreTD,
2467 IN TD_STRUCT *PtrTD
2468 )
2469{
2470 if ((PtrPreTD == NULL) || (PtrTD == NULL)) {
2471 return;
2472 }
2473
2474 //
2475 // Depth first fashion
2476 //
2477 SetTDLinkPtrDepthorBreadth (PtrPreTD, TRUE);
2478
2479 //
2480 // Link pointer pointing to TD struct
2481 //
2482 SetTDLinkPtrQHorTDSelect (PtrPreTD, FALSE);
2483
2484 //
2485 // Validate the link pointer valid bit
2486 //
2487 SetTDLinkPtrValidorInvalid (PtrPreTD, TRUE);
2488
2489 SetTDLinkPtr (PtrPreTD, PtrTD);
2490
2491 PtrPreTD->PtrNextTD = (VOID *)PtrTD;
2492
2493 PtrTD->PtrNextTD = NULL;
2494}
2495
2512 IN USB_UHC_DEV *UhcDev,
2513 IN TD_STRUCT *PtrTD,
2514 OUT UINTN *ActualLen,
2515 IN UINTN TimeOut,
2516 OUT UINT32 *TransferResult
2517 )
2518{
2519 UINTN ErrTDPos;
2520 UINTN Delay;
2521 BOOLEAN InfiniteLoop;
2522
2523 ErrTDPos = 0;
2524 *TransferResult = EFI_USB_NOERROR;
2525 *ActualLen = 0;
2526 InfiniteLoop = FALSE;
2527
2528 Delay = TimeOut * STALL_1_MILLI_SECOND;
2529 //
2530 // If Timeout is 0, then the caller must wait for the function to be completed
2531 // until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
2532 //
2533 if (TimeOut == 0) {
2534 InfiniteLoop = TRUE;
2535 }
2536
2537 do {
2538 CheckTDsResults (PtrTD, TransferResult, &ErrTDPos, ActualLen);
2539
2540 //
2541 // TD is inactive, means the control transfer is end.
2542 //
2543 if ((*TransferResult & EFI_USB_ERR_NOTEXECUTE) != EFI_USB_ERR_NOTEXECUTE) {
2544 break;
2545 }
2546
2547 MicroSecondDelay (STALL_1_MICRO_SECOND);
2548 Delay--;
2549 } while (InfiniteLoop || (Delay != 0));
2550
2551 if (*TransferResult != EFI_USB_NOERROR) {
2552 return EFI_DEVICE_ERROR;
2553 }
2554
2555 return EFI_SUCCESS;
2556}
2557
2575 IN USB_UHC_DEV *UhcDev,
2576 IN TD_STRUCT *PtrTD,
2577 IN OUT UINTN *ActualLen,
2578 IN UINT8 *DataToggle,
2579 IN UINTN TimeOut,
2580 OUT UINT32 *TransferResult
2581 )
2582{
2583 UINTN ErrTDPos;
2584 UINTN ScrollNum;
2585 UINTN Delay;
2586 BOOLEAN InfiniteLoop;
2587
2588 ErrTDPos = 0;
2589 *TransferResult = EFI_USB_NOERROR;
2590 *ActualLen = 0;
2591 InfiniteLoop = FALSE;
2592
2593 Delay = TimeOut * STALL_1_MILLI_SECOND;
2594 //
2595 // If Timeout is 0, then the caller must wait for the function to be completed
2596 // until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
2597 //
2598 if (TimeOut == 0) {
2599 InfiniteLoop = TRUE;
2600 }
2601
2602 do {
2603 CheckTDsResults (PtrTD, TransferResult, &ErrTDPos, ActualLen);
2604 //
2605 // TD is inactive, thus meaning bulk transfer's end.
2606 //
2607 if ((*TransferResult & EFI_USB_ERR_NOTEXECUTE) != EFI_USB_ERR_NOTEXECUTE) {
2608 break;
2609 }
2610
2611 MicroSecondDelay (STALL_1_MICRO_SECOND);
2612 Delay--;
2613 } while (InfiniteLoop || (Delay != 0));
2614
2615 //
2616 // has error
2617 //
2618 if (*TransferResult != EFI_USB_NOERROR) {
2619 //
2620 // scroll the Data Toggle back to the last success TD
2621 //
2622 ScrollNum = CountTDsNumber (PtrTD) - ErrTDPos;
2623 if ((ScrollNum % 2) != 0) {
2624 *DataToggle ^= 1;
2625 }
2626
2627 //
2628 // If error, wait 100ms to retry by upper layer
2629 //
2630 MicroSecondDelay (100 * 1000);
2631 return EFI_DEVICE_ERROR;
2632 }
2633
2634 return EFI_SUCCESS;
2635}
2636
2644VOID
2646 IN USB_UHC_DEV *UhcDev,
2647 IN TD_STRUCT *PtrFirstTD
2648 )
2649{
2650 TD_STRUCT *Tptr1;
2651
2652 TD_STRUCT *Tptr2;
2653
2654 Tptr1 = PtrFirstTD;
2655 //
2656 // Delete all the TDs in a queue.
2657 //
2658 while (Tptr1 != NULL) {
2659 Tptr2 = Tptr1;
2660
2661 if (!GetTDLinkPtrValidorInvalid (Tptr2)) {
2662 Tptr1 = NULL;
2663 } else {
2664 //
2665 // has more than one TD in the queue.
2666 //
2667 Tptr1 = GetTDLinkPtr (Tptr2);
2668 }
2669
2670 UhcFreePool (UhcDev, (UINT8 *)Tptr2, sizeof (TD_STRUCT));
2671 }
2672
2673 return;
2674}
2675
2687BOOLEAN
2689 IN TD_STRUCT *PtrTD,
2690 OUT UINT32 *Result,
2691 OUT UINTN *ErrTDPos,
2692 OUT UINTN *ActualTransferSize
2693 )
2694{
2695 UINTN Len;
2696
2697 *Result = EFI_USB_NOERROR;
2698 *ErrTDPos = 0;
2699
2700 //
2701 // Init to zero.
2702 //
2703 *ActualTransferSize = 0;
2704
2705 while (PtrTD != NULL) {
2706 if (IsTDStatusActive (PtrTD)) {
2707 *Result |= EFI_USB_ERR_NOTEXECUTE;
2708 }
2709
2710 if (IsTDStatusStalled (PtrTD)) {
2711 *Result |= EFI_USB_ERR_STALL;
2712 }
2713
2714 if (IsTDStatusBufferError (PtrTD)) {
2715 *Result |= EFI_USB_ERR_BUFFER;
2716 }
2717
2718 if (IsTDStatusBabbleError (PtrTD)) {
2719 *Result |= EFI_USB_ERR_BABBLE;
2720 }
2721
2722 if (IsTDStatusNAKReceived (PtrTD)) {
2723 *Result |= EFI_USB_ERR_NAK;
2724 }
2725
2726 if (IsTDStatusCRCTimeOutError (PtrTD)) {
2727 *Result |= EFI_USB_ERR_TIMEOUT;
2728 }
2729
2730 if (IsTDStatusBitStuffError (PtrTD)) {
2731 *Result |= EFI_USB_ERR_BITSTUFF;
2732 }
2733
2734 //
2735 // Accumulate actual transferred data length in each TD.
2736 //
2737 Len = GetTDStatusActualLength (PtrTD) & 0x7FF;
2738 *ActualTransferSize += Len;
2739
2740 //
2741 // if any error encountered, stop processing the left TDs.
2742 //
2743 if ((*Result) != 0) {
2744 return FALSE;
2745 }
2746
2747 PtrTD = (TD_STRUCT *)(PtrTD->PtrNextTD);
2748 //
2749 // Record the first Error TD's position in the queue,
2750 // this value is zero-based.
2751 //
2752 (*ErrTDPos)++;
2753 }
2754
2755 return TRUE;
2756}
2757
2771 IN USB_UHC_DEV *UhcDev,
2772 OUT MEMORY_MANAGE_HEADER **MemoryHeader,
2773 IN UINTN MemoryBlockSizeInPages
2774 )
2775{
2776 EFI_STATUS Status;
2777 UINT8 *TempPtr;
2778 UINTN MemPages;
2779 UINT8 *Ptr;
2780 VOID *Mapping;
2781 EFI_PHYSICAL_ADDRESS MappedAddr;
2782
2783 //
2784 // Memory Block uses MemoryBlockSizeInPages pages,
2785 // memory management header and bit array use 1 page
2786 //
2787 MemPages = MemoryBlockSizeInPages + 1;
2788 Status = IoMmuAllocateBuffer (
2789 UhcDev->IoMmu,
2790 MemPages,
2791 (VOID **)&TempPtr,
2792 &MappedAddr,
2793 &Mapping
2794 );
2795 if (EFI_ERROR (Status) || (TempPtr == NULL)) {
2796 return EFI_OUT_OF_RESOURCES;
2797 }
2798
2799 Ptr = TempPtr;
2800
2801 ZeroMem (Ptr, MemPages * EFI_PAGE_SIZE);
2802
2803 *MemoryHeader = (MEMORY_MANAGE_HEADER *)Ptr;
2804 //
2805 // adjust Ptr pointer to the next empty memory
2806 //
2807 Ptr += sizeof (MEMORY_MANAGE_HEADER);
2808 //
2809 // Set Bit Array initial address
2810 //
2811 (*MemoryHeader)->BitArrayPtr = Ptr;
2812
2813 (*MemoryHeader)->Next = NULL;
2814
2815 //
2816 // Memory block initial address
2817 //
2818 Ptr = TempPtr;
2819 Ptr += EFI_PAGE_SIZE;
2820 (*MemoryHeader)->MemoryBlockPtr = Ptr;
2821 //
2822 // set Memory block size
2823 //
2824 (*MemoryHeader)->MemoryBlockSizeInBytes = MemoryBlockSizeInPages * EFI_PAGE_SIZE;
2825 //
2826 // each bit in Bit Array will manage 32byte memory in memory block
2827 //
2828 (*MemoryHeader)->BitArraySizeInBytes = ((*MemoryHeader)->MemoryBlockSizeInBytes / 32) / 8;
2829
2830 return EFI_SUCCESS;
2831}
2832
2844 IN USB_UHC_DEV *UhcDev
2845 )
2846{
2847 MEMORY_MANAGE_HEADER *MemoryHeader;
2848 EFI_STATUS Status;
2849 UINTN MemPages;
2850
2851 MemPages = NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES;
2852 Status = CreateMemoryBlock (UhcDev, &MemoryHeader, MemPages);
2853 if (EFI_ERROR (Status)) {
2854 return Status;
2855 }
2856
2857 UhcDev->Header1 = MemoryHeader;
2858
2859 return EFI_SUCCESS;
2860}
2861
2875 IN USB_UHC_DEV *UhcDev,
2876 OUT UINT8 **Pool,
2877 IN UINTN AllocSize
2878 )
2879{
2880 MEMORY_MANAGE_HEADER *MemoryHeader;
2881 MEMORY_MANAGE_HEADER *TempHeaderPtr;
2882 MEMORY_MANAGE_HEADER *NewMemoryHeader;
2883 UINTN RealAllocSize;
2884 UINTN MemoryBlockSizeInPages;
2885 EFI_STATUS Status;
2886
2887 *Pool = NULL;
2888
2889 MemoryHeader = UhcDev->Header1;
2890
2891 //
2892 // allocate unit is 32 byte (align on 32 byte)
2893 //
2894 if ((AllocSize & 0x1F) != 0) {
2895 RealAllocSize = (AllocSize / 32 + 1) * 32;
2896 } else {
2897 RealAllocSize = AllocSize;
2898 }
2899
2900 Status = EFI_NOT_FOUND;
2901 for (TempHeaderPtr = MemoryHeader; TempHeaderPtr != NULL; TempHeaderPtr = TempHeaderPtr->Next) {
2902 Status = AllocMemInMemoryBlock (
2903 TempHeaderPtr,
2904 (VOID **)Pool,
2905 RealAllocSize / 32
2906 );
2907 if (!EFI_ERROR (Status)) {
2908 return EFI_SUCCESS;
2909 }
2910 }
2911
2912 //
2913 // There is no enough memory,
2914 // Create a new Memory Block
2915 //
2916 //
2917 // if pool size is larger than NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES,
2918 // just allocate a large enough memory block.
2919 //
2920 if (RealAllocSize > (NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES * EFI_PAGE_SIZE)) {
2921 MemoryBlockSizeInPages = RealAllocSize / EFI_PAGE_SIZE + 1;
2922 } else {
2923 MemoryBlockSizeInPages = NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES;
2924 }
2925
2926 Status = CreateMemoryBlock (UhcDev, &NewMemoryHeader, MemoryBlockSizeInPages);
2927 if (EFI_ERROR (Status)) {
2928 return Status;
2929 }
2930
2931 //
2932 // Link the new Memory Block to the Memory Header list
2933 //
2934 InsertMemoryHeaderToList (MemoryHeader, NewMemoryHeader);
2935
2936 Status = AllocMemInMemoryBlock (
2937 NewMemoryHeader,
2938 (VOID **)Pool,
2939 RealAllocSize / 32
2940 );
2941 return Status;
2942}
2943
2957 IN MEMORY_MANAGE_HEADER *MemoryHeader,
2958 OUT VOID **Pool,
2959 IN UINTN NumberOfMemoryUnit
2960 )
2961{
2962 UINTN TempBytePos;
2963 UINTN FoundBytePos;
2964 UINT8 Index;
2965 UINT8 FoundBitPos;
2966 UINT8 ByteValue;
2967 UINT8 BitValue;
2968 UINTN NumberOfZeros;
2969 UINTN Count;
2970
2971 FoundBytePos = 0;
2972 FoundBitPos = 0;
2973
2974 ByteValue = MemoryHeader->BitArrayPtr[0];
2975 NumberOfZeros = 0;
2976 Index = 0;
2977 for (TempBytePos = 0; TempBytePos < MemoryHeader->BitArraySizeInBytes;) {
2978 //
2979 // Pop out BitValue from a byte in TempBytePos.
2980 //
2981 BitValue = (UINT8)(ByteValue & 0x1);
2982
2983 if (BitValue == 0) {
2984 //
2985 // Found a free bit, the NumberOfZeros only record the number of those consecutive zeros
2986 //
2987 NumberOfZeros++;
2988 //
2989 // Found enough consecutive free space, break the loop
2990 //
2991 if (NumberOfZeros >= NumberOfMemoryUnit) {
2992 break;
2993 }
2994 } else {
2995 //
2996 // Encountering a '1', meant the bit is ocupied.
2997 //
2998 if (NumberOfZeros >= NumberOfMemoryUnit) {
2999 //
3000 // Found enough consecutive free space,break the loop
3001 //
3002 break;
3003 } else {
3004 //
3005 // the NumberOfZeros only record the number of those consecutive zeros,
3006 // so reset the NumberOfZeros to 0 when encountering '1' before finding
3007 // enough consecutive '0's
3008 //
3009 NumberOfZeros = 0;
3010 //
3011 // reset the (FoundBytePos,FoundBitPos) to the position of '1'
3012 //
3013 FoundBytePos = TempBytePos;
3014 FoundBitPos = Index;
3015 }
3016 }
3017
3018 //
3019 // right shift the byte
3020 //
3021 ByteValue /= 2;
3022
3023 //
3024 // step forward a bit
3025 //
3026 Index++;
3027 if (Index == 8) {
3028 //
3029 // step forward a byte, getting the byte value,
3030 // and reset the bit pos.
3031 //
3032 TempBytePos += 1;
3033 ByteValue = MemoryHeader->BitArrayPtr[TempBytePos];
3034 Index = 0;
3035 }
3036 }
3037
3038 if (NumberOfZeros < NumberOfMemoryUnit) {
3039 return EFI_NOT_FOUND;
3040 }
3041
3042 //
3043 // Found enough free space.
3044 //
3045 //
3046 // The values recorded in (FoundBytePos,FoundBitPos) have two conditions:
3047 // 1)(FoundBytePos,FoundBitPos) record the position
3048 // of the last '1' before the consecutive '0's, it must
3049 // be adjusted to the start position of the consecutive '0's.
3050 // 2)the start address of the consecutive '0's is just the start of
3051 // the bitarray. so no need to adjust the values of (FoundBytePos,FoundBitPos).
3052 //
3053 if ((MemoryHeader->BitArrayPtr[0] & BIT0) != 0) {
3054 FoundBitPos += 1;
3055 }
3056
3057 //
3058 // Have the (FoundBytePos,FoundBitPos) make sense.
3059 //
3060 if (FoundBitPos > 7) {
3061 FoundBytePos += 1;
3062 FoundBitPos -= 8;
3063 }
3064
3065 //
3066 // Set the memory as allocated
3067 //
3068 for (TempBytePos = FoundBytePos, Index = FoundBitPos, Count = 0; Count < NumberOfMemoryUnit; Count++) {
3069 MemoryHeader->BitArrayPtr[TempBytePos] = (UINT8)(MemoryHeader->BitArrayPtr[TempBytePos] | (1 << Index));
3070 Index++;
3071 if (Index == 8) {
3072 TempBytePos += 1;
3073 Index = 0;
3074 }
3075 }
3076
3077 *Pool = MemoryHeader->MemoryBlockPtr + (FoundBytePos * 8 + FoundBitPos) * 32;
3078
3079 return EFI_SUCCESS;
3080}
3081
3090VOID
3092 IN USB_UHC_DEV *UhcDev,
3093 IN UINT8 *Pool,
3094 IN UINTN AllocSize
3095 )
3096{
3097 MEMORY_MANAGE_HEADER *MemoryHeader;
3098 MEMORY_MANAGE_HEADER *TempHeaderPtr;
3099 UINTN StartBytePos;
3100 UINTN Index;
3101 UINT8 StartBitPos;
3102 UINT8 Index2;
3103 UINTN Count;
3104 UINTN RealAllocSize;
3105
3106 MemoryHeader = UhcDev->Header1;
3107
3108 //
3109 // allocate unit is 32 byte (align on 32 byte)
3110 //
3111 if ((AllocSize & 0x1F) != 0) {
3112 RealAllocSize = (AllocSize / 32 + 1) * 32;
3113 } else {
3114 RealAllocSize = AllocSize;
3115 }
3116
3117 for (TempHeaderPtr = MemoryHeader; TempHeaderPtr != NULL;
3118 TempHeaderPtr = TempHeaderPtr->Next)
3119 {
3120 if ((Pool >= TempHeaderPtr->MemoryBlockPtr) &&
3121 ((Pool + RealAllocSize) <= (TempHeaderPtr->MemoryBlockPtr +
3122 TempHeaderPtr->MemoryBlockSizeInBytes)))
3123 {
3124 //
3125 // Pool is in the Memory Block area,
3126 // find the start byte and bit in the bit array
3127 //
3128 StartBytePos = ((Pool - TempHeaderPtr->MemoryBlockPtr) / 32) / 8;
3129 StartBitPos = (UINT8)(((Pool - TempHeaderPtr->MemoryBlockPtr) / 32) % 8);
3130
3131 //
3132 // reset associated bits in bit array
3133 //
3134 for (Index = StartBytePos, Index2 = StartBitPos, Count = 0; Count < (RealAllocSize / 32); Count++) {
3135 TempHeaderPtr->BitArrayPtr[Index] = (UINT8)(TempHeaderPtr->BitArrayPtr[Index] ^ (1 << Index2));
3136 Index2++;
3137 if (Index2 == 8) {
3138 Index += 1;
3139 Index2 = 0;
3140 }
3141 }
3142
3143 //
3144 // break the loop
3145 //
3146 break;
3147 }
3148 }
3149}
3150
3158VOID
3160 IN MEMORY_MANAGE_HEADER *MemoryHeader,
3161 IN MEMORY_MANAGE_HEADER *NewMemoryHeader
3162 )
3163{
3164 MEMORY_MANAGE_HEADER *TempHeaderPtr;
3165
3166 for (TempHeaderPtr = MemoryHeader; TempHeaderPtr != NULL; TempHeaderPtr = TempHeaderPtr->Next) {
3167 if (TempHeaderPtr->Next == NULL) {
3168 TempHeaderPtr->Next = NewMemoryHeader;
3169 break;
3170 }
3171 }
3172}
3173
3188 IN USB_UHC_DEV *Uhc,
3189 IN OUT VOID *Request,
3190 OUT UINT8 **MappedAddr,
3191 OUT VOID **Map
3192 )
3193{
3194 EFI_STATUS Status;
3195 UINTN Len;
3196 EFI_PHYSICAL_ADDRESS PhyAddr;
3197
3198 Len = sizeof (EFI_USB_DEVICE_REQUEST);
3199 Status = IoMmuMap (
3200 Uhc->IoMmu,
3202 Request,
3203 &Len,
3204 &PhyAddr,
3205 Map
3206 );
3207
3208 if (!EFI_ERROR (Status)) {
3209 *MappedAddr = (UINT8 *)(UINTN)PhyAddr;
3210 }
3211
3212 return Status;
3213}
3214
3232 IN USB_UHC_DEV *Uhc,
3233 IN EFI_USB_DATA_DIRECTION Direction,
3234 IN VOID *Data,
3235 IN OUT UINTN *Len,
3236 OUT UINT8 *PktId,
3237 OUT UINT8 **MappedAddr,
3238 OUT VOID **Map
3239 )
3240{
3241 EFI_STATUS Status;
3242 EFI_PHYSICAL_ADDRESS PhyAddr;
3243
3244 Status = EFI_SUCCESS;
3245
3246 switch (Direction) {
3247 case EfiUsbDataIn:
3248 //
3249 // BusMasterWrite means cpu read
3250 //
3251 *PktId = INPUT_PACKET_ID;
3252 Status = IoMmuMap (
3253 Uhc->IoMmu,
3255 Data,
3256 Len,
3257 &PhyAddr,
3258 Map
3259 );
3260
3261 if (EFI_ERROR (Status)) {
3262 goto EXIT;
3263 }
3264
3265 *MappedAddr = (UINT8 *)(UINTN)PhyAddr;
3266 break;
3267
3268 case EfiUsbDataOut:
3269 *PktId = OUTPUT_PACKET_ID;
3270 Status = IoMmuMap (
3271 Uhc->IoMmu,
3273 Data,
3274 Len,
3275 &PhyAddr,
3276 Map
3277 );
3278
3279 if (EFI_ERROR (Status)) {
3280 goto EXIT;
3281 }
3282
3283 *MappedAddr = (UINT8 *)(UINTN)PhyAddr;
3284 break;
3285
3286 case EfiUsbNoData:
3287 if ((Len != NULL) && (*Len != 0)) {
3288 Status = EFI_INVALID_PARAMETER;
3289 goto EXIT;
3290 }
3291
3292 *PktId = OUTPUT_PACKET_ID;
3293 *MappedAddr = NULL;
3294 *Map = NULL;
3295 break;
3296
3297 default:
3298 Status = EFI_INVALID_PARAMETER;
3299 }
3300
3301EXIT:
3302 return Status;
3303}
UINT64 UINTN
EFI_STATUS IoMmuUnmap(IN VOID *Mapping)
Definition: DmaMem.c:132
EFI_STATUS IoMmuAllocateBuffer(IN UINTN Pages, OUT VOID **HostAddress, OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, OUT VOID **Mapping)
Definition: DmaMem.c:170
EFI_STATUS IoMmuMap(IN EDKII_IOMMU_OPERATION Operation, IN VOID *HostAddress, IN OUT UINTN *NumberOfBytes, OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, OUT VOID **Mapping)
Definition: DmaMem.c:60
UINTN EFIAPI MicroSecondDelay(IN UINTN MicroSeconds)
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
EFI_STATUS EFIAPI PeiServicesLocatePpi(IN CONST EFI_GUID *Guid, IN UINTN Instance, IN OUT EFI_PEI_PPI_DESCRIPTOR **PpiDescriptor, IN OUT VOID **Ppi)
EFI_STATUS EFIAPI PeiServicesNotifyPpi(IN CONST EFI_PEI_NOTIFY_DESCRIPTOR *NotifyList)
EFI_STATUS EFIAPI PeiServicesAllocatePages(IN EFI_MEMORY_TYPE MemoryType, IN UINTN Pages, OUT EFI_PHYSICAL_ADDRESS *Memory)
EFI_STATUS EFIAPI PeiServicesInstallPpi(IN CONST EFI_PEI_PPI_DESCRIPTOR *PpiList)
EFI_STATUS EFIAPI PeiServicesRegisterForShadow(IN EFI_PEI_FILE_HANDLE FileHandle)
UINT16 EFIAPI IoRead16(IN UINTN Port)
Definition: IoLibArmVirt.c:225
UINT32 EFIAPI IoWrite32(IN UINTN Port, IN UINT32 Value)
Definition: IoLibArmVirt.c:300
UINT16 EFIAPI IoWrite16(IN UINTN Port, IN UINT16 Value)
Definition: IoLibArmVirt.c:250
#define NULL
Definition: Base.h:319
#define CONST
Definition: Base.h:259
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define ASSERT_EFI_ERROR(StatusParameter)
Definition: DebugLib.h:462
EFI_USB_PORT_FEATURE
#define USB_PORT_STAT_C_CONNECTION
#define USB_PORT_STAT_CONNECTION
EFI_USB_DATA_DIRECTION
Definition: UsbIo.h:44
VOID IoMmuInit(OUT EDKII_IOMMU_PPI **IoMmu)
Definition: DmaMem.c:238
VOID * EFI_PEI_FILE_HANDLE
Definition: PiPeiCis.h:26
@ EdkiiIoMmuOperationBusMasterWrite
Definition: IoMmu.h:54
@ EdkiiIoMmuOperationBusMasterRead
Definition: IoMmu.h:49
UINT64 EFI_PHYSICAL_ADDRESS
Definition: UefiBaseType.h:50
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
@ EfiBootServicesData
VOID SetQHVerticalQHorTDSelect(IN QH_STRUCT *PtrQH, IN BOOLEAN IsQH)
Definition: UhcPeim.c:1409
VOID SetFrameListBaseAddress(IN USB_UHC_DEV *UhcDev, IN UINT32 FrameListRegAddr, IN UINT32 Addr)
Definition: UhcPeim.c:1272
VOID SetTDTokenDeviceAddress(IN TD_STRUCT *PtrTDStruct, IN UINTN DevAddr)
Definition: UhcPeim.c:2168
VOID SetTDTokenEndPoint(IN TD_STRUCT *PtrTDStruct, IN UINTN EndPoint)
Definition: UhcPeim.c:2149
EFI_STATUS EFIAPI UhcControlTransfer(IN EFI_PEI_SERVICES **PeiServices, IN PEI_USB_HOST_CONTROLLER_PPI *This, IN UINT8 DeviceAddress, IN UINT8 DeviceSpeed, IN UINT8 MaximumPacketLength, IN EFI_USB_DEVICE_REQUEST *Request, IN EFI_USB_DATA_DIRECTION TransferDirection, IN OUT VOID *Data OPTIONAL, IN OUT UINTN *DataLength OPTIONAL, IN UINTN TimeOut, OUT UINT32 *TransferResult)
Definition: UhcPeim.c:241
VOID SetTDTokenDataToggle1(IN TD_STRUCT *PtrTDStruct)
Definition: UhcPeim.c:2114
EFI_STATUS EFIAPI UhcBulkTransfer(IN EFI_PEI_SERVICES **PeiServices, IN PEI_USB_HOST_CONTROLLER_PPI *This, IN UINT8 DeviceAddress, IN UINT8 EndPointAddress, IN UINT8 MaximumPacketLength, IN OUT VOID *Data, IN OUT UINTN *DataLength, IN OUT UINT8 *DataToggle, IN UINTN TimeOut, OUT UINT32 *TransferResult)
Definition: UhcPeim.c:489
BOOLEAN GetTDLinkPtrValidorInvalid(IN TD_STRUCT *PtrTDStruct)
Definition: UhcPeim.c:2381
BOOLEAN CheckTDsResults(IN TD_STRUCT *PtrTD, OUT UINT32 *Result, OUT UINTN *ErrTDPos, OUT UINTN *ActualTransferSize)
Definition: UhcPeim.c:2688
VOID LinkTDToQH(IN QH_STRUCT *PtrQH, IN TD_STRUCT *PtrTD)
Definition: UhcPeim.c:2433
VOID SetTDLinkPtrValidorInvalid(IN TD_STRUCT *PtrTDStruct, IN BOOLEAN IsValid)
Definition: UhcPeim.c:1864
EFI_STATUS CreateQH(IN USB_UHC_DEV *UhcDev, OUT QH_STRUCT **PtrQH)
Definition: UhcPeim.c:1295
VOID ClearStatusReg(IN USB_UHC_DEV *UhcDev, IN UINT32 StatusAddr)
Definition: UhcPeim.c:1225
EFI_STATUS CreateMemoryBlock(IN USB_UHC_DEV *UhcDev, OUT MEMORY_MANAGE_HEADER **MemoryHeader, IN UINTN MemoryBlockSizeInPages)
Definition: UhcPeim.c:2770
EFI_STATUS UhciMapUserRequest(IN USB_UHC_DEV *Uhc, IN OUT VOID *Request, OUT UINT8 **MappedAddr, OUT VOID **Map)
Definition: UhcPeim.c:3187
EFI_STATUS InitializeMemoryManagement(IN USB_UHC_DEV *UhcDev)
Definition: UhcPeim.c:2843
VOID SetQHHorizontalQHorTDSelect(IN QH_STRUCT *PtrQH, IN BOOLEAN IsQH)
Definition: UhcPeim.c:1348
EFI_STATUS EFIAPI UhcGetRootHubPortNumber(IN EFI_PEI_SERVICES **PeiServices, IN PEI_USB_HOST_CONTROLLER_PPI *This, OUT UINT8 *PortNumber)
Definition: UhcPeim.c:708
UINTN CountTDsNumber(IN TD_STRUCT *PtrFirstTD)
Definition: UhcPeim.c:2405
VOID USBWritePortDW(IN USB_UHC_DEV *UhcDev, IN UINT32 Port, IN UINT32 Data)
Definition: UhcPeim.c:1208
EFI_STATUS CreateFrameList(USB_UHC_DEV *UhcDev)
Definition: UhcPeim.c:1101
EFI_STATUS CreateStatusTD(IN USB_UHC_DEV *UhcDev, IN UINT8 DevAddr, IN UINT8 Endpoint, IN UINT8 PktID, IN UINT8 DeviceSpeed, OUT TD_STRUCT **PtrTD)
Definition: UhcPeim.c:1763
VOID SetQHHorizontalLinkPtr(IN QH_STRUCT *PtrQH, IN VOID *PtrNext)
Definition: UhcPeim.c:1327
EFI_STATUS AllocMemInMemoryBlock(IN MEMORY_MANAGE_HEADER *MemoryHeader, OUT VOID **Pool, IN UINTN NumberOfMemoryUnit)
Definition: UhcPeim.c:2956
EFI_STATUS UhcAllocatePool(IN USB_UHC_DEV *UhcDev, OUT UINT8 **Pool, IN UINTN AllocSize)
Definition: UhcPeim.c:2874
VOID USBWritePortW(IN USB_UHC_DEV *UhcDev, IN UINT32 Port, IN UINT16 Data)
Definition: UhcPeim.c:1190
VOID SetorClearTDControlIOC(IN TD_STRUCT *PtrTDStruct, IN BOOLEAN IsSet)
Definition: UhcPeim.c:2044
BOOLEAN IsStatusOK(IN USB_UHC_DEV *UhcDev, IN UINT32 StatusRegAddr)
Definition: UhcPeim.c:1247
VOID SetTDLinkPtrQHorTDSelect(IN TD_STRUCT *PtrTDStruct, IN BOOLEAN IsQH)
Definition: UhcPeim.c:1884
VOID SetQHHorizontalValidorInvalid(IN QH_STRUCT *PtrQH, IN BOOLEAN IsValid)
Definition: UhcPeim.c:1368
VOID SetTDControlErrorCounter(IN TD_STRUCT *PtrTDStruct, IN UINT8 MaxErrors)
Definition: UhcPeim.c:1982
VOID UhcFreePool(IN USB_UHC_DEV *UhcDev, IN UINT8 *Pool, IN UINTN AllocSize)
Definition: UhcPeim.c:3091
EFI_STATUS InitializeUsbHC(IN USB_UHC_DEV *UhcDev)
Definition: UhcPeim.c:1041
BOOLEAN IsTDStatusBufferError(IN TD_STRUCT *PtrTDStruct)
Definition: UhcPeim.c:2251
VOID SetTDStatusActiveorInactive(IN TD_STRUCT *PtrTDStruct, IN BOOLEAN IsActive)
Definition: UhcPeim.c:2064
VOID DeleteQueuedTDs(IN USB_UHC_DEV *UhcDev, IN TD_STRUCT *PtrFirstTD)
Definition: UhcPeim.c:2645
EFI_STATUS EFIAPI UhcGetRootHubPortStatus(IN EFI_PEI_SERVICES **PeiServices, IN PEI_USB_HOST_CONTROLLER_PPI *This, IN UINT8 PortNumber, OUT EFI_USB_PORT_STATUS *PortStatus)
Definition: UhcPeim.c:756
BOOLEAN IsTDStatusCRCTimeOutError(IN TD_STRUCT *PtrTDStruct)
Definition: UhcPeim.c:2317
EFI_STATUS AllocateTDorQHStruct(IN USB_UHC_DEV *UhcDev, IN UINT32 Size, OUT VOID **PtrStruct)
Definition: UhcPeim.c:1453
BOOLEAN IsTDStatusStalled(IN TD_STRUCT *PtrTDStruct)
Definition: UhcPeim.c:2229
VOID SetTDLinkPtr(IN TD_STRUCT *PtrTDStruct, IN VOID *PtrNext)
Definition: UhcPeim.c:1923
EFI_STATUS GenDataTD(IN USB_UHC_DEV *UhcDev, IN UINT8 DevAddr, IN UINT8 Endpoint, IN UINT8 *PtrData, IN UINT8 *DataPhy, IN UINT8 Len, IN UINT8 PktID, IN UINT8 Toggle, IN UINT8 DeviceSpeed, OUT TD_STRUCT **PtrTD)
Definition: UhcPeim.c:1643
UINT16 GetTDStatusActualLength(IN TD_STRUCT *PtrTDStruct)
Definition: UhcPeim.c:2361
EFI_STATUS GenSetupStageTD(IN USB_UHC_DEV *UhcDev, IN UINT8 DevAddr, IN UINT8 Endpoint, IN UINT8 DeviceSpeed, IN UINT8 *DevRequest, IN UINT8 *RequestPhy, IN UINT8 RequestLen, OUT TD_STRUCT **PtrTD)
Definition: UhcPeim.c:1529
EFI_STATUS EFIAPI UhcSetRootHubPortFeature(IN EFI_PEI_SERVICES **PeiServices, IN PEI_USB_HOST_CONTROLLER_PPI *This, IN UINT8 PortNumber, IN EFI_USB_PORT_FEATURE PortFeature)
Definition: UhcPeim.c:855
UINT16 SetTDTokenMaxLength(IN TD_STRUCT *PtrTDStruct, IN UINT16 MaxLen)
Definition: UhcPeim.c:2089
VOID SetTDLinkPtrDepthorBreadth(IN TD_STRUCT *PtrTDStruct, IN BOOLEAN IsDepth)
Definition: UhcPeim.c:1903
VOID EnableorDisableTDShortPacket(IN TD_STRUCT *PtrTDStruct, IN BOOLEAN IsEnable)
Definition: UhcPeim.c:1963
EFI_STATUS EFIAPI UhcPeimEntry(IN EFI_PEI_FILE_HANDLE FileHandle, IN CONST EFI_PEI_SERVICES **PeiServices)
Definition: UhcPeim.c:97
VOID SetTDLoworFullSpeedDevice(IN TD_STRUCT *PtrTDStruct, IN BOOLEAN IsLowSpeedDevice)
Definition: UhcPeim.c:2005
VOID SetQHVerticalLinkPtr(IN QH_STRUCT *PtrQH, IN VOID *PtrNext)
Definition: UhcPeim.c:1388
BOOLEAN IsTDStatusNAKReceived(IN TD_STRUCT *PtrTDStruct)
Definition: UhcPeim.c:2295
EFI_STATUS ExecuteControlTransfer(IN USB_UHC_DEV *UhcDev, IN TD_STRUCT *PtrTD, OUT UINTN *ActualLen, IN UINTN TimeOut, OUT UINT32 *TransferResult)
Definition: UhcPeim.c:2511
EFI_STATUS UhciMapUserData(IN USB_UHC_DEV *Uhc, IN EFI_USB_DATA_DIRECTION Direction, IN VOID *Data, IN OUT UINTN *Len, OUT UINT8 *PktId, OUT UINT8 **MappedAddr, OUT VOID **Map)
Definition: UhcPeim.c:3231
VOID * GetTDLinkPtr(IN TD_STRUCT *PtrTDStruct)
Definition: UhcPeim.c:1944
EFI_STATUS ExecBulkTransfer(IN USB_UHC_DEV *UhcDev, IN TD_STRUCT *PtrTD, IN OUT UINTN *ActualLen, IN UINT8 *DataToggle, IN UINTN TimeOut, OUT UINT32 *TransferResult)
Definition: UhcPeim.c:2574
VOID SetQHVerticalValidorInvalid(IN QH_STRUCT *PtrQH, IN BOOLEAN IsValid)
Definition: UhcPeim.c:1429
BOOLEAN IsTDStatusBitStuffError(IN TD_STRUCT *PtrTDStruct)
Definition: UhcPeim.c:2339
UINT16 USBReadPortW(IN USB_UHC_DEV *UhcDev, IN UINT32 Port)
Definition: UhcPeim.c:1173
VOID SetTDTokenPacketID(IN TD_STRUCT *PtrTDStruct, IN UINT8 PacketID)
Definition: UhcPeim.c:2187
VOID SetTDControlIsochronousorNot(IN TD_STRUCT *PtrTDStruct, IN BOOLEAN IsIsochronous)
Definition: UhcPeim.c:2024
VOID SetTDTokenDataToggle0(IN TD_STRUCT *PtrTDStruct)
Definition: UhcPeim.c:2131
VOID LinkTDToTD(IN TD_STRUCT *PtrPreTD, IN TD_STRUCT *PtrTD)
Definition: UhcPeim.c:2465
EFI_STATUS EFIAPI UhcClearRootHubPortFeature(IN EFI_PEI_SERVICES **PeiServices, IN PEI_USB_HOST_CONTROLLER_PPI *This, IN UINT8 PortNumber, IN EFI_USB_PORT_FEATURE PortFeature)
Definition: UhcPeim.c:933
EFI_STATUS CreateTD(IN USB_UHC_DEV *UhcDev, OUT TD_STRUCT **PtrTD)
Definition: UhcPeim.c:1489
EFI_STATUS UhciStopHc(IN USB_UHC_DEV *Uhc, IN UINTN Timeout)
Definition: UhcPeim.c:24
BOOLEAN IsTDStatusActive(IN TD_STRUCT *PtrTDStruct)
Definition: UhcPeim.c:2207
VOID InsertMemoryHeaderToList(IN MEMORY_MANAGE_HEADER *MemoryHeader, IN MEMORY_MANAGE_HEADER *NewMemoryHeader)
Definition: UhcPeim.c:3159
EFI_STATUS EFIAPI UhcEndOfPei(IN EFI_PEI_SERVICES **PeiServices, IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, IN VOID *Ppi)
Definition: UhcPeim.c:67
BOOLEAN IsTDStatusBabbleError(IN TD_STRUCT *PtrTDStruct)
Definition: UhcPeim.c:2273
#define PEI_UHCI_CONTROLLER
Definition: UsbController.h:31
EFI_PEIM_NOTIFY_ENTRY_POINT Notify
Definition: PiPeiCis.h:122