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