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