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