1 /** @file
2 PEIM to produce gPeiUsbHostControllerPpiGuid based on gPeiUsbControllerPpiGuid
3 which is used to enable recovery function from USB Drivers.
4 
5 Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved. <BR>
6 
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions
9 of the BSD License which accompanies this distribution.  The
10 full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.php
12 
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 
16 **/
17 
18 #include "UhcPeim.h"
19 
20 /**
21   Initializes Usb Host Controller.
22 
23   @param  FileHandle  Handle of the file being invoked.
24   @param  PeiServices Describes the list of possible PEI Services.
25 
26   @retval EFI_SUCCESS            PPI successfully installed.
27   @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resource.
28 
29 **/
30 EFI_STATUS
31 EFIAPI
UhcPeimEntry(IN EFI_PEI_FILE_HANDLE FileHandle,IN CONST EFI_PEI_SERVICES ** PeiServices)32 UhcPeimEntry (
33   IN EFI_PEI_FILE_HANDLE        FileHandle,
34   IN CONST EFI_PEI_SERVICES     **PeiServices
35   )
36 {
37   PEI_USB_CONTROLLER_PPI      *ChipSetUsbControllerPpi;
38   EFI_STATUS                  Status;
39   UINT8                       Index;
40   UINTN                       ControllerType;
41   UINTN                       BaseAddress;
42   UINTN                       MemPages;
43   USB_UHC_DEV                 *UhcDev;
44   EFI_PHYSICAL_ADDRESS        TempPtr;
45 
46   //
47   // Shadow this PEIM to run from memory
48   //
49   if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {
50     return EFI_SUCCESS;
51   }
52 
53   Status = PeiServicesLocatePpi (
54              &gPeiUsbControllerPpiGuid,
55              0,
56              NULL,
57              (VOID **) &ChipSetUsbControllerPpi
58              );
59   //
60   // If failed to locate, it is a bug in dispather as depex has gPeiUsbControllerPpiGuid.
61   //
62   ASSERT_EFI_ERROR (Status);
63 
64   Index = 0;
65   while (TRUE) {
66     Status = ChipSetUsbControllerPpi->GetUsbController (
67                                         (EFI_PEI_SERVICES **) PeiServices,
68                                         ChipSetUsbControllerPpi,
69                                         Index,
70                                         &ControllerType,
71                                         &BaseAddress
72                                         );
73     //
74     // When status is error, meant no controller is found
75     //
76     if (EFI_ERROR (Status)) {
77       break;
78     }
79 
80     //
81     // This PEIM is for UHC type controller.
82     //
83     if (ControllerType != PEI_UHCI_CONTROLLER) {
84       Index++;
85       continue;
86     }
87 
88     MemPages = sizeof (USB_UHC_DEV) / EFI_PAGE_SIZE + 1;
89 
90     Status = PeiServicesAllocatePages (
91                EfiBootServicesData,
92                MemPages,
93                &TempPtr
94                );
95     if (EFI_ERROR (Status)) {
96       return EFI_OUT_OF_RESOURCES;
97     }
98 
99     UhcDev = (USB_UHC_DEV *) ((UINTN) TempPtr);
100     UhcDev->Signature   = USB_UHC_DEV_SIGNATURE;
101     UhcDev->UsbHostControllerBaseAddress = (UINT32) BaseAddress;
102 
103     //
104     // Init local memory management service
105     //
106     Status = InitializeMemoryManagement (UhcDev);
107     if (EFI_ERROR (Status)) {
108       return Status;
109     }
110 
111     //
112     // Initialize Uhc's hardware
113     //
114     Status = InitializeUsbHC (UhcDev);
115     if (EFI_ERROR (Status)) {
116       return Status;
117     }
118 
119     UhcDev->UsbHostControllerPpi.ControlTransfer          = UhcControlTransfer;
120     UhcDev->UsbHostControllerPpi.BulkTransfer             = UhcBulkTransfer;
121     UhcDev->UsbHostControllerPpi.GetRootHubPortNumber     = UhcGetRootHubPortNumber;
122     UhcDev->UsbHostControllerPpi.GetRootHubPortStatus     = UhcGetRootHubPortStatus;
123     UhcDev->UsbHostControllerPpi.SetRootHubPortFeature    = UhcSetRootHubPortFeature;
124     UhcDev->UsbHostControllerPpi.ClearRootHubPortFeature  = UhcClearRootHubPortFeature;
125 
126     UhcDev->PpiDescriptor.Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);
127     UhcDev->PpiDescriptor.Guid  = &gPeiUsbHostControllerPpiGuid;
128     UhcDev->PpiDescriptor.Ppi   = &UhcDev->UsbHostControllerPpi;
129 
130     Status = PeiServicesInstallPpi (&UhcDev->PpiDescriptor);
131     if (EFI_ERROR (Status)) {
132       Index++;
133       continue;
134     }
135 
136     Index++;
137   }
138 
139   return EFI_SUCCESS;
140 }
141 
142 /**
143   Submits control transfer to a target USB device.
144 
145   @param  PeiServices            The pointer of EFI_PEI_SERVICES.
146   @param  This                   The pointer of PEI_USB_HOST_CONTROLLER_PPI.
147   @param  DeviceAddress          The target device address.
148   @param  DeviceSpeed            Target device speed.
149   @param  MaximumPacketLength    Maximum packet size the default control transfer
150                                  endpoint is capable of sending or receiving.
151   @param  Request                USB device request to send.
152   @param  TransferDirection      Specifies the data direction for the data stage.
153   @param  Data                   Data buffer to be transmitted or received from USB device.
154   @param  DataLength             The size (in bytes) of the data buffer.
155   @param  TimeOut                Indicates the maximum timeout, in millisecond.
156                                  If Timeout is 0, then the caller must wait for the function
157                                  to be completed until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
158   @param  TransferResult         Return the result of this control transfer.
159 
160   @retval EFI_SUCCESS            Transfer was completed successfully.
161   @retval EFI_OUT_OF_RESOURCES   The transfer failed due to lack of resources.
162   @retval EFI_INVALID_PARAMETER  Some parameters are invalid.
163   @retval EFI_TIMEOUT            Transfer failed due to timeout.
164   @retval EFI_DEVICE_ERROR       Transfer failed due to host controller or device error.
165 
166 **/
167 EFI_STATUS
168 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)169 UhcControlTransfer (
170   IN     EFI_PEI_SERVICES               **PeiServices,
171   IN     PEI_USB_HOST_CONTROLLER_PPI    *This,
172   IN     UINT8                          DeviceAddress,
173   IN     UINT8                          DeviceSpeed,
174   IN     UINT8                          MaximumPacketLength,
175   IN     EFI_USB_DEVICE_REQUEST         *Request,
176   IN     EFI_USB_DATA_DIRECTION         TransferDirection,
177   IN OUT VOID                           *Data                 OPTIONAL,
178   IN OUT UINTN                          *DataLength           OPTIONAL,
179   IN     UINTN                          TimeOut,
180   OUT    UINT32                         *TransferResult
181   )
182 {
183   USB_UHC_DEV *UhcDev;
184   UINT32      StatusReg;
185   UINT8       PktID;
186   QH_STRUCT   *PtrQH;
187   TD_STRUCT   *PtrTD;
188   TD_STRUCT   *PtrPreTD;
189   TD_STRUCT   *PtrSetupTD;
190   TD_STRUCT   *PtrStatusTD;
191   EFI_STATUS  Status;
192   UINT32      DataLen;
193   UINT8       *PtrDataSource;
194   UINT8       *Ptr;
195   UINT8       DataToggle;
196 
197   UhcDev      = PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This);
198 
199   StatusReg   = UhcDev->UsbHostControllerBaseAddress + USBSTS;
200 
201   PktID       = INPUT_PACKET_ID;
202 
203   if (Request == NULL || TransferResult == NULL) {
204     return EFI_INVALID_PARAMETER;
205   }
206   //
207   // if errors exist that cause host controller halt,
208   // then return EFI_DEVICE_ERROR.
209   //
210 
211   if (!IsStatusOK (UhcDev, StatusReg)) {
212     ClearStatusReg (UhcDev, StatusReg);
213     *TransferResult = EFI_USB_ERR_SYSTEM;
214     return EFI_DEVICE_ERROR;
215   }
216 
217   ClearStatusReg (UhcDev, StatusReg);
218 
219   //
220   // generate Setup Stage TD
221   //
222 
223   PtrQH = UhcDev->ConfigQH;
224 
225   GenSetupStageTD (
226     UhcDev,
227     DeviceAddress,
228     0,
229     DeviceSpeed,
230     (UINT8 *) Request,
231     (UINT8) sizeof (EFI_USB_DEVICE_REQUEST),
232     &PtrSetupTD
233     );
234 
235   //
236   // link setup TD structures to QH structure
237   //
238   LinkTDToQH (PtrQH, PtrSetupTD);
239 
240   PtrPreTD = PtrSetupTD;
241 
242   //
243   //  Data Stage of Control Transfer
244   //
245   switch (TransferDirection) {
246 
247   case EfiUsbDataIn:
248     PktID         = INPUT_PACKET_ID;
249     PtrDataSource = Data;
250     DataLen       = (UINT32) *DataLength;
251     Ptr           = PtrDataSource;
252     break;
253 
254   case EfiUsbDataOut:
255     PktID         = OUTPUT_PACKET_ID;
256     PtrDataSource = Data;
257     DataLen       = (UINT32) *DataLength;
258     Ptr           = PtrDataSource;
259     break;
260 
261   //
262   // no data stage
263   //
264   case EfiUsbNoData:
265     if (*DataLength != 0) {
266       return EFI_INVALID_PARAMETER;
267     }
268 
269     PktID         = OUTPUT_PACKET_ID;
270     PtrDataSource = NULL;
271     DataLen       = 0;
272     Ptr           = NULL;
273     break;
274 
275   default:
276     return EFI_INVALID_PARAMETER;
277   }
278 
279   DataToggle  = 1;
280 
281   PtrTD       = PtrSetupTD;
282   while (DataLen > 0) {
283     //
284     // create TD structures and link together
285     //
286     UINT8 PacketSize;
287 
288     //
289     // PacketSize is the data load size of each TD carries.
290     //
291     PacketSize = (UINT8) DataLen;
292     if (DataLen > MaximumPacketLength) {
293       PacketSize = MaximumPacketLength;
294     }
295 
296     GenDataTD (
297       UhcDev,
298       DeviceAddress,
299       0,
300       Ptr,
301       PacketSize,
302       PktID,
303       DataToggle,
304       DeviceSpeed,
305       &PtrTD
306       );
307 
308     //
309     // Link two TDs in vertical depth
310     //
311     LinkTDToTD (PtrPreTD, PtrTD);
312     PtrPreTD = PtrTD;
313 
314     DataToggle ^= 1;
315     Ptr += PacketSize;
316     DataLen -= PacketSize;
317   }
318 
319   //
320   // PtrPreTD points to the last TD before the Setup-Stage TD.
321   //
322   PtrPreTD = PtrTD;
323 
324   //
325   // Status Stage of Control Transfer
326   //
327   if (PktID == OUTPUT_PACKET_ID) {
328     PktID = INPUT_PACKET_ID;
329   } else {
330     PktID = OUTPUT_PACKET_ID;
331   }
332   //
333   // create Status Stage TD structure
334   //
335   CreateStatusTD (
336     UhcDev,
337     DeviceAddress,
338     0,
339     PktID,
340     DeviceSpeed,
341     &PtrStatusTD
342     );
343 
344   LinkTDToTD (PtrPreTD, PtrStatusTD);
345 
346   //
347   // Poll QH-TDs execution and get result.
348   // detail status is returned
349   //
350   Status = ExecuteControlTransfer (
351             UhcDev,
352             PtrSetupTD,
353             DataLength,
354             TimeOut,
355             TransferResult
356             );
357 
358   //
359   // TRUE means must search other framelistindex
360   //
361   SetQHVerticalValidorInvalid(PtrQH, FALSE);
362   DeleteQueuedTDs (UhcDev, PtrSetupTD);
363 
364   //
365   // if has errors that cause host controller halt, then return EFI_DEVICE_ERROR directly.
366   //
367   if (!IsStatusOK (UhcDev, StatusReg)) {
368 
369     ClearStatusReg (UhcDev, StatusReg);
370     *TransferResult |= EFI_USB_ERR_SYSTEM;
371     return EFI_DEVICE_ERROR;
372   }
373 
374   ClearStatusReg (UhcDev, StatusReg);
375 
376   return Status;
377 }
378 
379 /**
380   Submits bulk transfer to a bulk endpoint of a USB device.
381 
382   @param  PeiServices           The pointer of EFI_PEI_SERVICES.
383   @param  This                  The pointer of PEI_USB_HOST_CONTROLLER_PPI.
384   @param  DeviceAddress         Target device address.
385   @param  EndPointAddress       Endpoint number and its direction in bit 7.
386   @param  MaximumPacketLength   Maximum packet size the endpoint is capable of
387                                 sending or receiving.
388   @param  Data                  Array of pointers to the buffers of data to transmit
389                                 from or receive into.
390   @param  DataLength            The lenght of the data buffer.
391   @param  DataToggle            On input, the initial data toggle for the transfer;
392                                 On output, it is updated to to next data toggle to use of
393                                 the subsequent bulk transfer.
394   @param  TimeOut               Indicates the maximum time, in millisecond, which the
395                                 transfer is allowed to complete.
396                                 If Timeout is 0, then the caller must wait for the function
397                                 to be completed until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
398   @param  TransferResult        A pointer to the detailed result information of the
399                                 bulk transfer.
400 
401   @retval EFI_SUCCESS           The transfer was completed successfully.
402   @retval EFI_OUT_OF_RESOURCES  The transfer failed due to lack of resource.
403   @retval EFI_INVALID_PARAMETER Parameters are invalid.
404   @retval EFI_TIMEOUT           The transfer failed due to timeout.
405   @retval EFI_DEVICE_ERROR      The transfer failed due to host controller error.
406 
407 **/
408 EFI_STATUS
409 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)410 UhcBulkTransfer (
411   IN     EFI_PEI_SERVICES               **PeiServices,
412   IN     PEI_USB_HOST_CONTROLLER_PPI    *This,
413   IN     UINT8                          DeviceAddress,
414   IN     UINT8                          EndPointAddress,
415   IN     UINT8                          MaximumPacketLength,
416   IN OUT VOID                           *Data,
417   IN OUT UINTN                          *DataLength,
418   IN OUT UINT8                          *DataToggle,
419   IN     UINTN                          TimeOut,
420   OUT    UINT32                         *TransferResult
421   )
422 {
423   USB_UHC_DEV             *UhcDev;
424   UINT32                  StatusReg;
425 
426   UINT32                  DataLen;
427 
428   QH_STRUCT               *PtrQH;
429   TD_STRUCT               *PtrFirstTD;
430   TD_STRUCT               *PtrTD;
431   TD_STRUCT               *PtrPreTD;
432 
433   UINT8                   PktID;
434   UINT8                   *PtrDataSource;
435   UINT8                   *Ptr;
436 
437   BOOLEAN                 IsFirstTD;
438 
439   EFI_STATUS              Status;
440 
441   EFI_USB_DATA_DIRECTION  TransferDirection;
442 
443   BOOLEAN                 ShortPacketEnable;
444 
445   UINT16                  CommandContent;
446 
447   UhcDev = PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This);
448 
449   //
450   // Enable the maximum packet size (64bytes)
451   // that can be used for full speed bandwidth reclamation
452   // at the end of a frame.
453   //
454   CommandContent = USBReadPortW (UhcDev, UhcDev->UsbHostControllerBaseAddress + USBCMD);
455   if ((CommandContent & USBCMD_MAXP) != USBCMD_MAXP) {
456     CommandContent |= USBCMD_MAXP;
457     USBWritePortW (UhcDev, UhcDev->UsbHostControllerBaseAddress + USBCMD, CommandContent);
458   }
459 
460   StatusReg   = UhcDev->UsbHostControllerBaseAddress + USBSTS;
461 
462   //
463   // these code lines are added here per complier's strict demand
464   //
465   PktID             = INPUT_PACKET_ID;
466   PtrTD             = NULL;
467   PtrFirstTD        = NULL;
468   PtrPreTD          = NULL;
469   DataLen           = 0;
470   Ptr               = NULL;
471 
472   ShortPacketEnable = FALSE;
473 
474   if ((DataLength == 0) || (Data == NULL) || (TransferResult == NULL)) {
475     return EFI_INVALID_PARAMETER;
476   }
477 
478   if ((*DataToggle != 1) && (*DataToggle != 0)) {
479     return EFI_INVALID_PARAMETER;
480   }
481 
482   if (MaximumPacketLength != 8 && MaximumPacketLength != 16
483       && MaximumPacketLength != 32 && MaximumPacketLength != 64) {
484     return EFI_INVALID_PARAMETER;
485   }
486   //
487   // if has errors that cause host controller halt, then return EFI_DEVICE_ERROR directly.
488   //
489   if (!IsStatusOK (UhcDev, StatusReg)) {
490 
491     ClearStatusReg (UhcDev, StatusReg);
492     *TransferResult = EFI_USB_ERR_SYSTEM;
493     return EFI_DEVICE_ERROR;
494   }
495 
496   ClearStatusReg (UhcDev, StatusReg);
497 
498   if ((EndPointAddress & 0x80) != 0) {
499     TransferDirection = EfiUsbDataIn;
500   } else {
501     TransferDirection = EfiUsbDataOut;
502   }
503 
504   switch (TransferDirection) {
505 
506   case EfiUsbDataIn:
507     ShortPacketEnable = TRUE;
508     PktID             = INPUT_PACKET_ID;
509     PtrDataSource     = Data;
510     DataLen           = (UINT32) *DataLength;
511     Ptr               = PtrDataSource;
512     break;
513 
514   case EfiUsbDataOut:
515     PktID         = OUTPUT_PACKET_ID;
516     PtrDataSource = Data;
517     DataLen       = (UINT32) *DataLength;
518     Ptr           = PtrDataSource;
519     break;
520 
521   default:
522     break;
523   }
524 
525   PtrQH = UhcDev->BulkQH;
526 
527   IsFirstTD = TRUE;
528   while (DataLen > 0) {
529     //
530     // create TD structures and link together
531     //
532     UINT8 PacketSize;
533 
534     PacketSize = (UINT8) DataLen;
535     if (DataLen > MaximumPacketLength) {
536       PacketSize = MaximumPacketLength;
537     }
538 
539     GenDataTD (
540       UhcDev,
541       DeviceAddress,
542       EndPointAddress,
543       Ptr,
544       PacketSize,
545       PktID,
546       *DataToggle,
547       USB_FULL_SPEED_DEVICE,
548       &PtrTD
549       );
550 
551     //
552     // Enable short packet detection.
553     // (default action is disabling short packet detection)
554     //
555     if (ShortPacketEnable) {
556       EnableorDisableTDShortPacket (PtrTD, TRUE);
557     }
558 
559     if (IsFirstTD) {
560       PtrFirstTD            = PtrTD;
561       PtrFirstTD->PtrNextTD = NULL;
562       IsFirstTD             = FALSE;
563     } else {
564       //
565       // Link two TDs in vertical depth
566       //
567       LinkTDToTD (PtrPreTD, PtrTD);
568     }
569 
570     PtrPreTD = PtrTD;
571 
572     *DataToggle ^= 1;
573     Ptr += PacketSize;
574     DataLen -= PacketSize;
575   }
576   //
577   // link TD structures to QH structure
578   //
579   LinkTDToQH (PtrQH, PtrFirstTD);
580 
581   //
582   // Execute QH-TD and get result
583   //
584   //
585   // detail status is put into the Result field in the pIRP
586   // the Data Toggle value is also re-updated to the value
587   // of the last successful TD
588   //
589   Status = ExecBulkTransfer (
590             UhcDev,
591             PtrFirstTD,
592             DataLength,
593             DataToggle,
594             TimeOut,
595             TransferResult
596             );
597 
598   //
599   // Delete Bulk transfer TD structure
600   //
601   DeleteQueuedTDs (UhcDev, PtrFirstTD);
602 
603   //
604   // if has errors that cause host controller halt, then return EFI_DEVICE_ERROR directly.
605   //
606   if (!IsStatusOK (UhcDev, StatusReg)) {
607 
608     ClearStatusReg (UhcDev, StatusReg);
609     *TransferResult |= EFI_USB_ERR_SYSTEM;
610     return EFI_DEVICE_ERROR;
611   }
612 
613   ClearStatusReg (UhcDev, StatusReg);
614 
615   return Status;
616 }
617 
618 /**
619   Retrieves the number of root hub ports.
620 
621   @param[in]  PeiServices   The pointer to the PEI Services Table.
622   @param[in]  This          The pointer to this instance of the
623                             PEI_USB_HOST_CONTROLLER_PPI.
624   @param[out] PortNumber    The pointer to the number of the root hub ports.
625 
626   @retval EFI_SUCCESS           The port number was retrieved successfully.
627   @retval EFI_INVALID_PARAMETER PortNumber is NULL.
628 
629 **/
630 EFI_STATUS
631 EFIAPI
UhcGetRootHubPortNumber(IN EFI_PEI_SERVICES ** PeiServices,IN PEI_USB_HOST_CONTROLLER_PPI * This,OUT UINT8 * PortNumber)632 UhcGetRootHubPortNumber (
633   IN EFI_PEI_SERVICES               **PeiServices,
634   IN PEI_USB_HOST_CONTROLLER_PPI    *This,
635   OUT UINT8                         *PortNumber
636   )
637 {
638   USB_UHC_DEV *UhcDev;
639   UINT32      PSAddr;
640   UINT16      RHPortControl;
641   UINT32      Index;
642 
643   UhcDev = PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This);
644 
645   if (PortNumber == NULL) {
646     return EFI_INVALID_PARAMETER;
647   }
648 
649   *PortNumber = 0;
650 
651   for (Index = 0; Index < 2; Index++) {
652     PSAddr = UhcDev->UsbHostControllerBaseAddress + USBPORTSC1 + Index * 2;
653     RHPortControl = USBReadPortW (UhcDev, PSAddr);
654     //
655     // Port Register content is valid
656     //
657     if (RHPortControl != 0xff) {
658       (*PortNumber)++;
659     }
660   }
661 
662   return EFI_SUCCESS;
663 }
664 
665 /**
666   Retrieves the current status of a USB root hub port.
667 
668   @param  PeiServices            The pointer of EFI_PEI_SERVICES.
669   @param  This                   The pointer of PEI_USB_HOST_CONTROLLER_PPI.
670   @param  PortNumber             The root hub port to retrieve the state from.
671   @param  PortStatus             Variable to receive the port state.
672 
673   @retval EFI_SUCCESS            The status of the USB root hub port specified.
674                                  by PortNumber was returned in PortStatus.
675   @retval EFI_INVALID_PARAMETER  PortNumber is invalid.
676 
677 **/
678 EFI_STATUS
679 EFIAPI
UhcGetRootHubPortStatus(IN EFI_PEI_SERVICES ** PeiServices,IN PEI_USB_HOST_CONTROLLER_PPI * This,IN UINT8 PortNumber,OUT EFI_USB_PORT_STATUS * PortStatus)680 UhcGetRootHubPortStatus (
681   IN EFI_PEI_SERVICES               **PeiServices,
682   IN PEI_USB_HOST_CONTROLLER_PPI    *This,
683   IN  UINT8                         PortNumber,
684   OUT EFI_USB_PORT_STATUS           *PortStatus
685   )
686 {
687   USB_UHC_DEV *UhcDev;
688   UINT32      PSAddr;
689   UINT16      RHPortStatus;
690   UINT8       TotalPortNumber;
691 
692   if (PortStatus == NULL) {
693     return EFI_INVALID_PARAMETER;
694   }
695 
696   UhcGetRootHubPortNumber (PeiServices, This, &TotalPortNumber);
697   if (PortNumber > TotalPortNumber) {
698     return EFI_INVALID_PARAMETER;
699   }
700 
701   UhcDev                        = PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This);
702   PSAddr                        = UhcDev->UsbHostControllerBaseAddress + USBPORTSC1 + PortNumber * 2;
703 
704   PortStatus->PortStatus        = 0;
705   PortStatus->PortChangeStatus  = 0;
706 
707   RHPortStatus = USBReadPortW (UhcDev, PSAddr);
708 
709   //
710   // Current Connect Status
711   //
712   if ((RHPortStatus & USBPORTSC_CCS) != 0) {
713     PortStatus->PortStatus |= USB_PORT_STAT_CONNECTION;
714   }
715   //
716   // Port Enabled/Disabled
717   //
718   if ((RHPortStatus & USBPORTSC_PED) != 0) {
719     PortStatus->PortStatus |= USB_PORT_STAT_ENABLE;
720   }
721   //
722   // Port Suspend
723   //
724   if ((RHPortStatus & USBPORTSC_SUSP) != 0) {
725     PortStatus->PortStatus |= USB_PORT_STAT_SUSPEND;
726   }
727   //
728   // Port Reset
729   //
730   if ((RHPortStatus & USBPORTSC_PR) != 0) {
731     PortStatus->PortStatus |= USB_PORT_STAT_RESET;
732   }
733   //
734   // Low Speed Device Attached
735   //
736   if ((RHPortStatus & USBPORTSC_LSDA) != 0) {
737     PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;
738   }
739   //
740   //   Fill Port Status Change bits
741   //
742   //
743   // Connect Status Change
744   //
745   if ((RHPortStatus & USBPORTSC_CSC) != 0) {
746     PortStatus->PortChangeStatus |= USB_PORT_STAT_C_CONNECTION;
747   }
748   //
749   // Port Enabled/Disabled Change
750   //
751   if ((RHPortStatus & USBPORTSC_PEDC) != 0) {
752     PortStatus->PortChangeStatus |= USB_PORT_STAT_C_ENABLE;
753   }
754 
755   return EFI_SUCCESS;
756 }
757 
758 /**
759   Sets a feature for the specified root hub port.
760 
761   @param  PeiServices           The pointer of EFI_PEI_SERVICES
762   @param  This                  The pointer of PEI_USB_HOST_CONTROLLER_PPI
763   @param  PortNumber            Root hub port to set.
764   @param  PortFeature           Feature to set.
765 
766   @retval EFI_SUCCESS            The feature specified by PortFeature was set.
767   @retval EFI_INVALID_PARAMETER  PortNumber is invalid or PortFeature is invalid.
768   @retval EFI_TIMEOUT            The time out occurred.
769 
770 **/
771 EFI_STATUS
772 EFIAPI
UhcSetRootHubPortFeature(IN EFI_PEI_SERVICES ** PeiServices,IN PEI_USB_HOST_CONTROLLER_PPI * This,IN UINT8 PortNumber,IN EFI_USB_PORT_FEATURE PortFeature)773 UhcSetRootHubPortFeature (
774   IN EFI_PEI_SERVICES               **PeiServices,
775   IN PEI_USB_HOST_CONTROLLER_PPI    *This,
776   IN UINT8                          PortNumber,
777   IN EFI_USB_PORT_FEATURE           PortFeature
778   )
779 {
780   USB_UHC_DEV *UhcDev;
781   UINT32      PSAddr;
782   UINT32      CommandRegAddr;
783   UINT16      RHPortControl;
784   UINT8       TotalPortNumber;
785 
786   UhcGetRootHubPortNumber (PeiServices, This, &TotalPortNumber);
787   if (PortNumber > TotalPortNumber) {
788     return EFI_INVALID_PARAMETER;
789   }
790 
791   UhcDev          = PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This);
792   PSAddr          = UhcDev->UsbHostControllerBaseAddress + USBPORTSC1 + PortNumber * 2;
793   CommandRegAddr  = UhcDev->UsbHostControllerBaseAddress + USBCMD;
794 
795   RHPortControl = USBReadPortW (UhcDev, PSAddr);
796 
797   switch (PortFeature) {
798 
799   case EfiUsbPortSuspend:
800     if ((USBReadPortW (UhcDev, CommandRegAddr) & USBCMD_EGSM) == 0) {
801       //
802       // if global suspend is not active, can set port suspend
803       //
804       RHPortControl &= 0xfff5;
805       RHPortControl |= USBPORTSC_SUSP;
806     }
807     break;
808 
809   case EfiUsbPortReset:
810     RHPortControl &= 0xfff5;
811     RHPortControl |= USBPORTSC_PR;
812     //
813     // Set the reset bit
814     //
815     break;
816 
817   case EfiUsbPortPower:
818     break;
819 
820   case EfiUsbPortEnable:
821     RHPortControl &= 0xfff5;
822     RHPortControl |= USBPORTSC_PED;
823     break;
824 
825   default:
826     return EFI_INVALID_PARAMETER;
827   }
828 
829   USBWritePortW (UhcDev, PSAddr, RHPortControl);
830 
831   return EFI_SUCCESS;
832 }
833 
834 /**
835   Clears a feature for the specified root hub port.
836 
837   @param  PeiServices           The pointer of EFI_PEI_SERVICES.
838   @param  This                  The pointer of PEI_USB_HOST_CONTROLLER_PPI.
839   @param  PortNumber            Specifies the root hub port whose feature
840                                 is requested to be cleared.
841   @param  PortFeature           Indicates the feature selector associated with the
842                                 feature clear request.
843 
844   @retval EFI_SUCCESS            The feature specified by PortFeature was cleared
845                                  for the USB root hub port specified by PortNumber.
846   @retval EFI_INVALID_PARAMETER  PortNumber is invalid or PortFeature is invalid.
847 
848 **/
849 EFI_STATUS
850 EFIAPI
UhcClearRootHubPortFeature(IN EFI_PEI_SERVICES ** PeiServices,IN PEI_USB_HOST_CONTROLLER_PPI * This,IN UINT8 PortNumber,IN EFI_USB_PORT_FEATURE PortFeature)851 UhcClearRootHubPortFeature (
852   IN EFI_PEI_SERVICES               **PeiServices,
853   IN PEI_USB_HOST_CONTROLLER_PPI    *This,
854   IN UINT8                          PortNumber,
855   IN EFI_USB_PORT_FEATURE           PortFeature
856   )
857 {
858   USB_UHC_DEV *UhcDev;
859   UINT32      PSAddr;
860   UINT16      RHPortControl;
861   UINT8       TotalPortNumber;
862 
863   UhcGetRootHubPortNumber (PeiServices, This, &TotalPortNumber);
864 
865   if (PortNumber > TotalPortNumber) {
866     return EFI_INVALID_PARAMETER;
867   }
868 
869   UhcDev  = PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This);
870   PSAddr  = UhcDev->UsbHostControllerBaseAddress + USBPORTSC1 + PortNumber * 2;
871 
872   RHPortControl = USBReadPortW (UhcDev, PSAddr);
873 
874   switch (PortFeature) {
875   //
876   // clear PORT_ENABLE feature means disable port.
877   //
878   case EfiUsbPortEnable:
879     RHPortControl &= 0xfff5;
880     RHPortControl &= ~USBPORTSC_PED;
881     break;
882 
883   //
884   // clear PORT_SUSPEND feature means resume the port.
885   // (cause a resume on the specified port if in suspend mode)
886   //
887   case EfiUsbPortSuspend:
888     RHPortControl &= 0xfff5;
889     RHPortControl &= ~USBPORTSC_SUSP;
890     break;
891 
892   //
893   // no operation
894   //
895   case EfiUsbPortPower:
896     break;
897 
898   //
899   // clear PORT_RESET means clear the reset signal.
900   //
901   case EfiUsbPortReset:
902     RHPortControl &= 0xfff5;
903     RHPortControl &= ~USBPORTSC_PR;
904     break;
905 
906   //
907   // clear connect status change
908   //
909   case EfiUsbPortConnectChange:
910     RHPortControl &= 0xfff5;
911     RHPortControl |= USBPORTSC_CSC;
912     break;
913 
914   //
915   // clear enable/disable status change
916   //
917   case EfiUsbPortEnableChange:
918     RHPortControl &= 0xfff5;
919     RHPortControl |= USBPORTSC_PEDC;
920     break;
921 
922   //
923   // root hub does not support this request
924   //
925   case EfiUsbPortSuspendChange:
926     break;
927 
928   //
929   // root hub does not support this request
930   //
931   case EfiUsbPortOverCurrentChange:
932     break;
933 
934   //
935   // root hub does not support this request
936   //
937   case EfiUsbPortResetChange:
938     break;
939 
940   default:
941     return EFI_INVALID_PARAMETER;
942   }
943 
944   USBWritePortW (UhcDev, PSAddr, RHPortControl);
945 
946   return EFI_SUCCESS;
947 }
948 
949 /**
950   Initialize UHCI.
951 
952   @param  UhcDev                 UHCI Device.
953 
954   @retval EFI_SUCCESS            UHCI successfully initialized.
955   @retval EFI_OUT_OF_RESOURCES   Resource can not be allocated.
956 
957 **/
958 EFI_STATUS
InitializeUsbHC(IN USB_UHC_DEV * UhcDev)959 InitializeUsbHC (
960   IN USB_UHC_DEV          *UhcDev
961   )
962 {
963   EFI_STATUS  Status;
964   UINT32      FrameListBaseAddrReg;
965   UINT32      CommandReg;
966   UINT16      Command;
967 
968   //
969   // Create and Initialize Frame List For the Host Controller.
970   //
971   Status = CreateFrameList (UhcDev);
972   if (EFI_ERROR (Status)) {
973     return Status;
974   }
975 
976   FrameListBaseAddrReg  = UhcDev->UsbHostControllerBaseAddress + USBFLBASEADD;
977   CommandReg            = UhcDev->UsbHostControllerBaseAddress + USBCMD;
978 
979   //
980   // Set Frame List Base Address to the specific register to inform the hardware.
981   //
982   SetFrameListBaseAddress (UhcDev, FrameListBaseAddrReg, (UINT32) (UINTN) (UhcDev->FrameListEntry));
983 
984   Command = USBReadPortW (UhcDev, CommandReg);
985   Command |= USBCMD_GRESET;
986   USBWritePortW (UhcDev, CommandReg, Command);
987 
988   MicroSecondDelay (50 * 1000);
989 
990 
991   Command &= ~USBCMD_GRESET;
992 
993   USBWritePortW (UhcDev, CommandReg, Command);
994 
995   //
996   //UHCI spec page120 reset recovery time
997   //
998   MicroSecondDelay (20 * 1000);
999 
1000   //
1001   // Set Run/Stop bit to 1.
1002   //
1003   Command = USBReadPortW (UhcDev, CommandReg);
1004   Command |= USBCMD_RS | USBCMD_MAXP;
1005   USBWritePortW (UhcDev, CommandReg, Command);
1006 
1007   return EFI_SUCCESS;
1008 }
1009 
1010 /**
1011   Create Frame List Structure.
1012 
1013   @param  UhcDev                 UHCI device.
1014 
1015   @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resources.
1016   @retval EFI_SUCCESS            Success.
1017 
1018 **/
1019 EFI_STATUS
CreateFrameList(USB_UHC_DEV * UhcDev)1020 CreateFrameList (
1021   USB_UHC_DEV             *UhcDev
1022   )
1023 {
1024   EFI_STATUS            Status;
1025   EFI_PHYSICAL_ADDRESS  FrameListBaseAddr;
1026   FRAMELIST_ENTRY       *FrameListPtr;
1027   UINTN                 Index;
1028 
1029   //
1030   // The Frame List ocupies 4K bytes,
1031   // and must be aligned on 4-Kbyte boundaries.
1032   //
1033   Status = PeiServicesAllocatePages (
1034              EfiBootServicesData,
1035              1,
1036              &FrameListBaseAddr
1037              );
1038 
1039   if (Status != EFI_SUCCESS) {
1040     return EFI_OUT_OF_RESOURCES;
1041   }
1042 
1043   //
1044   //Create Control QH and Bulk QH and link them into Framelist Entry
1045   //
1046   Status = CreateQH(UhcDev, &UhcDev->ConfigQH);
1047   if (Status != EFI_SUCCESS) {
1048     return EFI_OUT_OF_RESOURCES;
1049   }
1050   ASSERT (UhcDev->ConfigQH != NULL);
1051 
1052   Status = CreateQH(UhcDev, &UhcDev->BulkQH);
1053   if (Status != EFI_SUCCESS) {
1054     return EFI_OUT_OF_RESOURCES;
1055   }
1056   ASSERT (UhcDev->BulkQH != NULL);
1057 
1058   //
1059   //Set the corresponding QH pointer
1060   //
1061   SetQHHorizontalLinkPtr(UhcDev->ConfigQH, UhcDev->BulkQH);
1062   SetQHHorizontalQHorTDSelect (UhcDev->ConfigQH, TRUE);
1063   SetQHHorizontalValidorInvalid (UhcDev->ConfigQH, TRUE);
1064 
1065   UhcDev->FrameListEntry = (FRAMELIST_ENTRY *) ((UINTN) FrameListBaseAddr);
1066 
1067   FrameListPtr = UhcDev->FrameListEntry;
1068 
1069   for (Index = 0; Index < 1024; Index++) {
1070     FrameListPtr->FrameListPtrTerminate = 0;
1071     FrameListPtr->FrameListPtr          = (UINT32)(UINTN)UhcDev->ConfigQH >> 4;
1072     FrameListPtr->FrameListPtrQSelect   = 1;
1073     FrameListPtr->FrameListRsvd         = 0;
1074     FrameListPtr ++;
1075   }
1076 
1077   return EFI_SUCCESS;
1078 }
1079 
1080 /**
1081   Read a 16bit width data from Uhc HC IO space register.
1082 
1083   @param  UhcDev  The UHCI device.
1084   @param  Port    The IO space address of the register.
1085 
1086   @retval the register content read.
1087 
1088 **/
1089 UINT16
USBReadPortW(IN USB_UHC_DEV * UhcDev,IN UINT32 Port)1090 USBReadPortW (
1091   IN  USB_UHC_DEV   *UhcDev,
1092   IN  UINT32        Port
1093   )
1094 {
1095   return IoRead16 (Port);
1096 }
1097 
1098 /**
1099   Write a 16bit width data into Uhc HC IO space register.
1100 
1101   @param  UhcDev  The UHCI device.
1102   @param  Port    The IO space address of the register.
1103   @param  Data    The data written into the register.
1104 
1105 **/
1106 VOID
USBWritePortW(IN USB_UHC_DEV * UhcDev,IN UINT32 Port,IN UINT16 Data)1107 USBWritePortW (
1108   IN  USB_UHC_DEV   *UhcDev,
1109   IN  UINT32        Port,
1110   IN  UINT16        Data
1111   )
1112 {
1113   IoWrite16 (Port, Data);
1114 }
1115 
1116 /**
1117   Write a 32bit width data into Uhc HC IO space register.
1118 
1119   @param  UhcDev  The UHCI device.
1120   @param  Port    The IO space address of the register.
1121   @param  Data    The data written into the register.
1122 
1123 **/
1124 VOID
USBWritePortDW(IN USB_UHC_DEV * UhcDev,IN UINT32 Port,IN UINT32 Data)1125 USBWritePortDW (
1126   IN  USB_UHC_DEV   *UhcDev,
1127   IN  UINT32        Port,
1128   IN  UINT32        Data
1129   )
1130 {
1131   IoWrite32 (Port, Data);
1132 }
1133 
1134 /**
1135   Clear the content of UHCI's Status Register.
1136 
1137   @param  UhcDev       The UHCI device.
1138   @param  StatusAddr   The IO space address of the register.
1139 
1140 **/
1141 VOID
ClearStatusReg(IN USB_UHC_DEV * UhcDev,IN UINT32 StatusAddr)1142 ClearStatusReg (
1143   IN  USB_UHC_DEV   *UhcDev,
1144   IN  UINT32        StatusAddr
1145   )
1146 {
1147   //
1148   // Clear the content of UHCI's Status Register
1149   //
1150   USBWritePortW (UhcDev, StatusAddr, 0x003F);
1151 }
1152 
1153 /**
1154   Check whether the host controller operates well.
1155 
1156   @param  UhcDev        The UHCI device.
1157   @param  StatusRegAddr The io address of status register.
1158 
1159   @retval TRUE          Host controller is working.
1160   @retval FALSE         Host controller is halted or system error.
1161 
1162 **/
1163 BOOLEAN
IsStatusOK(IN USB_UHC_DEV * UhcDev,IN UINT32 StatusRegAddr)1164 IsStatusOK (
1165   IN USB_UHC_DEV     *UhcDev,
1166   IN UINT32          StatusRegAddr
1167   )
1168 {
1169   UINT16  StatusValue;
1170 
1171   StatusValue = USBReadPortW (UhcDev, StatusRegAddr);
1172 
1173   if ((StatusValue & (USBSTS_HCPE | USBSTS_HSE | USBSTS_HCH)) != 0) {
1174     return FALSE;
1175   } else {
1176     return TRUE;
1177   }
1178 }
1179 
1180 /**
1181   Get Current Frame Number.
1182 
1183   @param  UhcDev          The UHCI device.
1184   @param  FrameNumberAddr The address of frame list register.
1185 
1186   @retval The content of the frame list register.
1187 
1188 **/
1189 UINT16
GetCurrentFrameNumber(IN USB_UHC_DEV * UhcDev,IN UINT32 FrameNumberAddr)1190 GetCurrentFrameNumber (
1191   IN USB_UHC_DEV   *UhcDev,
1192   IN UINT32        FrameNumberAddr
1193   )
1194 {
1195   //
1196   // Gets value in the USB frame number register.
1197   //
1198   return (UINT16) (USBReadPortW (UhcDev, FrameNumberAddr) & 0x03FF);
1199 }
1200 
1201 /**
1202   Set Frame List Base Address.
1203 
1204   @param  UhcDev           The UHCI device.
1205   @param  FrameListRegAddr The address of frame list register.
1206   @param  Addr             The address of frame list table.
1207 
1208 **/
1209 VOID
SetFrameListBaseAddress(IN USB_UHC_DEV * UhcDev,IN UINT32 FrameListRegAddr,IN UINT32 Addr)1210 SetFrameListBaseAddress (
1211   IN USB_UHC_DEV   *UhcDev,
1212   IN UINT32        FrameListRegAddr,
1213   IN UINT32        Addr
1214   )
1215 {
1216   //
1217   // Sets value in the USB Frame List Base Address register.
1218   //
1219   USBWritePortDW (UhcDev, FrameListRegAddr, (UINT32) (Addr & 0xFFFFF000));
1220 }
1221 
1222 /**
1223   Create QH and initialize.
1224 
1225   @param  UhcDev               The UHCI device.
1226   @param  PtrQH                Place to store QH_STRUCT pointer.
1227 
1228   @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
1229   @retval EFI_SUCCESS        Success.
1230 
1231 **/
1232 EFI_STATUS
CreateQH(IN USB_UHC_DEV * UhcDev,OUT QH_STRUCT ** PtrQH)1233 CreateQH (
1234   IN  USB_UHC_DEV   *UhcDev,
1235   OUT QH_STRUCT     **PtrQH
1236   )
1237 {
1238   EFI_STATUS  Status;
1239 
1240   //
1241   // allocate align memory for QH_STRUCT
1242   //
1243   Status = AllocateTDorQHStruct (UhcDev, sizeof(QH_STRUCT), (void **)PtrQH);
1244   if (EFI_ERROR (Status)) {
1245     return EFI_OUT_OF_RESOURCES;
1246   }
1247   //
1248   // init each field of the QH_STRUCT
1249   //
1250   SetQHHorizontalValidorInvalid (*PtrQH, FALSE);
1251   SetQHVerticalValidorInvalid (*PtrQH, FALSE);
1252 
1253   return EFI_SUCCESS;
1254 }
1255 
1256 /**
1257   Set the horizontal link pointer in QH.
1258 
1259   @param  PtrQH               Place to store QH_STRUCT pointer.
1260   @param  PtrNext             Place to the next QH_STRUCT.
1261 
1262 **/
1263 VOID
SetQHHorizontalLinkPtr(IN QH_STRUCT * PtrQH,IN VOID * PtrNext)1264 SetQHHorizontalLinkPtr (
1265   IN QH_STRUCT  *PtrQH,
1266   IN VOID       *PtrNext
1267   )
1268 {
1269   //
1270   // Since the QH_STRUCT is aligned on 16-byte boundaries,
1271   // Only the highest 28bit of the address is valid
1272   // (take 32bit address as an example).
1273   //
1274   PtrQH->QueueHead.QHHorizontalPtr = (UINT32) (UINTN) PtrNext >> 4;
1275 }
1276 
1277 /**
1278   Get the horizontal link pointer in QH.
1279 
1280   @param  PtrQH     Place to store QH_STRUCT pointer.
1281 
1282   @retval The horizontal link pointer in QH.
1283 
1284 **/
1285 VOID *
GetQHHorizontalLinkPtr(IN QH_STRUCT * PtrQH)1286 GetQHHorizontalLinkPtr (
1287   IN QH_STRUCT  *PtrQH
1288   )
1289 {
1290   //
1291   // Restore the 28bit address to 32bit address
1292   // (take 32bit address as an example)
1293   //
1294   return (VOID *) (UINTN) ((PtrQH->QueueHead.QHHorizontalPtr) << 4);
1295 }
1296 
1297 /**
1298   Set a QH or TD horizontally to be connected with a specific QH.
1299 
1300   @param  PtrQH      Place to store QH_STRUCT pointer.
1301   @param  IsQH       Specify QH or TD is connected.
1302 
1303 **/
1304 VOID
SetQHHorizontalQHorTDSelect(IN QH_STRUCT * PtrQH,IN BOOLEAN IsQH)1305 SetQHHorizontalQHorTDSelect (
1306   IN QH_STRUCT  *PtrQH,
1307   IN BOOLEAN    IsQH
1308   )
1309 {
1310   //
1311   // if QH is connected, the specified bit is set,
1312   // if TD is connected, the specified bit is cleared.
1313   //
1314   PtrQH->QueueHead.QHHorizontalQSelect = IsQH ? 1 : 0;
1315 }
1316 
1317 /**
1318   Set the horizontal validor bit in QH.
1319 
1320   @param  PtrQH      Place to store QH_STRUCT pointer.
1321   @param  IsValid    Specify the horizontal linker is valid or not.
1322 
1323 **/
1324 VOID
SetQHHorizontalValidorInvalid(IN QH_STRUCT * PtrQH,IN BOOLEAN IsValid)1325 SetQHHorizontalValidorInvalid (
1326   IN QH_STRUCT  *PtrQH,
1327   IN BOOLEAN    IsValid
1328   )
1329 {
1330   //
1331   // Valid means the horizontal link pointer is valid,
1332   // else, it's invalid.
1333   //
1334   PtrQH->QueueHead.QHHorizontalTerminate = IsValid ? 0 : 1;
1335 }
1336 
1337 /**
1338   Set the vertical link pointer in QH.
1339 
1340   @param  PtrQH       Place to store QH_STRUCT pointer.
1341   @param  PtrNext     Place to the next QH_STRUCT.
1342 
1343 **/
1344 VOID
SetQHVerticalLinkPtr(IN QH_STRUCT * PtrQH,IN VOID * PtrNext)1345 SetQHVerticalLinkPtr (
1346   IN QH_STRUCT  *PtrQH,
1347   IN VOID       *PtrNext
1348   )
1349 {
1350   //
1351   // Since the QH_STRUCT is aligned on 16-byte boundaries,
1352   // Only the highest 28bit of the address is valid
1353   // (take 32bit address as an example).
1354   //
1355   PtrQH->QueueHead.QHVerticalPtr = (UINT32) (UINTN) PtrNext >> 4;
1356 }
1357 
1358 /**
1359   Set a QH or TD vertically to be connected with a specific QH.
1360 
1361   @param  PtrQH      Place to store QH_STRUCT pointer.
1362   @param  IsQH       Specify QH or TD is connected.
1363 
1364 **/
1365 VOID
SetQHVerticalQHorTDSelect(IN QH_STRUCT * PtrQH,IN BOOLEAN IsQH)1366 SetQHVerticalQHorTDSelect (
1367   IN QH_STRUCT  *PtrQH,
1368   IN BOOLEAN    IsQH
1369   )
1370 {
1371   //
1372   // Set the specified bit if the Vertical Link Pointer pointing to a QH,
1373   // Clear the specified bit if the Vertical Link Pointer pointing to a TD.
1374   //
1375   PtrQH->QueueHead.QHVerticalQSelect = IsQH ? 1 : 0;
1376 }
1377 
1378 /**
1379   Set the vertical validor bit in QH.
1380 
1381   @param  PtrQH      Place to store QH_STRUCT pointer.
1382   @param  IsValid    Specify the vertical linker is valid or not.
1383 
1384 **/
1385 VOID
SetQHVerticalValidorInvalid(IN QH_STRUCT * PtrQH,IN BOOLEAN IsValid)1386 SetQHVerticalValidorInvalid (
1387   IN QH_STRUCT  *PtrQH,
1388   IN BOOLEAN    IsValid
1389   )
1390 {
1391   //
1392   // If TRUE, meaning the Vertical Link Pointer field is valid,
1393   // else, the field is invalid.
1394   //
1395   PtrQH->QueueHead.QHVerticalTerminate = IsValid ? 0 : 1;
1396 }
1397 
1398 /**
1399   Get the vertical validor bit in QH.
1400 
1401   @param  PtrQH      Place to store QH_STRUCT pointer.
1402 
1403   @retval The vertical linker is valid or not.
1404 
1405 **/
1406 BOOLEAN
GetQHHorizontalValidorInvalid(IN QH_STRUCT * PtrQH)1407 GetQHHorizontalValidorInvalid (
1408   IN QH_STRUCT  *PtrQH
1409   )
1410 {
1411   //
1412   // If TRUE, meaning the Horizontal Link Pointer field is valid,
1413   // else, the field is invalid.
1414   //
1415   return (BOOLEAN) (!(PtrQH->QueueHead.QHHorizontalTerminate));
1416 }
1417 
1418 /**
1419   Allocate TD or QH Struct.
1420 
1421   @param  UhcDev                 The UHCI device.
1422   @param  Size                   The size of allocation.
1423   @param  PtrStruct              Place to store TD_STRUCT pointer.
1424 
1425   @return EFI_SUCCESS            Allocate successfully.
1426   @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resource.
1427 
1428 **/
1429 EFI_STATUS
AllocateTDorQHStruct(IN USB_UHC_DEV * UhcDev,IN UINT32 Size,OUT VOID ** PtrStruct)1430 AllocateTDorQHStruct (
1431   IN  USB_UHC_DEV     *UhcDev,
1432   IN  UINT32          Size,
1433   OUT VOID            **PtrStruct
1434   )
1435 {
1436   EFI_STATUS  Status;
1437 
1438   Status      = EFI_SUCCESS;
1439   *PtrStruct  = NULL;
1440 
1441   Status = UhcAllocatePool (
1442             UhcDev,
1443             (UINT8 **) PtrStruct,
1444             Size
1445             );
1446   if (EFI_ERROR (Status)) {
1447     return Status;
1448   }
1449 
1450   ZeroMem (*PtrStruct, Size);
1451 
1452   return Status;
1453 }
1454 
1455 /**
1456   Create a TD Struct.
1457 
1458   @param  UhcDev                 The UHCI device.
1459   @param  PtrTD                  Place to store TD_STRUCT pointer.
1460 
1461   @return EFI_SUCCESS            Allocate successfully.
1462   @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resource.
1463 
1464 **/
1465 EFI_STATUS
CreateTD(IN USB_UHC_DEV * UhcDev,OUT TD_STRUCT ** PtrTD)1466 CreateTD (
1467   IN  USB_UHC_DEV     *UhcDev,
1468   OUT TD_STRUCT       **PtrTD
1469   )
1470 {
1471   EFI_STATUS  Status;
1472   //
1473   // create memory for TD_STRUCT, and align the memory.
1474   //
1475   Status = AllocateTDorQHStruct (UhcDev, sizeof(TD_STRUCT), (void **)PtrTD);
1476   if (EFI_ERROR (Status)) {
1477     return Status;
1478   }
1479 
1480   //
1481   // Make TD ready.
1482   //
1483   SetTDLinkPtrValidorInvalid (*PtrTD, FALSE);
1484 
1485   return EFI_SUCCESS;
1486 }
1487 
1488 /**
1489   Generate Setup Stage TD.
1490 
1491   @param  UhcDev       The UHCI device.
1492   @param  DevAddr      Device address.
1493   @param  Endpoint     Endpoint number.
1494   @param  DeviceSpeed  Device Speed.
1495   @param  DevRequest   Device reuquest.
1496   @param  RequestLen   Request length.
1497   @param  PtrTD        TD_STRUCT generated.
1498 
1499   @return EFI_SUCCESS            Generate setup stage TD successfully.
1500   @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resource.
1501 
1502 **/
1503 EFI_STATUS
GenSetupStageTD(IN USB_UHC_DEV * UhcDev,IN UINT8 DevAddr,IN UINT8 Endpoint,IN UINT8 DeviceSpeed,IN UINT8 * DevRequest,IN UINT8 RequestLen,OUT TD_STRUCT ** PtrTD)1504 GenSetupStageTD (
1505   IN  USB_UHC_DEV     *UhcDev,
1506   IN  UINT8           DevAddr,
1507   IN  UINT8           Endpoint,
1508   IN  UINT8           DeviceSpeed,
1509   IN  UINT8           *DevRequest,
1510   IN  UINT8           RequestLen,
1511   OUT TD_STRUCT       **PtrTD
1512   )
1513 {
1514   TD_STRUCT   *TdStruct;
1515   EFI_STATUS  Status;
1516 
1517   Status = CreateTD (UhcDev, &TdStruct);
1518   if (EFI_ERROR (Status)) {
1519     return Status;
1520   }
1521 
1522   SetTDLinkPtr (TdStruct, NULL);
1523 
1524   //
1525   // Depth first fashion
1526   //
1527   SetTDLinkPtrDepthorBreadth (TdStruct, TRUE);
1528 
1529   //
1530   // initialize as the last TD in the QH context,
1531   // this field will be updated in the TD linkage process.
1532   //
1533   SetTDLinkPtrValidorInvalid (TdStruct, FALSE);
1534 
1535   //
1536   // Disable Short Packet Detection by default
1537   //
1538   EnableorDisableTDShortPacket (TdStruct, FALSE);
1539 
1540   //
1541   // Max error counter is 3, retry 3 times when error encountered.
1542   //
1543   SetTDControlErrorCounter (TdStruct, 3);
1544 
1545   //
1546   // set device speed attribute
1547   // (TRUE - Slow Device; FALSE - Full Speed Device)
1548   //
1549   switch (DeviceSpeed) {
1550   case USB_SLOW_SPEED_DEVICE:
1551     SetTDLoworFullSpeedDevice (TdStruct, TRUE);
1552     break;
1553 
1554   case USB_FULL_SPEED_DEVICE:
1555     SetTDLoworFullSpeedDevice (TdStruct, FALSE);
1556     break;
1557   }
1558   //
1559   // Non isochronous transfer TD
1560   //
1561   SetTDControlIsochronousorNot (TdStruct, FALSE);
1562 
1563   //
1564   // Interrupt On Complete bit be set to zero,
1565   // Disable IOC interrupt.
1566   //
1567   SetorClearTDControlIOC (TdStruct, FALSE);
1568 
1569   //
1570   // Set TD Active bit
1571   //
1572   SetTDStatusActiveorInactive (TdStruct, TRUE);
1573 
1574   SetTDTokenMaxLength (TdStruct, RequestLen);
1575 
1576   SetTDTokenDataToggle0 (TdStruct);
1577 
1578   SetTDTokenEndPoint (TdStruct, Endpoint);
1579 
1580   SetTDTokenDeviceAddress (TdStruct, DevAddr);
1581 
1582   SetTDTokenPacketID (TdStruct, SETUP_PACKET_ID);
1583 
1584   TdStruct->PtrTDBuffer      = (UINT8 *) DevRequest;
1585   TdStruct->TDBufferLength = RequestLen;
1586   SetTDDataBuffer (TdStruct);
1587 
1588   *PtrTD = TdStruct;
1589 
1590   return EFI_SUCCESS;
1591 }
1592 
1593 /**
1594   Generate Data Stage TD.
1595 
1596   @param  UhcDev       The UHCI device.
1597   @param  DevAddr      Device address.
1598   @param  Endpoint     Endpoint number.
1599   @param  PtrData      Data buffer.
1600   @param  Len          Data length.
1601   @param  PktID        PacketID.
1602   @param  Toggle       Data toggle value.
1603   @param  DeviceSpeed  Device Speed.
1604   @param  PtrTD        TD_STRUCT generated.
1605 
1606   @return EFI_SUCCESS            Generate data stage TD successfully.
1607   @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resource.
1608 
1609 **/
1610 EFI_STATUS
GenDataTD(IN USB_UHC_DEV * UhcDev,IN UINT8 DevAddr,IN UINT8 Endpoint,IN UINT8 * PtrData,IN UINT8 Len,IN UINT8 PktID,IN UINT8 Toggle,IN UINT8 DeviceSpeed,OUT TD_STRUCT ** PtrTD)1611 GenDataTD (
1612   IN  USB_UHC_DEV     *UhcDev,
1613   IN  UINT8           DevAddr,
1614   IN  UINT8           Endpoint,
1615   IN  UINT8           *PtrData,
1616   IN  UINT8           Len,
1617   IN  UINT8           PktID,
1618   IN  UINT8           Toggle,
1619   IN  UINT8           DeviceSpeed,
1620   OUT TD_STRUCT       **PtrTD
1621   )
1622 {
1623   TD_STRUCT   *TdStruct;
1624   EFI_STATUS  Status;
1625 
1626   Status = CreateTD (UhcDev, &TdStruct);
1627   if (EFI_ERROR (Status)) {
1628     return Status;
1629   }
1630 
1631   SetTDLinkPtr (TdStruct, NULL);
1632 
1633   //
1634   // Depth first fashion
1635   //
1636   SetTDLinkPtrDepthorBreadth (TdStruct, TRUE);
1637 
1638   //
1639   // Link pointer pointing to TD struct
1640   //
1641   SetTDLinkPtrQHorTDSelect (TdStruct, FALSE);
1642 
1643   //
1644   // initialize as the last TD in the QH context,
1645   // this field will be updated in the TD linkage process.
1646   //
1647   SetTDLinkPtrValidorInvalid (TdStruct, FALSE);
1648 
1649   //
1650   // Disable short packet detect
1651   //
1652   EnableorDisableTDShortPacket (TdStruct, FALSE);
1653   //
1654   // Max error counter is 3
1655   //
1656   SetTDControlErrorCounter (TdStruct, 3);
1657 
1658   //
1659   // set device speed attribute
1660   // (TRUE - Slow Device; FALSE - Full Speed Device)
1661   //
1662   switch (DeviceSpeed) {
1663   case USB_SLOW_SPEED_DEVICE:
1664     SetTDLoworFullSpeedDevice (TdStruct, TRUE);
1665     break;
1666 
1667   case USB_FULL_SPEED_DEVICE:
1668     SetTDLoworFullSpeedDevice (TdStruct, FALSE);
1669     break;
1670   }
1671   //
1672   // Non isochronous transfer TD
1673   //
1674   SetTDControlIsochronousorNot (TdStruct, FALSE);
1675 
1676   //
1677   // Disable Interrupt On Complete
1678   // Disable IOC interrupt.
1679   //
1680   SetorClearTDControlIOC (TdStruct, FALSE);
1681 
1682   //
1683   // Set Active bit
1684   //
1685   SetTDStatusActiveorInactive (TdStruct, TRUE);
1686 
1687   SetTDTokenMaxLength (TdStruct, Len);
1688 
1689   if (Toggle != 0) {
1690     SetTDTokenDataToggle1 (TdStruct);
1691   } else {
1692     SetTDTokenDataToggle0 (TdStruct);
1693   }
1694 
1695   SetTDTokenEndPoint (TdStruct, Endpoint);
1696 
1697   SetTDTokenDeviceAddress (TdStruct, DevAddr);
1698 
1699   SetTDTokenPacketID (TdStruct, PktID);
1700 
1701   TdStruct->PtrTDBuffer      = (UINT8 *) PtrData;
1702   TdStruct->TDBufferLength = Len;
1703   SetTDDataBuffer (TdStruct);
1704 
1705   *PtrTD = TdStruct;
1706 
1707   return EFI_SUCCESS;
1708 }
1709 
1710 /**
1711   Generate Status Stage TD.
1712 
1713   @param  UhcDev       The UHCI device.
1714   @param  DevAddr      Device address.
1715   @param  Endpoint     Endpoint number.
1716   @param  PktID        PacketID.
1717   @param  DeviceSpeed  Device Speed.
1718   @param  PtrTD        TD_STRUCT generated.
1719 
1720   @return EFI_SUCCESS            Generate status stage TD successfully.
1721   @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resource.
1722 
1723 **/
1724 EFI_STATUS
CreateStatusTD(IN USB_UHC_DEV * UhcDev,IN UINT8 DevAddr,IN UINT8 Endpoint,IN UINT8 PktID,IN UINT8 DeviceSpeed,OUT TD_STRUCT ** PtrTD)1725 CreateStatusTD (
1726   IN  USB_UHC_DEV     *UhcDev,
1727   IN  UINT8           DevAddr,
1728   IN  UINT8           Endpoint,
1729   IN  UINT8           PktID,
1730   IN  UINT8           DeviceSpeed,
1731   OUT TD_STRUCT       **PtrTD
1732   )
1733 {
1734   TD_STRUCT   *PtrTDStruct;
1735   EFI_STATUS  Status;
1736 
1737   Status = CreateTD (UhcDev, &PtrTDStruct);
1738   if (EFI_ERROR (Status)) {
1739     return Status;
1740   }
1741 
1742   SetTDLinkPtr (PtrTDStruct, NULL);
1743 
1744   //
1745   // Depth first fashion
1746   //
1747   SetTDLinkPtrDepthorBreadth (PtrTDStruct, TRUE);
1748 
1749   //
1750   // initialize as the last TD in the QH context,
1751   // this field will be updated in the TD linkage process.
1752   //
1753   SetTDLinkPtrValidorInvalid (PtrTDStruct, FALSE);
1754 
1755   //
1756   // Disable short packet detect
1757   //
1758   EnableorDisableTDShortPacket (PtrTDStruct, FALSE);
1759 
1760   //
1761   // Max error counter is 3
1762   //
1763   SetTDControlErrorCounter (PtrTDStruct, 3);
1764 
1765   //
1766   // set device speed attribute
1767   // (TRUE - Slow Device; FALSE - Full Speed Device)
1768   //
1769   switch (DeviceSpeed) {
1770   case USB_SLOW_SPEED_DEVICE:
1771     SetTDLoworFullSpeedDevice (PtrTDStruct, TRUE);
1772     break;
1773 
1774   case USB_FULL_SPEED_DEVICE:
1775     SetTDLoworFullSpeedDevice (PtrTDStruct, FALSE);
1776     break;
1777   }
1778   //
1779   // Non isochronous transfer TD
1780   //
1781   SetTDControlIsochronousorNot (PtrTDStruct, FALSE);
1782 
1783   //
1784   // Disable Interrupt On Complete
1785   // Disable IOC interrupt.
1786   //
1787   SetorClearTDControlIOC (PtrTDStruct, FALSE);
1788 
1789   //
1790   // Set TD Active bit
1791   //
1792   SetTDStatusActiveorInactive (PtrTDStruct, TRUE);
1793 
1794   SetTDTokenMaxLength (PtrTDStruct, 0);
1795 
1796   SetTDTokenDataToggle1 (PtrTDStruct);
1797 
1798   SetTDTokenEndPoint (PtrTDStruct, Endpoint);
1799 
1800   SetTDTokenDeviceAddress (PtrTDStruct, DevAddr);
1801 
1802   SetTDTokenPacketID (PtrTDStruct, PktID);
1803 
1804   PtrTDStruct->PtrTDBuffer      = NULL;
1805   PtrTDStruct->TDBufferLength = 0;
1806   SetTDDataBuffer (PtrTDStruct);
1807 
1808   *PtrTD = PtrTDStruct;
1809 
1810   return EFI_SUCCESS;
1811 }
1812 
1813 /**
1814   Set the link pointer validor bit in TD.
1815 
1816   @param  PtrTDStruct  Place to store TD_STRUCT pointer.
1817   @param  IsValid      Specify the linker pointer is valid or not.
1818 
1819 **/
1820 VOID
SetTDLinkPtrValidorInvalid(IN TD_STRUCT * PtrTDStruct,IN BOOLEAN IsValid)1821 SetTDLinkPtrValidorInvalid (
1822   IN  TD_STRUCT *PtrTDStruct,
1823   IN  BOOLEAN   IsValid
1824   )
1825 {
1826   //
1827   // Valid means the link pointer is valid,
1828   // else, it's invalid.
1829   //
1830   PtrTDStruct->TDData.TDLinkPtrTerminate = (IsValid ? 0 : 1);
1831 }
1832 
1833 /**
1834   Set the Link Pointer pointing to a QH or TD.
1835 
1836   @param  PtrTDStruct   Place to store TD_STRUCT pointer.
1837   @param  IsQH          Specify QH or TD is connected.
1838 
1839 **/
1840 VOID
SetTDLinkPtrQHorTDSelect(IN TD_STRUCT * PtrTDStruct,IN BOOLEAN IsQH)1841 SetTDLinkPtrQHorTDSelect (
1842   IN  TD_STRUCT *PtrTDStruct,
1843   IN  BOOLEAN   IsQH
1844   )
1845 {
1846   //
1847   // Indicate whether the Link Pointer pointing to a QH or TD
1848   //
1849   PtrTDStruct->TDData.TDLinkPtrQSelect = (IsQH ? 1 : 0);
1850 }
1851 
1852 /**
1853   Set the traverse is depth-first or breadth-first.
1854 
1855   @param  PtrTDStruct   Place to store TD_STRUCT pointer.
1856   @param  IsDepth       Specify the traverse is depth-first or breadth-first.
1857 
1858 **/
1859 VOID
SetTDLinkPtrDepthorBreadth(IN TD_STRUCT * PtrTDStruct,IN BOOLEAN IsDepth)1860 SetTDLinkPtrDepthorBreadth (
1861   IN  TD_STRUCT *PtrTDStruct,
1862   IN  BOOLEAN   IsDepth
1863   )
1864 {
1865   //
1866   // If TRUE, indicating the host controller should process in depth first fashion,
1867   // else, the host controller should process in breadth first fashion
1868   //
1869   PtrTDStruct->TDData.TDLinkPtrDepthSelect = (IsDepth ? 1 : 0);
1870 }
1871 
1872 /**
1873   Set TD Link Pointer in TD.
1874 
1875   @param  PtrTDStruct  Place to store TD_STRUCT pointer.
1876   @param  PtrNext      Place to the next TD_STRUCT.
1877 
1878 **/
1879 VOID
SetTDLinkPtr(IN TD_STRUCT * PtrTDStruct,IN VOID * PtrNext)1880 SetTDLinkPtr (
1881   IN  TD_STRUCT *PtrTDStruct,
1882   IN  VOID      *PtrNext
1883   )
1884 {
1885   //
1886   // Set TD Link Pointer. Since QH,TD align on 16-byte boundaries,
1887   // only the highest 28 bits are valid. (if take 32bit address as an example)
1888   //
1889   PtrTDStruct->TDData.TDLinkPtr = (UINT32) (UINTN) PtrNext >> 4;
1890 }
1891 
1892 /**
1893   Get TD Link Pointer.
1894 
1895   @param  PtrTDStruct     Place to store TD_STRUCT pointer.
1896 
1897   @retval Get TD Link Pointer in TD.
1898 
1899 **/
1900 VOID *
GetTDLinkPtr(IN TD_STRUCT * PtrTDStruct)1901 GetTDLinkPtr (
1902   IN  TD_STRUCT *PtrTDStruct
1903   )
1904 {
1905   //
1906   // Get TD Link Pointer. Restore it back to 32bit
1907   // (if take 32bit address as an example)
1908   //
1909   return (VOID *) (UINTN) ((PtrTDStruct->TDData.TDLinkPtr) << 4);
1910 }
1911 
1912 /**
1913   Get the information about whether the Link Pointer field pointing to
1914   a QH or a TD.
1915 
1916   @param  PtrTDStruct     Place to store TD_STRUCT pointer.
1917 
1918   @retval whether the Link Pointer field pointing to a QH or a TD.
1919 
1920 **/
1921 BOOLEAN
IsTDLinkPtrQHOrTD(IN TD_STRUCT * PtrTDStruct)1922 IsTDLinkPtrQHOrTD (
1923   IN  TD_STRUCT *PtrTDStruct
1924   )
1925 {
1926   //
1927   // Get the information about whether the Link Pointer field pointing to
1928   // a QH or a TD.
1929   //
1930   return (BOOLEAN) (PtrTDStruct->TDData.TDLinkPtrQSelect);
1931 }
1932 
1933 /**
1934   Enable/Disable short packet detection mechanism.
1935 
1936   @param  PtrTDStruct  Place to store TD_STRUCT pointer.
1937   @param  IsEnable     Enable or disable short packet detection mechanism.
1938 
1939 **/
1940 VOID
EnableorDisableTDShortPacket(IN TD_STRUCT * PtrTDStruct,IN BOOLEAN IsEnable)1941 EnableorDisableTDShortPacket (
1942   IN  TD_STRUCT *PtrTDStruct,
1943   IN  BOOLEAN   IsEnable
1944   )
1945 {
1946   //
1947   // TRUE means enable short packet detection mechanism.
1948   //
1949   PtrTDStruct->TDData.TDStatusSPD = (IsEnable ? 1 : 0);
1950 }
1951 
1952 /**
1953   Set the max error counter in TD.
1954 
1955   @param  PtrTDStruct  Place to store TD_STRUCT pointer.
1956   @param  MaxErrors    The number of allowable error.
1957 
1958 **/
1959 VOID
SetTDControlErrorCounter(IN TD_STRUCT * PtrTDStruct,IN UINT8 MaxErrors)1960 SetTDControlErrorCounter (
1961   IN  TD_STRUCT *PtrTDStruct,
1962   IN  UINT8     MaxErrors
1963   )
1964 {
1965   //
1966   // valid value of MaxErrors is 0,1,2,3
1967   //
1968   if (MaxErrors > 3) {
1969     MaxErrors = 3;
1970   }
1971 
1972   PtrTDStruct->TDData.TDStatusErr = MaxErrors;
1973 }
1974 
1975 /**
1976   Set the TD is targeting a low-speed device or not.
1977 
1978   @param  PtrTDStruct       Place to store TD_STRUCT pointer.
1979   @param  IsLowSpeedDevice  Whether The device is low-speed.
1980 
1981 **/
1982 VOID
SetTDLoworFullSpeedDevice(IN TD_STRUCT * PtrTDStruct,IN BOOLEAN IsLowSpeedDevice)1983 SetTDLoworFullSpeedDevice (
1984   IN  TD_STRUCT *PtrTDStruct,
1985   IN  BOOLEAN   IsLowSpeedDevice
1986   )
1987 {
1988   //
1989   // TRUE means the TD is targeting at a Low-speed device
1990   //
1991   PtrTDStruct->TDData.TDStatusLS = (IsLowSpeedDevice ? 1 : 0);
1992 }
1993 
1994 /**
1995   Set the TD is isochronous transfer type or not.
1996 
1997   @param  PtrTDStruct       Place to store TD_STRUCT pointer.
1998   @param  IsIsochronous     Whether the transaction isochronous transfer type.
1999 
2000 **/
2001 VOID
SetTDControlIsochronousorNot(IN TD_STRUCT * PtrTDStruct,IN BOOLEAN IsIsochronous)2002 SetTDControlIsochronousorNot (
2003   IN  TD_STRUCT   *PtrTDStruct,
2004   IN  BOOLEAN     IsIsochronous
2005   )
2006 {
2007   //
2008   // TRUE means the TD belongs to Isochronous transfer type.
2009   //
2010   PtrTDStruct->TDData.TDStatusIOS = (IsIsochronous ? 1 : 0);
2011 }
2012 
2013 /**
2014   Set if UCHI should issue an interrupt on completion of the frame
2015   in which this TD is executed
2016 
2017   @param  PtrTDStruct       Place to store TD_STRUCT pointer.
2018   @param  IsSet             Whether HC should issue an interrupt on completion.
2019 
2020 **/
2021 VOID
SetorClearTDControlIOC(IN TD_STRUCT * PtrTDStruct,IN BOOLEAN IsSet)2022 SetorClearTDControlIOC (
2023   IN  TD_STRUCT *PtrTDStruct,
2024   IN  BOOLEAN   IsSet
2025   )
2026 {
2027   //
2028   // If this bit is set, it indicates that the host controller should issue
2029   // an interrupt on completion of the frame in which this TD is executed.
2030   //
2031   PtrTDStruct->TDData.TDStatusIOC = IsSet ? 1 : 0;
2032 }
2033 
2034 /**
2035   Set if the TD is active and can be executed.
2036 
2037   @param  PtrTDStruct       Place to store TD_STRUCT pointer.
2038   @param  IsActive          Whether the TD is active and can be executed.
2039 
2040 **/
2041 VOID
SetTDStatusActiveorInactive(IN TD_STRUCT * PtrTDStruct,IN BOOLEAN IsActive)2042 SetTDStatusActiveorInactive (
2043   IN  TD_STRUCT *PtrTDStruct,
2044   IN  BOOLEAN   IsActive
2045   )
2046 {
2047   //
2048   // If this bit is set, it indicates that the TD is active and can be
2049   // executed.
2050   //
2051   if (IsActive) {
2052     PtrTDStruct->TDData.TDStatus |= 0x80;
2053   } else {
2054     PtrTDStruct->TDData.TDStatus &= 0x7F;
2055   }
2056 }
2057 
2058 /**
2059   Specifies the maximum number of data bytes allowed for the transfer.
2060 
2061   @param  PtrTDStruct   Place to store TD_STRUCT pointer.
2062   @param  MaxLen        The maximum number of data bytes allowed.
2063 
2064   @retval The allowed maximum number of data.
2065 **/
2066 UINT16
SetTDTokenMaxLength(IN TD_STRUCT * PtrTDStruct,IN UINT16 MaxLen)2067 SetTDTokenMaxLength (
2068   IN  TD_STRUCT *PtrTDStruct,
2069   IN  UINT16    MaxLen
2070   )
2071 {
2072   //
2073   // Specifies the maximum number of data bytes allowed for the transfer.
2074   // the legal value extent is 0 ~ 0x500.
2075   //
2076   if (MaxLen > 0x500) {
2077     MaxLen = 0x500;
2078   }
2079 
2080   PtrTDStruct->TDData.TDTokenMaxLen = MaxLen - 1;
2081 
2082   return MaxLen;
2083 }
2084 
2085 /**
2086   Set the data toggle bit to DATA1.
2087 
2088   @param  PtrTDStruct   Place to store TD_STRUCT pointer.
2089 
2090 **/
2091 VOID
SetTDTokenDataToggle1(IN TD_STRUCT * PtrTDStruct)2092 SetTDTokenDataToggle1 (
2093   IN  TD_STRUCT *PtrTDStruct
2094   )
2095 {
2096   //
2097   // Set the data toggle bit to DATA1
2098   //
2099   PtrTDStruct->TDData.TDTokenDataToggle = 1;
2100 }
2101 
2102 /**
2103   Set the data toggle bit to DATA0.
2104 
2105   @param  PtrTDStruct   Place to store TD_STRUCT pointer.
2106 
2107 **/
2108 VOID
SetTDTokenDataToggle0(IN TD_STRUCT * PtrTDStruct)2109 SetTDTokenDataToggle0 (
2110   IN  TD_STRUCT *PtrTDStruct
2111   )
2112 {
2113   //
2114   // Set the data toggle bit to DATA0
2115   //
2116   PtrTDStruct->TDData.TDTokenDataToggle = 0;
2117 }
2118 
2119 /**
2120   Set EndPoint Number the TD is targeting at.
2121 
2122   @param  PtrTDStruct   Place to store TD_STRUCT pointer.
2123   @param  EndPoint      The Endport number of the target.
2124 
2125 **/
2126 VOID
SetTDTokenEndPoint(IN TD_STRUCT * PtrTDStruct,IN UINTN EndPoint)2127 SetTDTokenEndPoint (
2128   IN  TD_STRUCT *PtrTDStruct,
2129   IN  UINTN     EndPoint
2130   )
2131 {
2132   //
2133   // Set EndPoint Number the TD is targeting at.
2134   //
2135   PtrTDStruct->TDData.TDTokenEndPt = (UINT8) EndPoint;
2136 }
2137 
2138 /**
2139   Set Device Address the TD is targeting at.
2140 
2141   @param  PtrTDStruct   Place to store TD_STRUCT pointer.
2142   @param  DevAddr       The Device Address of the target.
2143 
2144 **/
2145 VOID
SetTDTokenDeviceAddress(IN TD_STRUCT * PtrTDStruct,IN UINTN DevAddr)2146 SetTDTokenDeviceAddress (
2147   IN  TD_STRUCT *PtrTDStruct,
2148   IN  UINTN     DevAddr
2149   )
2150 {
2151   //
2152   // Set Device Address the TD is targeting at.
2153   //
2154   PtrTDStruct->TDData.TDTokenDevAddr = (UINT8) DevAddr;
2155 }
2156 
2157 /**
2158   Set Packet Identification the TD is targeting at.
2159 
2160   @param  PtrTDStruct   Place to store TD_STRUCT pointer.
2161   @param  PacketID      The Packet Identification of the target.
2162 
2163 **/
2164 VOID
SetTDTokenPacketID(IN TD_STRUCT * PtrTDStruct,IN UINT8 PacketID)2165 SetTDTokenPacketID (
2166   IN  TD_STRUCT *PtrTDStruct,
2167   IN  UINT8     PacketID
2168   )
2169 {
2170   //
2171   // Set the Packet Identification to be used for this transaction.
2172   //
2173   PtrTDStruct->TDData.TDTokenPID = PacketID;
2174 }
2175 
2176 /**
2177   Set the beginning address of the data buffer that will be used
2178   during the transaction.
2179 
2180   @param  PtrTDStruct   Place to store TD_STRUCT pointer.
2181 
2182 **/
2183 VOID
SetTDDataBuffer(IN TD_STRUCT * PtrTDStruct)2184 SetTDDataBuffer (
2185   IN  TD_STRUCT *PtrTDStruct
2186   )
2187 {
2188   //
2189   // Set the beginning address of the data buffer that will be used
2190   // during the transaction.
2191   //
2192   PtrTDStruct->TDData.TDBufferPtr = (UINT32) (UINTN) (PtrTDStruct->PtrTDBuffer);
2193 }
2194 
2195 /**
2196   Detect whether the TD is active.
2197 
2198   @param  PtrTDStruct   Place to store TD_STRUCT pointer.
2199 
2200   @retval The TD is active or not.
2201 
2202 **/
2203 BOOLEAN
IsTDStatusActive(IN TD_STRUCT * PtrTDStruct)2204 IsTDStatusActive (
2205   IN  TD_STRUCT *PtrTDStruct
2206   )
2207 {
2208   UINT8 TDStatus;
2209 
2210   //
2211   // Detect whether the TD is active.
2212   //
2213   TDStatus = (UINT8) (PtrTDStruct->TDData.TDStatus);
2214   return (BOOLEAN) (TDStatus & 0x80);
2215 }
2216 
2217 /**
2218   Detect whether the TD is stalled.
2219 
2220   @param  PtrTDStruct   Place to store TD_STRUCT pointer.
2221 
2222   @retval The TD is stalled or not.
2223 
2224 **/
2225 BOOLEAN
IsTDStatusStalled(IN TD_STRUCT * PtrTDStruct)2226 IsTDStatusStalled (
2227   IN  TD_STRUCT *PtrTDStruct
2228   )
2229 {
2230   UINT8 TDStatus;
2231 
2232   //
2233   // Detect whether the device/endpoint addressed by this TD is stalled.
2234   //
2235   TDStatus = (UINT8) (PtrTDStruct->TDData.TDStatus);
2236   return (BOOLEAN) (TDStatus & 0x40);
2237 }
2238 
2239 /**
2240   Detect whether Data Buffer Error is happened.
2241 
2242   @param  PtrTDStruct   Place to store TD_STRUCT pointer.
2243 
2244   @retval The Data Buffer Error is happened or not.
2245 
2246 **/
2247 BOOLEAN
IsTDStatusBufferError(IN TD_STRUCT * PtrTDStruct)2248 IsTDStatusBufferError (
2249   IN  TD_STRUCT *PtrTDStruct
2250   )
2251 {
2252   UINT8 TDStatus;
2253 
2254   //
2255   // Detect whether Data Buffer Error is happened.
2256   //
2257   TDStatus = (UINT8) (PtrTDStruct->TDData.TDStatus);
2258   return (BOOLEAN) (TDStatus & 0x20);
2259 }
2260 
2261 /**
2262   Detect whether Babble Error is happened.
2263 
2264   @param  PtrTDStruct   Place to store TD_STRUCT pointer.
2265 
2266   @retval The Babble Error is happened or not.
2267 
2268 **/
2269 BOOLEAN
IsTDStatusBabbleError(IN TD_STRUCT * PtrTDStruct)2270 IsTDStatusBabbleError (
2271   IN  TD_STRUCT *PtrTDStruct
2272   )
2273 {
2274   UINT8 TDStatus;
2275 
2276   //
2277   // Detect whether Babble Error is happened.
2278   //
2279   TDStatus = (UINT8) (PtrTDStruct->TDData.TDStatus);
2280   return (BOOLEAN) (TDStatus & 0x10);
2281 }
2282 
2283 /**
2284   Detect whether NAK is received.
2285 
2286   @param  PtrTDStruct   Place to store TD_STRUCT pointer.
2287 
2288   @retval The NAK is received or not.
2289 
2290 **/
2291 BOOLEAN
IsTDStatusNAKReceived(IN TD_STRUCT * PtrTDStruct)2292 IsTDStatusNAKReceived (
2293   IN  TD_STRUCT *PtrTDStruct
2294   )
2295 {
2296   UINT8 TDStatus;
2297 
2298   //
2299   // Detect whether NAK is received.
2300   //
2301   TDStatus = (UINT8) (PtrTDStruct->TDData.TDStatus);
2302   return (BOOLEAN) (TDStatus & 0x08);
2303 }
2304 
2305 /**
2306   Detect whether CRC/Time Out Error is encountered.
2307 
2308   @param  PtrTDStruct   Place to store TD_STRUCT pointer.
2309 
2310   @retval The CRC/Time Out Error is encountered or not.
2311 
2312 **/
2313 BOOLEAN
IsTDStatusCRCTimeOutError(IN TD_STRUCT * PtrTDStruct)2314 IsTDStatusCRCTimeOutError (
2315   IN  TD_STRUCT *PtrTDStruct
2316   )
2317 {
2318   UINT8 TDStatus;
2319 
2320   //
2321   // Detect whether CRC/Time Out Error is encountered.
2322   //
2323   TDStatus = (UINT8) (PtrTDStruct->TDData.TDStatus);
2324   return (BOOLEAN) (TDStatus & 0x04);
2325 }
2326 
2327 /**
2328   Detect whether Bitstuff Error is received.
2329 
2330   @param  PtrTDStruct   Place to store TD_STRUCT pointer.
2331 
2332   @retval The Bitstuff Error is received or not.
2333 
2334 **/
2335 BOOLEAN
IsTDStatusBitStuffError(IN TD_STRUCT * PtrTDStruct)2336 IsTDStatusBitStuffError (
2337   IN  TD_STRUCT *PtrTDStruct
2338   )
2339 {
2340   UINT8 TDStatus;
2341 
2342   //
2343   // Detect whether Bitstuff Error is received.
2344   //
2345   TDStatus = (UINT8) (PtrTDStruct->TDData.TDStatus);
2346   return (BOOLEAN) (TDStatus & 0x02);
2347 }
2348 
2349 /**
2350   Retrieve the actual number of bytes that were tansferred.
2351 
2352   @param  PtrTDStruct   Place to store TD_STRUCT pointer.
2353 
2354   @retval The actual number of bytes that were tansferred.
2355 
2356 **/
2357 UINT16
GetTDStatusActualLength(IN TD_STRUCT * PtrTDStruct)2358 GetTDStatusActualLength (
2359   IN  TD_STRUCT *PtrTDStruct
2360   )
2361 {
2362   //
2363   // Retrieve the actual number of bytes that were tansferred.
2364   // the value is encoded as n-1. so return the decoded value.
2365   //
2366   return (UINT16) ((PtrTDStruct->TDData.TDStatusActualLength) + 1);
2367 }
2368 
2369 /**
2370   Retrieve the information of whether the Link Pointer field is valid or not.
2371 
2372   @param  PtrTDStruct   Place to store TD_STRUCT pointer.
2373 
2374   @retval The linker pointer field is valid or not.
2375 
2376 **/
2377 BOOLEAN
GetTDLinkPtrValidorInvalid(IN TD_STRUCT * PtrTDStruct)2378 GetTDLinkPtrValidorInvalid (
2379   IN  TD_STRUCT *PtrTDStruct
2380   )
2381 {
2382   //
2383   // Retrieve the information of whether the Link Pointer field
2384   // is valid or not.
2385   //
2386   if ((PtrTDStruct->TDData.TDLinkPtrTerminate & BIT0) != 0) {
2387     return FALSE;
2388   } else {
2389     return TRUE;
2390   }
2391 
2392 }
2393 
2394 /**
2395   Count TD Number from PtrFirstTD.
2396 
2397   @param  PtrFirstTD   Place to store TD_STRUCT pointer.
2398 
2399   @retval The queued TDs number.
2400 
2401 **/
2402 UINTN
CountTDsNumber(IN TD_STRUCT * PtrFirstTD)2403 CountTDsNumber (
2404   IN  TD_STRUCT *PtrFirstTD
2405   )
2406 {
2407   UINTN     Number;
2408   TD_STRUCT *Ptr;
2409 
2410   //
2411   // Count the queued TDs number.
2412   //
2413   Number  = 0;
2414   Ptr     = PtrFirstTD;
2415   while (Ptr != 0) {
2416     Ptr = (TD_STRUCT *) Ptr->PtrNextTD;
2417     Number++;
2418   }
2419 
2420   return Number;
2421 }
2422 
2423 /**
2424   Link TD To QH.
2425 
2426   @param  PtrQH   Place to store QH_STRUCT pointer.
2427   @param  PtrTD   Place to store TD_STRUCT pointer.
2428 
2429 **/
2430 VOID
LinkTDToQH(IN QH_STRUCT * PtrQH,IN TD_STRUCT * PtrTD)2431 LinkTDToQH (
2432   IN  QH_STRUCT *PtrQH,
2433   IN  TD_STRUCT *PtrTD
2434   )
2435 {
2436   if (PtrQH == NULL || PtrTD == NULL) {
2437     return ;
2438   }
2439   //
2440   //  Validate QH Vertical Ptr field
2441   //
2442   SetQHVerticalValidorInvalid (PtrQH, TRUE);
2443 
2444   //
2445   //  Vertical Ptr pointing to TD structure
2446   //
2447   SetQHVerticalQHorTDSelect (PtrQH, FALSE);
2448 
2449   SetQHVerticalLinkPtr (PtrQH, (VOID *) PtrTD);
2450 
2451   PtrQH->PtrDown = (VOID *) PtrTD;
2452 }
2453 
2454 /**
2455   Link TD To TD.
2456 
2457   @param  PtrPreTD  Place to store TD_STRUCT pointer.
2458   @param  PtrTD     Place to store TD_STRUCT pointer.
2459 
2460 **/
2461 VOID
LinkTDToTD(IN TD_STRUCT * PtrPreTD,IN TD_STRUCT * PtrTD)2462 LinkTDToTD (
2463   IN  TD_STRUCT *PtrPreTD,
2464   IN  TD_STRUCT *PtrTD
2465   )
2466 {
2467   if (PtrPreTD == NULL || PtrTD == NULL) {
2468     return ;
2469   }
2470   //
2471   // Depth first fashion
2472   //
2473   SetTDLinkPtrDepthorBreadth (PtrPreTD, TRUE);
2474 
2475   //
2476   // Link pointer pointing to TD struct
2477   //
2478   SetTDLinkPtrQHorTDSelect (PtrPreTD, FALSE);
2479 
2480   //
2481   // Validate the link pointer valid bit
2482   //
2483   SetTDLinkPtrValidorInvalid (PtrPreTD, TRUE);
2484 
2485   SetTDLinkPtr (PtrPreTD, PtrTD);
2486 
2487   PtrPreTD->PtrNextTD = (VOID *) PtrTD;
2488 
2489   PtrTD->PtrNextTD    = NULL;
2490 }
2491 
2492 /**
2493   Execute Control Transfer.
2494 
2495   @param  UhcDev            The UCHI device.
2496   @param  PtrTD             A pointer to TD_STRUCT data.
2497   @param  ActualLen         Actual transfer Length.
2498   @param  TimeOut           TimeOut value.
2499   @param  TransferResult    Transfer Result.
2500 
2501   @return EFI_DEVICE_ERROR  The transfer failed due to transfer error.
2502   @return EFI_TIMEOUT       The transfer failed due to time out.
2503   @return EFI_SUCCESS       The transfer finished OK.
2504 
2505 **/
2506 EFI_STATUS
ExecuteControlTransfer(IN USB_UHC_DEV * UhcDev,IN TD_STRUCT * PtrTD,OUT UINTN * ActualLen,IN UINTN TimeOut,OUT UINT32 * TransferResult)2507 ExecuteControlTransfer (
2508   IN  USB_UHC_DEV *UhcDev,
2509   IN  TD_STRUCT   *PtrTD,
2510   OUT UINTN       *ActualLen,
2511   IN  UINTN       TimeOut,
2512   OUT UINT32      *TransferResult
2513   )
2514 {
2515   UINTN   ErrTDPos;
2516   UINTN   Delay;
2517   BOOLEAN InfiniteLoop;
2518 
2519   ErrTDPos          = 0;
2520   *TransferResult   = EFI_USB_NOERROR;
2521   *ActualLen        = 0;
2522   InfiniteLoop      = FALSE;
2523 
2524   Delay = TimeOut * STALL_1_MILLI_SECOND;
2525   //
2526   // If Timeout is 0, then the caller must wait for the function to be completed
2527   // until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
2528   //
2529   if (TimeOut == 0) {
2530     InfiniteLoop = TRUE;
2531   }
2532 
2533   do {
2534 
2535     CheckTDsResults (PtrTD, TransferResult, &ErrTDPos, ActualLen);
2536 
2537     //
2538     // TD is inactive, means the control transfer is end.
2539     //
2540     if ((*TransferResult & EFI_USB_ERR_NOTEXECUTE) != EFI_USB_ERR_NOTEXECUTE) {
2541       break;
2542     }
2543     MicroSecondDelay (STALL_1_MICRO_SECOND);
2544     Delay--;
2545 
2546   } while (InfiniteLoop || (Delay != 0));
2547 
2548   if (*TransferResult != EFI_USB_NOERROR) {
2549     return EFI_DEVICE_ERROR;
2550   }
2551 
2552   return EFI_SUCCESS;
2553 }
2554 
2555 /**
2556   Execute Bulk Transfer.
2557 
2558   @param  UhcDev            The UCHI device.
2559   @param  PtrTD             A pointer to TD_STRUCT data.
2560   @param  ActualLen         Actual transfer Length.
2561   @param  DataToggle        DataToggle value.
2562   @param  TimeOut           TimeOut value.
2563   @param  TransferResult    Transfer Result.
2564 
2565   @return EFI_DEVICE_ERROR  The transfer failed due to transfer error.
2566   @return EFI_TIMEOUT       The transfer failed due to time out.
2567   @return EFI_SUCCESS       The transfer finished OK.
2568 
2569 **/
2570 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)2571 ExecBulkTransfer (
2572   IN     USB_UHC_DEV *UhcDev,
2573   IN     TD_STRUCT   *PtrTD,
2574   IN OUT UINTN       *ActualLen,
2575   IN     UINT8       *DataToggle,
2576   IN     UINTN       TimeOut,
2577   OUT    UINT32      *TransferResult
2578   )
2579 {
2580   UINTN   ErrTDPos;
2581   UINTN   ScrollNum;
2582   UINTN   Delay;
2583   BOOLEAN InfiniteLoop;
2584 
2585   ErrTDPos          = 0;
2586   *TransferResult   = EFI_USB_NOERROR;
2587   *ActualLen        = 0;
2588   InfiniteLoop      = FALSE;
2589 
2590   Delay = TimeOut * STALL_1_MILLI_SECOND;
2591   //
2592   // If Timeout is 0, then the caller must wait for the function to be completed
2593   // until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
2594   //
2595   if (TimeOut == 0) {
2596     InfiniteLoop = TRUE;
2597   }
2598 
2599   do {
2600 
2601     CheckTDsResults (PtrTD, TransferResult, &ErrTDPos, ActualLen);
2602     //
2603     // TD is inactive, thus meaning bulk transfer's end.
2604     //
2605     if ((*TransferResult & EFI_USB_ERR_NOTEXECUTE) != EFI_USB_ERR_NOTEXECUTE) {
2606       break;
2607     }
2608     MicroSecondDelay (STALL_1_MICRO_SECOND);
2609     Delay--;
2610 
2611   } while (InfiniteLoop || (Delay != 0));
2612 
2613   //
2614   // has error
2615   //
2616   if (*TransferResult != EFI_USB_NOERROR) {
2617     //
2618     // scroll the Data Toggle back to the last success TD
2619     //
2620     ScrollNum = CountTDsNumber (PtrTD) - ErrTDPos;
2621     if ((ScrollNum % 2) != 0) {
2622       *DataToggle ^= 1;
2623     }
2624 
2625   //
2626   // If error, wait 100ms to retry by upper layer
2627   //
2628     MicroSecondDelay (100 * 1000);
2629     return EFI_DEVICE_ERROR;
2630   }
2631 
2632   return EFI_SUCCESS;
2633 }
2634 
2635 /**
2636   Delete Queued TDs.
2637 
2638   @param  UhcDev       The UCHI device.
2639   @param  PtrFirstTD   Place to store TD_STRUCT pointer.
2640 
2641 **/
2642 VOID
DeleteQueuedTDs(IN USB_UHC_DEV * UhcDev,IN TD_STRUCT * PtrFirstTD)2643 DeleteQueuedTDs (
2644   IN USB_UHC_DEV     *UhcDev,
2645   IN TD_STRUCT       *PtrFirstTD
2646   )
2647 {
2648   TD_STRUCT *Tptr1;
2649 
2650   TD_STRUCT *Tptr2;
2651 
2652   Tptr1 = PtrFirstTD;
2653   //
2654   // Delete all the TDs in a queue.
2655   //
2656   while (Tptr1 != NULL) {
2657 
2658     Tptr2 = Tptr1;
2659 
2660     if (!GetTDLinkPtrValidorInvalid (Tptr2)) {
2661       Tptr1 = NULL;
2662     } else {
2663       //
2664       // has more than one TD in the queue.
2665       //
2666       Tptr1 = GetTDLinkPtr (Tptr2);
2667     }
2668 
2669     UhcFreePool (UhcDev, (UINT8 *) Tptr2, sizeof (TD_STRUCT));
2670   }
2671 
2672   return ;
2673 }
2674 
2675 /**
2676   Check TDs Results.
2677 
2678   @param  PtrTD               A pointer to TD_STRUCT data.
2679   @param  Result              The result to return.
2680   @param  ErrTDPos            The Error TD position.
2681   @param  ActualTransferSize  Actual transfer size.
2682 
2683   @retval The TD is executed successfully or not.
2684 
2685 **/
2686 BOOLEAN
CheckTDsResults(IN TD_STRUCT * PtrTD,OUT UINT32 * Result,OUT UINTN * ErrTDPos,OUT UINTN * ActualTransferSize)2687 CheckTDsResults (
2688   IN  TD_STRUCT               *PtrTD,
2689   OUT UINT32                  *Result,
2690   OUT UINTN                   *ErrTDPos,
2691   OUT UINTN                   *ActualTransferSize
2692   )
2693 {
2694   UINTN Len;
2695 
2696   *Result   = EFI_USB_NOERROR;
2697   *ErrTDPos = 0;
2698 
2699   //
2700   // Init to zero.
2701   //
2702   *ActualTransferSize = 0;
2703 
2704   while (PtrTD != NULL) {
2705 
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     // Accumulate actual transferred data length in each TD.
2735     //
2736     Len = GetTDStatusActualLength (PtrTD) & 0x7FF;
2737     *ActualTransferSize += Len;
2738 
2739     //
2740     // if any error encountered, stop processing the left TDs.
2741     //
2742     if ((*Result) != 0) {
2743       return FALSE;
2744     }
2745 
2746     PtrTD = (TD_STRUCT *) (PtrTD->PtrNextTD);
2747     //
2748     // Record the first Error TD's position in the queue,
2749     // this value is zero-based.
2750     //
2751     (*ErrTDPos)++;
2752   }
2753 
2754   return TRUE;
2755 }
2756 
2757 /**
2758   Create Memory Block.
2759 
2760   @param  UhcDev                   The UCHI device.
2761   @param  MemoryHeader             The Pointer to allocated memory block.
2762   @param  MemoryBlockSizeInPages   The page size of memory block to be allocated.
2763 
2764   @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resources.
2765   @retval EFI_SUCCESS            Success.
2766 
2767 **/
2768 EFI_STATUS
CreateMemoryBlock(IN USB_UHC_DEV * UhcDev,OUT MEMORY_MANAGE_HEADER ** MemoryHeader,IN UINTN MemoryBlockSizeInPages)2769 CreateMemoryBlock (
2770   IN  USB_UHC_DEV           *UhcDev,
2771   OUT MEMORY_MANAGE_HEADER  **MemoryHeader,
2772   IN  UINTN                 MemoryBlockSizeInPages
2773   )
2774 {
2775   EFI_STATUS            Status;
2776   EFI_PHYSICAL_ADDRESS  TempPtr;
2777   UINTN                 MemPages;
2778   UINT8                 *Ptr;
2779 
2780   //
2781   // Memory Block uses MemoryBlockSizeInPages pages,
2782   // memory management header and bit array use 1 page
2783   //
2784   MemPages = MemoryBlockSizeInPages + 1;
2785   Status = PeiServicesAllocatePages (
2786              EfiBootServicesData,
2787              MemPages,
2788              &TempPtr
2789              );
2790   if (EFI_ERROR (Status)) {
2791     return Status;
2792   }
2793 
2794   Ptr = (UINT8 *) ((UINTN) TempPtr);
2795 
2796   ZeroMem (Ptr, MemPages * EFI_PAGE_SIZE);
2797 
2798   *MemoryHeader = (MEMORY_MANAGE_HEADER *) Ptr;
2799   //
2800   // adjust Ptr pointer to the next empty memory
2801   //
2802   Ptr += sizeof (MEMORY_MANAGE_HEADER);
2803   //
2804   // Set Bit Array initial address
2805   //
2806   (*MemoryHeader)->BitArrayPtr  = Ptr;
2807 
2808   (*MemoryHeader)->Next         = NULL;
2809 
2810   //
2811   // Memory block initial address
2812   //
2813   Ptr = (UINT8 *) ((UINTN) TempPtr);
2814   Ptr += EFI_PAGE_SIZE;
2815   (*MemoryHeader)->MemoryBlockPtr = Ptr;
2816   //
2817   // set Memory block size
2818   //
2819   (*MemoryHeader)->MemoryBlockSizeInBytes = MemoryBlockSizeInPages * EFI_PAGE_SIZE;
2820   //
2821   // each bit in Bit Array will manage 32byte memory in memory block
2822   //
2823   (*MemoryHeader)->BitArraySizeInBytes = ((*MemoryHeader)->MemoryBlockSizeInBytes / 32) / 8;
2824 
2825   return EFI_SUCCESS;
2826 }
2827 
2828 /**
2829   Initialize UHCI memory management.
2830 
2831   @param  UhcDev                 The UCHI device.
2832 
2833   @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resources.
2834   @retval EFI_SUCCESS            Success.
2835 
2836 **/
2837 EFI_STATUS
InitializeMemoryManagement(IN USB_UHC_DEV * UhcDev)2838 InitializeMemoryManagement (
2839   IN USB_UHC_DEV           *UhcDev
2840   )
2841 {
2842   MEMORY_MANAGE_HEADER  *MemoryHeader;
2843   EFI_STATUS            Status;
2844   UINTN                 MemPages;
2845 
2846   MemPages  = NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES;
2847   Status    = CreateMemoryBlock (UhcDev, &MemoryHeader, MemPages);
2848   if (EFI_ERROR (Status)) {
2849     return Status;
2850   }
2851 
2852   UhcDev->Header1 = MemoryHeader;
2853 
2854   return EFI_SUCCESS;
2855 }
2856 
2857 /**
2858   Initialize UHCI memory management.
2859 
2860   @param  UhcDev           The UCHI device.
2861   @param  Pool             Buffer pointer to store the buffer pointer.
2862   @param  AllocSize        The size of the pool to be allocated.
2863 
2864   @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resources.
2865   @retval EFI_SUCCESS            Success.
2866 
2867 **/
2868 EFI_STATUS
UhcAllocatePool(IN USB_UHC_DEV * UhcDev,OUT UINT8 ** Pool,IN UINTN AllocSize)2869 UhcAllocatePool (
2870   IN  USB_UHC_DEV     *UhcDev,
2871   OUT UINT8           **Pool,
2872   IN  UINTN           AllocSize
2873   )
2874 {
2875   MEMORY_MANAGE_HEADER  *MemoryHeader;
2876   MEMORY_MANAGE_HEADER  *TempHeaderPtr;
2877   MEMORY_MANAGE_HEADER  *NewMemoryHeader;
2878   UINTN                 RealAllocSize;
2879   UINTN                 MemoryBlockSizeInPages;
2880   EFI_STATUS            Status;
2881 
2882   *Pool = NULL;
2883 
2884   MemoryHeader = UhcDev->Header1;
2885 
2886   //
2887   // allocate unit is 32 byte (align on 32 byte)
2888   //
2889   if ((AllocSize & 0x1F) != 0) {
2890     RealAllocSize = (AllocSize / 32 + 1) * 32;
2891   } else {
2892     RealAllocSize = AllocSize;
2893   }
2894 
2895   Status = EFI_NOT_FOUND;
2896   for (TempHeaderPtr = MemoryHeader; TempHeaderPtr != NULL; TempHeaderPtr = TempHeaderPtr->Next) {
2897 
2898     Status = AllocMemInMemoryBlock (
2899               TempHeaderPtr,
2900               (VOID **) Pool,
2901               RealAllocSize / 32
2902               );
2903     if (!EFI_ERROR (Status)) {
2904       return EFI_SUCCESS;
2905     }
2906   }
2907   //
2908   // There is no enough memory,
2909   // Create a new Memory Block
2910   //
2911   //
2912   // if pool size is larger than NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES,
2913   // just allocate a large enough memory block.
2914   //
2915   if (RealAllocSize > (NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES * EFI_PAGE_SIZE)) {
2916     MemoryBlockSizeInPages = RealAllocSize / EFI_PAGE_SIZE + 1;
2917   } else {
2918     MemoryBlockSizeInPages = NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES;
2919   }
2920 
2921   Status = CreateMemoryBlock (UhcDev, &NewMemoryHeader, MemoryBlockSizeInPages);
2922   if (EFI_ERROR (Status)) {
2923     return Status;
2924   }
2925   //
2926   // Link the new Memory Block to the Memory Header list
2927   //
2928   InsertMemoryHeaderToList (MemoryHeader, NewMemoryHeader);
2929 
2930   Status = AllocMemInMemoryBlock (
2931             NewMemoryHeader,
2932             (VOID **) Pool,
2933             RealAllocSize / 32
2934             );
2935   return Status;
2936 }
2937 
2938 /**
2939   Alloc Memory In MemoryBlock.
2940 
2941   @param  MemoryHeader           The pointer to memory manage header.
2942   @param  Pool                   Buffer pointer to store the buffer pointer.
2943   @param  NumberOfMemoryUnit     The size of the pool to be allocated.
2944 
2945   @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resources.
2946   @retval EFI_SUCCESS            Success.
2947 
2948 **/
2949 EFI_STATUS
AllocMemInMemoryBlock(IN MEMORY_MANAGE_HEADER * MemoryHeader,OUT VOID ** Pool,IN UINTN NumberOfMemoryUnit)2950 AllocMemInMemoryBlock (
2951   IN  MEMORY_MANAGE_HEADER  *MemoryHeader,
2952   OUT VOID                  **Pool,
2953   IN  UINTN                 NumberOfMemoryUnit
2954   )
2955 {
2956   UINTN TempBytePos;
2957   UINTN FoundBytePos;
2958   UINT8 Index;
2959   UINT8 FoundBitPos;
2960   UINT8 ByteValue;
2961   UINT8 BitValue;
2962   UINTN NumberOfZeros;
2963   UINTN Count;
2964 
2965   FoundBytePos  = 0;
2966   FoundBitPos   = 0;
2967 
2968   ByteValue     = MemoryHeader->BitArrayPtr[0];
2969   NumberOfZeros = 0;
2970   Index             = 0;
2971   for (TempBytePos = 0; TempBytePos < MemoryHeader->BitArraySizeInBytes;) {
2972     //
2973     // Pop out BitValue from a byte in TempBytePos.
2974     //
2975     BitValue = (UINT8)(ByteValue & 0x1);
2976 
2977     if (BitValue == 0) {
2978       //
2979       // Found a free bit, the NumberOfZeros only record the number of those consecutive zeros
2980       //
2981       NumberOfZeros++;
2982       //
2983       // Found enough consecutive free space, break the loop
2984       //
2985       if (NumberOfZeros >= NumberOfMemoryUnit) {
2986         break;
2987       }
2988     } else {
2989       //
2990       // Encountering a '1', meant the bit is ocupied.
2991       //
2992       if (NumberOfZeros >= NumberOfMemoryUnit) {
2993         //
2994         // Found enough consecutive free space,break the loop
2995         //
2996         break;
2997       } else {
2998         //
2999         // the NumberOfZeros only record the number of those consecutive zeros,
3000         // so reset the NumberOfZeros to 0 when encountering '1' before finding
3001         // enough consecutive '0's
3002         //
3003         NumberOfZeros = 0;
3004         //
3005         // reset the (FoundBytePos,FoundBitPos) to the position of '1'
3006         //
3007         FoundBytePos  = TempBytePos;
3008         FoundBitPos   = Index;
3009       }
3010     }
3011     //
3012     // right shift the byte
3013     //
3014     ByteValue /= 2;
3015 
3016     //
3017     // step forward a bit
3018     //
3019     Index++;
3020     if (Index == 8) {
3021       //
3022       // step forward a byte, getting the byte value,
3023       // and reset the bit pos.
3024       //
3025       TempBytePos += 1;
3026       ByteValue = MemoryHeader->BitArrayPtr[TempBytePos];
3027       Index     = 0;
3028     }
3029   }
3030 
3031   if (NumberOfZeros < NumberOfMemoryUnit) {
3032     return EFI_NOT_FOUND;
3033   }
3034   //
3035   // Found enough free space.
3036   //
3037   //
3038   // The values recorded in (FoundBytePos,FoundBitPos) have two conditions:
3039   //  1)(FoundBytePos,FoundBitPos) record the position
3040   //    of the last '1' before the consecutive '0's, it must
3041   //    be adjusted to the start position of the consecutive '0's.
3042   //  2)the start address of the consecutive '0's is just the start of
3043   //    the bitarray. so no need to adjust the values of (FoundBytePos,FoundBitPos).
3044   //
3045   if ((MemoryHeader->BitArrayPtr[0] & BIT0) != 0) {
3046     FoundBitPos += 1;
3047   }
3048   //
3049   // Have the (FoundBytePos,FoundBitPos) make sense.
3050   //
3051   if (FoundBitPos > 7) {
3052     FoundBytePos += 1;
3053     FoundBitPos -= 8;
3054   }
3055   //
3056   // Set the memory as allocated
3057   //
3058   for (TempBytePos = FoundBytePos, Index = FoundBitPos, Count = 0; Count < NumberOfMemoryUnit; Count++) {
3059 
3060     MemoryHeader->BitArrayPtr[TempBytePos] = (UINT8) (MemoryHeader->BitArrayPtr[TempBytePos] | (1 << Index));
3061     Index++;
3062     if (Index == 8) {
3063       TempBytePos += 1;
3064       Index = 0;
3065     }
3066   }
3067 
3068   *Pool = MemoryHeader->MemoryBlockPtr + (FoundBytePos * 8 + FoundBitPos) * 32;
3069 
3070   return EFI_SUCCESS;
3071 }
3072 
3073 /**
3074   Uhci Free Pool.
3075 
3076   @param  UhcDev                 The UHCI device.
3077   @param  Pool                   A pointer to store the buffer address.
3078   @param  AllocSize              The size of the pool to be freed.
3079 
3080 **/
3081 VOID
UhcFreePool(IN USB_UHC_DEV * UhcDev,IN UINT8 * Pool,IN UINTN AllocSize)3082 UhcFreePool (
3083   IN USB_UHC_DEV     *UhcDev,
3084   IN UINT8           *Pool,
3085   IN UINTN           AllocSize
3086   )
3087 {
3088   MEMORY_MANAGE_HEADER  *MemoryHeader;
3089   MEMORY_MANAGE_HEADER  *TempHeaderPtr;
3090   UINTN                 StartBytePos;
3091   UINTN                 Index;
3092   UINT8                 StartBitPos;
3093   UINT8                 Index2;
3094   UINTN                 Count;
3095   UINTN                 RealAllocSize;
3096 
3097   MemoryHeader = UhcDev->Header1;
3098 
3099   //
3100   // allocate unit is 32 byte (align on 32 byte)
3101   //
3102   if ((AllocSize & 0x1F) != 0) {
3103     RealAllocSize = (AllocSize / 32 + 1) * 32;
3104   } else {
3105     RealAllocSize = AllocSize;
3106   }
3107 
3108   for (TempHeaderPtr = MemoryHeader; TempHeaderPtr != NULL;
3109        TempHeaderPtr = TempHeaderPtr->Next) {
3110 
3111     if ((Pool >= TempHeaderPtr->MemoryBlockPtr) &&
3112         ((Pool + RealAllocSize) <= (TempHeaderPtr->MemoryBlockPtr +
3113                                     TempHeaderPtr->MemoryBlockSizeInBytes))) {
3114 
3115       //
3116       // Pool is in the Memory Block area,
3117       // find the start byte and bit in the bit array
3118       //
3119       StartBytePos  = ((Pool - TempHeaderPtr->MemoryBlockPtr) / 32) / 8;
3120       StartBitPos   = (UINT8) (((Pool - TempHeaderPtr->MemoryBlockPtr) / 32) % 8);
3121 
3122       //
3123       // reset associated bits in bit array
3124       //
3125       for (Index = StartBytePos, Index2 = StartBitPos, Count = 0; Count < (RealAllocSize / 32); Count++) {
3126 
3127         TempHeaderPtr->BitArrayPtr[Index] = (UINT8) (TempHeaderPtr->BitArrayPtr[Index] ^ (1 << Index2));
3128         Index2++;
3129         if (Index2 == 8) {
3130           Index += 1;
3131           Index2 = 0;
3132         }
3133       }
3134       //
3135       // break the loop
3136       //
3137       break;
3138     }
3139   }
3140 
3141 }
3142 
3143 /**
3144   Insert a new memory header into list.
3145 
3146   @param  MemoryHeader         A pointer to the memory header list.
3147   @param  NewMemoryHeader      A new memory header to be inserted into the list.
3148 
3149 **/
3150 VOID
InsertMemoryHeaderToList(IN MEMORY_MANAGE_HEADER * MemoryHeader,IN MEMORY_MANAGE_HEADER * NewMemoryHeader)3151 InsertMemoryHeaderToList (
3152   IN MEMORY_MANAGE_HEADER  *MemoryHeader,
3153   IN MEMORY_MANAGE_HEADER  *NewMemoryHeader
3154   )
3155 {
3156   MEMORY_MANAGE_HEADER  *TempHeaderPtr;
3157 
3158   for (TempHeaderPtr = MemoryHeader; TempHeaderPtr != NULL; TempHeaderPtr = TempHeaderPtr->Next) {
3159     if (TempHeaderPtr->Next == NULL) {
3160       TempHeaderPtr->Next = NewMemoryHeader;
3161       break;
3162     }
3163   }
3164 }
3165 
3166 /**
3167   Judge the memory block in the memory header is empty or not.
3168 
3169   @param  MemoryHeaderPtr   A pointer to the memory header list.
3170 
3171   @retval Whether the memory block in the memory header is empty or not.
3172 
3173 **/
3174 BOOLEAN
IsMemoryBlockEmptied(IN MEMORY_MANAGE_HEADER * MemoryHeaderPtr)3175 IsMemoryBlockEmptied (
3176   IN MEMORY_MANAGE_HEADER  *MemoryHeaderPtr
3177   )
3178 {
3179   UINTN Index;
3180 
3181   for (Index = 0; Index < MemoryHeaderPtr->BitArraySizeInBytes; Index++) {
3182     if (MemoryHeaderPtr->BitArrayPtr[Index] != 0) {
3183       return FALSE;
3184     }
3185   }
3186 
3187   return TRUE;
3188 }
3189 
3190 /**
3191   remove a memory header from list.
3192 
3193   @param  FirstMemoryHeader   A pointer to the memory header list.
3194   @param  FreeMemoryHeader    A memory header to be removed into the list.
3195 
3196 **/
3197 VOID
DelinkMemoryBlock(IN MEMORY_MANAGE_HEADER * FirstMemoryHeader,IN MEMORY_MANAGE_HEADER * FreeMemoryHeader)3198 DelinkMemoryBlock (
3199   IN MEMORY_MANAGE_HEADER    *FirstMemoryHeader,
3200   IN MEMORY_MANAGE_HEADER    *FreeMemoryHeader
3201   )
3202 {
3203   MEMORY_MANAGE_HEADER  *TempHeaderPtr;
3204 
3205   if ((FirstMemoryHeader == NULL) || (FreeMemoryHeader == NULL)) {
3206     return ;
3207   }
3208 
3209   for (TempHeaderPtr = FirstMemoryHeader; TempHeaderPtr != NULL; TempHeaderPtr = TempHeaderPtr->Next) {
3210 
3211     if (TempHeaderPtr->Next == FreeMemoryHeader) {
3212       //
3213       // Link the before and after
3214       //
3215       TempHeaderPtr->Next = FreeMemoryHeader->Next;
3216       break;
3217     }
3218   }
3219 }
3220