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