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