]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/UhciPei/UhcPeim.c
MdeModulePkg UhciPei: Also check TempPtr against NULL to return error
[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 - 2017, 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 Get Current Frame Number.
1257
1258 @param UhcDev The UHCI device.
1259 @param FrameNumberAddr The address of frame list register.
1260
1261 @retval The content of the frame list register.
1262
1263 **/
1264 UINT16
1265 GetCurrentFrameNumber (
1266 IN USB_UHC_DEV *UhcDev,
1267 IN UINT32 FrameNumberAddr
1268 )
1269 {
1270 //
1271 // Gets value in the USB frame number register.
1272 //
1273 return (UINT16) (USBReadPortW (UhcDev, FrameNumberAddr) & 0x03FF);
1274 }
1275
1276 /**
1277 Set Frame List Base Address.
1278
1279 @param UhcDev The UHCI device.
1280 @param FrameListRegAddr The address of frame list register.
1281 @param Addr The address of frame list table.
1282
1283 **/
1284 VOID
1285 SetFrameListBaseAddress (
1286 IN USB_UHC_DEV *UhcDev,
1287 IN UINT32 FrameListRegAddr,
1288 IN UINT32 Addr
1289 )
1290 {
1291 //
1292 // Sets value in the USB Frame List Base Address register.
1293 //
1294 USBWritePortDW (UhcDev, FrameListRegAddr, (UINT32) (Addr & 0xFFFFF000));
1295 }
1296
1297 /**
1298 Create QH and initialize.
1299
1300 @param UhcDev The UHCI device.
1301 @param PtrQH Place to store QH_STRUCT pointer.
1302
1303 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
1304 @retval EFI_SUCCESS Success.
1305
1306 **/
1307 EFI_STATUS
1308 CreateQH (
1309 IN USB_UHC_DEV *UhcDev,
1310 OUT QH_STRUCT **PtrQH
1311 )
1312 {
1313 EFI_STATUS Status;
1314
1315 //
1316 // allocate align memory for QH_STRUCT
1317 //
1318 Status = AllocateTDorQHStruct (UhcDev, sizeof(QH_STRUCT), (void **)PtrQH);
1319 if (EFI_ERROR (Status)) {
1320 return EFI_OUT_OF_RESOURCES;
1321 }
1322 //
1323 // init each field of the QH_STRUCT
1324 //
1325 SetQHHorizontalValidorInvalid (*PtrQH, FALSE);
1326 SetQHVerticalValidorInvalid (*PtrQH, FALSE);
1327
1328 return EFI_SUCCESS;
1329 }
1330
1331 /**
1332 Set the horizontal link pointer in QH.
1333
1334 @param PtrQH Place to store QH_STRUCT pointer.
1335 @param PtrNext Place to the next QH_STRUCT.
1336
1337 **/
1338 VOID
1339 SetQHHorizontalLinkPtr (
1340 IN QH_STRUCT *PtrQH,
1341 IN VOID *PtrNext
1342 )
1343 {
1344 //
1345 // Since the QH_STRUCT is aligned on 16-byte boundaries,
1346 // Only the highest 28bit of the address is valid
1347 // (take 32bit address as an example).
1348 //
1349 PtrQH->QueueHead.QHHorizontalPtr = (UINT32) (UINTN) PtrNext >> 4;
1350 }
1351
1352 /**
1353 Get the horizontal link pointer in QH.
1354
1355 @param PtrQH Place to store QH_STRUCT pointer.
1356
1357 @retval The horizontal link pointer in QH.
1358
1359 **/
1360 VOID *
1361 GetQHHorizontalLinkPtr (
1362 IN QH_STRUCT *PtrQH
1363 )
1364 {
1365 //
1366 // Restore the 28bit address to 32bit address
1367 // (take 32bit address as an example)
1368 //
1369 return (VOID *) (UINTN) ((PtrQH->QueueHead.QHHorizontalPtr) << 4);
1370 }
1371
1372 /**
1373 Set a QH or TD horizontally to be connected with a specific QH.
1374
1375 @param PtrQH Place to store QH_STRUCT pointer.
1376 @param IsQH Specify QH or TD is connected.
1377
1378 **/
1379 VOID
1380 SetQHHorizontalQHorTDSelect (
1381 IN QH_STRUCT *PtrQH,
1382 IN BOOLEAN IsQH
1383 )
1384 {
1385 //
1386 // if QH is connected, the specified bit is set,
1387 // if TD is connected, the specified bit is cleared.
1388 //
1389 PtrQH->QueueHead.QHHorizontalQSelect = IsQH ? 1 : 0;
1390 }
1391
1392 /**
1393 Set the horizontal validor bit in QH.
1394
1395 @param PtrQH Place to store QH_STRUCT pointer.
1396 @param IsValid Specify the horizontal linker is valid or not.
1397
1398 **/
1399 VOID
1400 SetQHHorizontalValidorInvalid (
1401 IN QH_STRUCT *PtrQH,
1402 IN BOOLEAN IsValid
1403 )
1404 {
1405 //
1406 // Valid means the horizontal link pointer is valid,
1407 // else, it's invalid.
1408 //
1409 PtrQH->QueueHead.QHHorizontalTerminate = IsValid ? 0 : 1;
1410 }
1411
1412 /**
1413 Set the vertical link pointer in QH.
1414
1415 @param PtrQH Place to store QH_STRUCT pointer.
1416 @param PtrNext Place to the next QH_STRUCT.
1417
1418 **/
1419 VOID
1420 SetQHVerticalLinkPtr (
1421 IN QH_STRUCT *PtrQH,
1422 IN VOID *PtrNext
1423 )
1424 {
1425 //
1426 // Since the QH_STRUCT is aligned on 16-byte boundaries,
1427 // Only the highest 28bit of the address is valid
1428 // (take 32bit address as an example).
1429 //
1430 PtrQH->QueueHead.QHVerticalPtr = (UINT32) (UINTN) PtrNext >> 4;
1431 }
1432
1433 /**
1434 Set a QH or TD vertically to be connected with a specific QH.
1435
1436 @param PtrQH Place to store QH_STRUCT pointer.
1437 @param IsQH Specify QH or TD is connected.
1438
1439 **/
1440 VOID
1441 SetQHVerticalQHorTDSelect (
1442 IN QH_STRUCT *PtrQH,
1443 IN BOOLEAN IsQH
1444 )
1445 {
1446 //
1447 // Set the specified bit if the Vertical Link Pointer pointing to a QH,
1448 // Clear the specified bit if the Vertical Link Pointer pointing to a TD.
1449 //
1450 PtrQH->QueueHead.QHVerticalQSelect = IsQH ? 1 : 0;
1451 }
1452
1453 /**
1454 Set the vertical validor bit in QH.
1455
1456 @param PtrQH Place to store QH_STRUCT pointer.
1457 @param IsValid Specify the vertical linker is valid or not.
1458
1459 **/
1460 VOID
1461 SetQHVerticalValidorInvalid (
1462 IN QH_STRUCT *PtrQH,
1463 IN BOOLEAN IsValid
1464 )
1465 {
1466 //
1467 // If TRUE, meaning the Vertical Link Pointer field is valid,
1468 // else, the field is invalid.
1469 //
1470 PtrQH->QueueHead.QHVerticalTerminate = IsValid ? 0 : 1;
1471 }
1472
1473 /**
1474 Get the vertical validor bit in QH.
1475
1476 @param PtrQH Place to store QH_STRUCT pointer.
1477
1478 @retval The vertical linker is valid or not.
1479
1480 **/
1481 BOOLEAN
1482 GetQHHorizontalValidorInvalid (
1483 IN QH_STRUCT *PtrQH
1484 )
1485 {
1486 //
1487 // If TRUE, meaning the Horizontal Link Pointer field is valid,
1488 // else, the field is invalid.
1489 //
1490 return (BOOLEAN) (!(PtrQH->QueueHead.QHHorizontalTerminate));
1491 }
1492
1493 /**
1494 Allocate TD or QH Struct.
1495
1496 @param UhcDev The UHCI device.
1497 @param Size The size of allocation.
1498 @param PtrStruct Place to store TD_STRUCT pointer.
1499
1500 @return EFI_SUCCESS Allocate successfully.
1501 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
1502
1503 **/
1504 EFI_STATUS
1505 AllocateTDorQHStruct (
1506 IN USB_UHC_DEV *UhcDev,
1507 IN UINT32 Size,
1508 OUT VOID **PtrStruct
1509 )
1510 {
1511 EFI_STATUS Status;
1512
1513 Status = EFI_SUCCESS;
1514 *PtrStruct = NULL;
1515
1516 Status = UhcAllocatePool (
1517 UhcDev,
1518 (UINT8 **) PtrStruct,
1519 Size
1520 );
1521 if (EFI_ERROR (Status)) {
1522 return Status;
1523 }
1524
1525 ZeroMem (*PtrStruct, Size);
1526
1527 return Status;
1528 }
1529
1530 /**
1531 Create a TD Struct.
1532
1533 @param UhcDev The UHCI device.
1534 @param PtrTD Place to store TD_STRUCT pointer.
1535
1536 @return EFI_SUCCESS Allocate successfully.
1537 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
1538
1539 **/
1540 EFI_STATUS
1541 CreateTD (
1542 IN USB_UHC_DEV *UhcDev,
1543 OUT TD_STRUCT **PtrTD
1544 )
1545 {
1546 EFI_STATUS Status;
1547 //
1548 // create memory for TD_STRUCT, and align the memory.
1549 //
1550 Status = AllocateTDorQHStruct (UhcDev, sizeof(TD_STRUCT), (void **)PtrTD);
1551 if (EFI_ERROR (Status)) {
1552 return Status;
1553 }
1554
1555 //
1556 // Make TD ready.
1557 //
1558 SetTDLinkPtrValidorInvalid (*PtrTD, FALSE);
1559
1560 return EFI_SUCCESS;
1561 }
1562
1563 /**
1564 Generate Setup Stage TD.
1565
1566 @param UhcDev The UHCI device.
1567 @param DevAddr Device address.
1568 @param Endpoint Endpoint number.
1569 @param DeviceSpeed Device Speed.
1570 @param DevRequest CPU memory address of request structure buffer to transfer.
1571 @param RequestPhy PCI memory address of request structure buffer to transfer.
1572 @param RequestLen Request length.
1573 @param PtrTD TD_STRUCT generated.
1574
1575 @return EFI_SUCCESS Generate setup stage TD successfully.
1576 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
1577
1578 **/
1579 EFI_STATUS
1580 GenSetupStageTD (
1581 IN USB_UHC_DEV *UhcDev,
1582 IN UINT8 DevAddr,
1583 IN UINT8 Endpoint,
1584 IN UINT8 DeviceSpeed,
1585 IN UINT8 *DevRequest,
1586 IN UINT8 *RequestPhy,
1587 IN UINT8 RequestLen,
1588 OUT TD_STRUCT **PtrTD
1589 )
1590 {
1591 TD_STRUCT *TdStruct;
1592 EFI_STATUS Status;
1593
1594 Status = CreateTD (UhcDev, &TdStruct);
1595 if (EFI_ERROR (Status)) {
1596 return Status;
1597 }
1598
1599 SetTDLinkPtr (TdStruct, NULL);
1600
1601 //
1602 // Depth first fashion
1603 //
1604 SetTDLinkPtrDepthorBreadth (TdStruct, TRUE);
1605
1606 //
1607 // initialize as the last TD in the QH context,
1608 // this field will be updated in the TD linkage process.
1609 //
1610 SetTDLinkPtrValidorInvalid (TdStruct, FALSE);
1611
1612 //
1613 // Disable Short Packet Detection by default
1614 //
1615 EnableorDisableTDShortPacket (TdStruct, FALSE);
1616
1617 //
1618 // Max error counter is 3, retry 3 times when error encountered.
1619 //
1620 SetTDControlErrorCounter (TdStruct, 3);
1621
1622 //
1623 // set device speed attribute
1624 // (TRUE - Slow Device; FALSE - Full Speed Device)
1625 //
1626 switch (DeviceSpeed) {
1627 case USB_SLOW_SPEED_DEVICE:
1628 SetTDLoworFullSpeedDevice (TdStruct, TRUE);
1629 break;
1630
1631 case USB_FULL_SPEED_DEVICE:
1632 SetTDLoworFullSpeedDevice (TdStruct, FALSE);
1633 break;
1634 }
1635 //
1636 // Non isochronous transfer TD
1637 //
1638 SetTDControlIsochronousorNot (TdStruct, FALSE);
1639
1640 //
1641 // Interrupt On Complete bit be set to zero,
1642 // Disable IOC interrupt.
1643 //
1644 SetorClearTDControlIOC (TdStruct, FALSE);
1645
1646 //
1647 // Set TD Active bit
1648 //
1649 SetTDStatusActiveorInactive (TdStruct, TRUE);
1650
1651 SetTDTokenMaxLength (TdStruct, RequestLen);
1652
1653 SetTDTokenDataToggle0 (TdStruct);
1654
1655 SetTDTokenEndPoint (TdStruct, Endpoint);
1656
1657 SetTDTokenDeviceAddress (TdStruct, DevAddr);
1658
1659 SetTDTokenPacketID (TdStruct, SETUP_PACKET_ID);
1660
1661 TdStruct->PtrTDBuffer = (UINT8 *) DevRequest;
1662 TdStruct->TDBufferLength = RequestLen;
1663 //
1664 // Set the beginning address of the buffer that will be used
1665 // during the transaction.
1666 //
1667 TdStruct->TDData.TDBufferPtr = (UINT32) (UINTN) RequestPhy;
1668
1669 *PtrTD = TdStruct;
1670
1671 return EFI_SUCCESS;
1672 }
1673
1674 /**
1675 Generate Data Stage TD.
1676
1677 @param UhcDev The UHCI device.
1678 @param DevAddr Device address.
1679 @param Endpoint Endpoint number.
1680 @param PtrData CPU memory address of user data buffer to transfer.
1681 @param DataPhy PCI memory address of user data buffer to transfer.
1682 @param Len Data length.
1683 @param PktID PacketID.
1684 @param Toggle Data toggle value.
1685 @param DeviceSpeed Device Speed.
1686 @param PtrTD TD_STRUCT generated.
1687
1688 @return EFI_SUCCESS Generate data stage TD successfully.
1689 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
1690
1691 **/
1692 EFI_STATUS
1693 GenDataTD (
1694 IN USB_UHC_DEV *UhcDev,
1695 IN UINT8 DevAddr,
1696 IN UINT8 Endpoint,
1697 IN UINT8 *PtrData,
1698 IN UINT8 *DataPhy,
1699 IN UINT8 Len,
1700 IN UINT8 PktID,
1701 IN UINT8 Toggle,
1702 IN UINT8 DeviceSpeed,
1703 OUT TD_STRUCT **PtrTD
1704 )
1705 {
1706 TD_STRUCT *TdStruct;
1707 EFI_STATUS Status;
1708
1709 Status = CreateTD (UhcDev, &TdStruct);
1710 if (EFI_ERROR (Status)) {
1711 return Status;
1712 }
1713
1714 SetTDLinkPtr (TdStruct, NULL);
1715
1716 //
1717 // Depth first fashion
1718 //
1719 SetTDLinkPtrDepthorBreadth (TdStruct, TRUE);
1720
1721 //
1722 // Link pointer pointing to TD struct
1723 //
1724 SetTDLinkPtrQHorTDSelect (TdStruct, FALSE);
1725
1726 //
1727 // initialize as the last TD in the QH context,
1728 // this field will be updated in the TD linkage process.
1729 //
1730 SetTDLinkPtrValidorInvalid (TdStruct, FALSE);
1731
1732 //
1733 // Disable short packet detect
1734 //
1735 EnableorDisableTDShortPacket (TdStruct, FALSE);
1736 //
1737 // Max error counter is 3
1738 //
1739 SetTDControlErrorCounter (TdStruct, 3);
1740
1741 //
1742 // set device speed attribute
1743 // (TRUE - Slow Device; FALSE - Full Speed Device)
1744 //
1745 switch (DeviceSpeed) {
1746 case USB_SLOW_SPEED_DEVICE:
1747 SetTDLoworFullSpeedDevice (TdStruct, TRUE);
1748 break;
1749
1750 case USB_FULL_SPEED_DEVICE:
1751 SetTDLoworFullSpeedDevice (TdStruct, FALSE);
1752 break;
1753 }
1754 //
1755 // Non isochronous transfer TD
1756 //
1757 SetTDControlIsochronousorNot (TdStruct, FALSE);
1758
1759 //
1760 // Disable Interrupt On Complete
1761 // Disable IOC interrupt.
1762 //
1763 SetorClearTDControlIOC (TdStruct, FALSE);
1764
1765 //
1766 // Set Active bit
1767 //
1768 SetTDStatusActiveorInactive (TdStruct, TRUE);
1769
1770 SetTDTokenMaxLength (TdStruct, Len);
1771
1772 if (Toggle != 0) {
1773 SetTDTokenDataToggle1 (TdStruct);
1774 } else {
1775 SetTDTokenDataToggle0 (TdStruct);
1776 }
1777
1778 SetTDTokenEndPoint (TdStruct, Endpoint);
1779
1780 SetTDTokenDeviceAddress (TdStruct, DevAddr);
1781
1782 SetTDTokenPacketID (TdStruct, PktID);
1783
1784 TdStruct->PtrTDBuffer = (UINT8 *) PtrData;
1785 TdStruct->TDBufferLength = Len;
1786 //
1787 // Set the beginning address of the buffer that will be used
1788 // during the transaction.
1789 //
1790 TdStruct->TDData.TDBufferPtr = (UINT32) (UINTN) DataPhy;
1791
1792 *PtrTD = TdStruct;
1793
1794 return EFI_SUCCESS;
1795 }
1796
1797 /**
1798 Generate Status Stage TD.
1799
1800 @param UhcDev The UHCI device.
1801 @param DevAddr Device address.
1802 @param Endpoint Endpoint number.
1803 @param PktID PacketID.
1804 @param DeviceSpeed Device Speed.
1805 @param PtrTD TD_STRUCT generated.
1806
1807 @return EFI_SUCCESS Generate status stage TD successfully.
1808 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resource.
1809
1810 **/
1811 EFI_STATUS
1812 CreateStatusTD (
1813 IN USB_UHC_DEV *UhcDev,
1814 IN UINT8 DevAddr,
1815 IN UINT8 Endpoint,
1816 IN UINT8 PktID,
1817 IN UINT8 DeviceSpeed,
1818 OUT TD_STRUCT **PtrTD
1819 )
1820 {
1821 TD_STRUCT *PtrTDStruct;
1822 EFI_STATUS Status;
1823
1824 Status = CreateTD (UhcDev, &PtrTDStruct);
1825 if (EFI_ERROR (Status)) {
1826 return Status;
1827 }
1828
1829 SetTDLinkPtr (PtrTDStruct, NULL);
1830
1831 //
1832 // Depth first fashion
1833 //
1834 SetTDLinkPtrDepthorBreadth (PtrTDStruct, TRUE);
1835
1836 //
1837 // initialize as the last TD in the QH context,
1838 // this field will be updated in the TD linkage process.
1839 //
1840 SetTDLinkPtrValidorInvalid (PtrTDStruct, FALSE);
1841
1842 //
1843 // Disable short packet detect
1844 //
1845 EnableorDisableTDShortPacket (PtrTDStruct, FALSE);
1846
1847 //
1848 // Max error counter is 3
1849 //
1850 SetTDControlErrorCounter (PtrTDStruct, 3);
1851
1852 //
1853 // set device speed attribute
1854 // (TRUE - Slow Device; FALSE - Full Speed Device)
1855 //
1856 switch (DeviceSpeed) {
1857 case USB_SLOW_SPEED_DEVICE:
1858 SetTDLoworFullSpeedDevice (PtrTDStruct, TRUE);
1859 break;
1860
1861 case USB_FULL_SPEED_DEVICE:
1862 SetTDLoworFullSpeedDevice (PtrTDStruct, FALSE);
1863 break;
1864 }
1865 //
1866 // Non isochronous transfer TD
1867 //
1868 SetTDControlIsochronousorNot (PtrTDStruct, FALSE);
1869
1870 //
1871 // Disable Interrupt On Complete
1872 // Disable IOC interrupt.
1873 //
1874 SetorClearTDControlIOC (PtrTDStruct, FALSE);
1875
1876 //
1877 // Set TD Active bit
1878 //
1879 SetTDStatusActiveorInactive (PtrTDStruct, TRUE);
1880
1881 SetTDTokenMaxLength (PtrTDStruct, 0);
1882
1883 SetTDTokenDataToggle1 (PtrTDStruct);
1884
1885 SetTDTokenEndPoint (PtrTDStruct, Endpoint);
1886
1887 SetTDTokenDeviceAddress (PtrTDStruct, DevAddr);
1888
1889 SetTDTokenPacketID (PtrTDStruct, PktID);
1890
1891 PtrTDStruct->PtrTDBuffer = NULL;
1892 PtrTDStruct->TDBufferLength = 0;
1893 //
1894 // Set the beginning address of the buffer that will be used
1895 // during the transaction.
1896 //
1897 PtrTDStruct->TDData.TDBufferPtr = 0;
1898
1899 *PtrTD = PtrTDStruct;
1900
1901 return EFI_SUCCESS;
1902 }
1903
1904 /**
1905 Set the link pointer validor bit in TD.
1906
1907 @param PtrTDStruct Place to store TD_STRUCT pointer.
1908 @param IsValid Specify the linker pointer is valid or not.
1909
1910 **/
1911 VOID
1912 SetTDLinkPtrValidorInvalid (
1913 IN TD_STRUCT *PtrTDStruct,
1914 IN BOOLEAN IsValid
1915 )
1916 {
1917 //
1918 // Valid means the link pointer is valid,
1919 // else, it's invalid.
1920 //
1921 PtrTDStruct->TDData.TDLinkPtrTerminate = (IsValid ? 0 : 1);
1922 }
1923
1924 /**
1925 Set the Link Pointer pointing to a QH or TD.
1926
1927 @param PtrTDStruct Place to store TD_STRUCT pointer.
1928 @param IsQH Specify QH or TD is connected.
1929
1930 **/
1931 VOID
1932 SetTDLinkPtrQHorTDSelect (
1933 IN TD_STRUCT *PtrTDStruct,
1934 IN BOOLEAN IsQH
1935 )
1936 {
1937 //
1938 // Indicate whether the Link Pointer pointing to a QH or TD
1939 //
1940 PtrTDStruct->TDData.TDLinkPtrQSelect = (IsQH ? 1 : 0);
1941 }
1942
1943 /**
1944 Set the traverse is depth-first or breadth-first.
1945
1946 @param PtrTDStruct Place to store TD_STRUCT pointer.
1947 @param IsDepth Specify the traverse is depth-first or breadth-first.
1948
1949 **/
1950 VOID
1951 SetTDLinkPtrDepthorBreadth (
1952 IN TD_STRUCT *PtrTDStruct,
1953 IN BOOLEAN IsDepth
1954 )
1955 {
1956 //
1957 // If TRUE, indicating the host controller should process in depth first fashion,
1958 // else, the host controller should process in breadth first fashion
1959 //
1960 PtrTDStruct->TDData.TDLinkPtrDepthSelect = (IsDepth ? 1 : 0);
1961 }
1962
1963 /**
1964 Set TD Link Pointer in TD.
1965
1966 @param PtrTDStruct Place to store TD_STRUCT pointer.
1967 @param PtrNext Place to the next TD_STRUCT.
1968
1969 **/
1970 VOID
1971 SetTDLinkPtr (
1972 IN TD_STRUCT *PtrTDStruct,
1973 IN VOID *PtrNext
1974 )
1975 {
1976 //
1977 // Set TD Link Pointer. Since QH,TD align on 16-byte boundaries,
1978 // only the highest 28 bits are valid. (if take 32bit address as an example)
1979 //
1980 PtrTDStruct->TDData.TDLinkPtr = (UINT32) (UINTN) PtrNext >> 4;
1981 }
1982
1983 /**
1984 Get TD Link Pointer.
1985
1986 @param PtrTDStruct Place to store TD_STRUCT pointer.
1987
1988 @retval Get TD Link Pointer in TD.
1989
1990 **/
1991 VOID *
1992 GetTDLinkPtr (
1993 IN TD_STRUCT *PtrTDStruct
1994 )
1995 {
1996 //
1997 // Get TD Link Pointer. Restore it back to 32bit
1998 // (if take 32bit address as an example)
1999 //
2000 return (VOID *) (UINTN) ((PtrTDStruct->TDData.TDLinkPtr) << 4);
2001 }
2002
2003 /**
2004 Get the information about whether the Link Pointer field pointing to
2005 a QH or a TD.
2006
2007 @param PtrTDStruct Place to store TD_STRUCT pointer.
2008
2009 @retval whether the Link Pointer field pointing to a QH or a TD.
2010
2011 **/
2012 BOOLEAN
2013 IsTDLinkPtrQHOrTD (
2014 IN TD_STRUCT *PtrTDStruct
2015 )
2016 {
2017 //
2018 // Get the information about whether the Link Pointer field pointing to
2019 // a QH or a TD.
2020 //
2021 return (BOOLEAN) (PtrTDStruct->TDData.TDLinkPtrQSelect);
2022 }
2023
2024 /**
2025 Enable/Disable short packet detection mechanism.
2026
2027 @param PtrTDStruct Place to store TD_STRUCT pointer.
2028 @param IsEnable Enable or disable short packet detection mechanism.
2029
2030 **/
2031 VOID
2032 EnableorDisableTDShortPacket (
2033 IN TD_STRUCT *PtrTDStruct,
2034 IN BOOLEAN IsEnable
2035 )
2036 {
2037 //
2038 // TRUE means enable short packet detection mechanism.
2039 //
2040 PtrTDStruct->TDData.TDStatusSPD = (IsEnable ? 1 : 0);
2041 }
2042
2043 /**
2044 Set the max error counter in TD.
2045
2046 @param PtrTDStruct Place to store TD_STRUCT pointer.
2047 @param MaxErrors The number of allowable error.
2048
2049 **/
2050 VOID
2051 SetTDControlErrorCounter (
2052 IN TD_STRUCT *PtrTDStruct,
2053 IN UINT8 MaxErrors
2054 )
2055 {
2056 //
2057 // valid value of MaxErrors is 0,1,2,3
2058 //
2059 if (MaxErrors > 3) {
2060 MaxErrors = 3;
2061 }
2062
2063 PtrTDStruct->TDData.TDStatusErr = MaxErrors;
2064 }
2065
2066 /**
2067 Set the TD is targeting a low-speed device or not.
2068
2069 @param PtrTDStruct Place to store TD_STRUCT pointer.
2070 @param IsLowSpeedDevice Whether The device is low-speed.
2071
2072 **/
2073 VOID
2074 SetTDLoworFullSpeedDevice (
2075 IN TD_STRUCT *PtrTDStruct,
2076 IN BOOLEAN IsLowSpeedDevice
2077 )
2078 {
2079 //
2080 // TRUE means the TD is targeting at a Low-speed device
2081 //
2082 PtrTDStruct->TDData.TDStatusLS = (IsLowSpeedDevice ? 1 : 0);
2083 }
2084
2085 /**
2086 Set the TD is isochronous transfer type or not.
2087
2088 @param PtrTDStruct Place to store TD_STRUCT pointer.
2089 @param IsIsochronous Whether the transaction isochronous transfer type.
2090
2091 **/
2092 VOID
2093 SetTDControlIsochronousorNot (
2094 IN TD_STRUCT *PtrTDStruct,
2095 IN BOOLEAN IsIsochronous
2096 )
2097 {
2098 //
2099 // TRUE means the TD belongs to Isochronous transfer type.
2100 //
2101 PtrTDStruct->TDData.TDStatusIOS = (IsIsochronous ? 1 : 0);
2102 }
2103
2104 /**
2105 Set if UCHI should issue an interrupt on completion of the frame
2106 in which this TD is executed
2107
2108 @param PtrTDStruct Place to store TD_STRUCT pointer.
2109 @param IsSet Whether HC should issue an interrupt on completion.
2110
2111 **/
2112 VOID
2113 SetorClearTDControlIOC (
2114 IN TD_STRUCT *PtrTDStruct,
2115 IN BOOLEAN IsSet
2116 )
2117 {
2118 //
2119 // If this bit is set, it indicates that the host controller should issue
2120 // an interrupt on completion of the frame in which this TD is executed.
2121 //
2122 PtrTDStruct->TDData.TDStatusIOC = IsSet ? 1 : 0;
2123 }
2124
2125 /**
2126 Set if the TD is active and can be executed.
2127
2128 @param PtrTDStruct Place to store TD_STRUCT pointer.
2129 @param IsActive Whether the TD is active and can be executed.
2130
2131 **/
2132 VOID
2133 SetTDStatusActiveorInactive (
2134 IN TD_STRUCT *PtrTDStruct,
2135 IN BOOLEAN IsActive
2136 )
2137 {
2138 //
2139 // If this bit is set, it indicates that the TD is active and can be
2140 // executed.
2141 //
2142 if (IsActive) {
2143 PtrTDStruct->TDData.TDStatus |= 0x80;
2144 } else {
2145 PtrTDStruct->TDData.TDStatus &= 0x7F;
2146 }
2147 }
2148
2149 /**
2150 Specifies the maximum number of data bytes allowed for the transfer.
2151
2152 @param PtrTDStruct Place to store TD_STRUCT pointer.
2153 @param MaxLen The maximum number of data bytes allowed.
2154
2155 @retval The allowed maximum number of data.
2156 **/
2157 UINT16
2158 SetTDTokenMaxLength (
2159 IN TD_STRUCT *PtrTDStruct,
2160 IN UINT16 MaxLen
2161 )
2162 {
2163 //
2164 // Specifies the maximum number of data bytes allowed for the transfer.
2165 // the legal value extent is 0 ~ 0x500.
2166 //
2167 if (MaxLen > 0x500) {
2168 MaxLen = 0x500;
2169 }
2170
2171 PtrTDStruct->TDData.TDTokenMaxLen = MaxLen - 1;
2172
2173 return MaxLen;
2174 }
2175
2176 /**
2177 Set the data toggle bit to DATA1.
2178
2179 @param PtrTDStruct Place to store TD_STRUCT pointer.
2180
2181 **/
2182 VOID
2183 SetTDTokenDataToggle1 (
2184 IN TD_STRUCT *PtrTDStruct
2185 )
2186 {
2187 //
2188 // Set the data toggle bit to DATA1
2189 //
2190 PtrTDStruct->TDData.TDTokenDataToggle = 1;
2191 }
2192
2193 /**
2194 Set the data toggle bit to DATA0.
2195
2196 @param PtrTDStruct Place to store TD_STRUCT pointer.
2197
2198 **/
2199 VOID
2200 SetTDTokenDataToggle0 (
2201 IN TD_STRUCT *PtrTDStruct
2202 )
2203 {
2204 //
2205 // Set the data toggle bit to DATA0
2206 //
2207 PtrTDStruct->TDData.TDTokenDataToggle = 0;
2208 }
2209
2210 /**
2211 Set EndPoint Number the TD is targeting at.
2212
2213 @param PtrTDStruct Place to store TD_STRUCT pointer.
2214 @param EndPoint The Endport number of the target.
2215
2216 **/
2217 VOID
2218 SetTDTokenEndPoint (
2219 IN TD_STRUCT *PtrTDStruct,
2220 IN UINTN EndPoint
2221 )
2222 {
2223 //
2224 // Set EndPoint Number the TD is targeting at.
2225 //
2226 PtrTDStruct->TDData.TDTokenEndPt = (UINT8) EndPoint;
2227 }
2228
2229 /**
2230 Set Device Address the TD is targeting at.
2231
2232 @param PtrTDStruct Place to store TD_STRUCT pointer.
2233 @param DevAddr The Device Address of the target.
2234
2235 **/
2236 VOID
2237 SetTDTokenDeviceAddress (
2238 IN TD_STRUCT *PtrTDStruct,
2239 IN UINTN DevAddr
2240 )
2241 {
2242 //
2243 // Set Device Address the TD is targeting at.
2244 //
2245 PtrTDStruct->TDData.TDTokenDevAddr = (UINT8) DevAddr;
2246 }
2247
2248 /**
2249 Set Packet Identification the TD is targeting at.
2250
2251 @param PtrTDStruct Place to store TD_STRUCT pointer.
2252 @param PacketID The Packet Identification of the target.
2253
2254 **/
2255 VOID
2256 SetTDTokenPacketID (
2257 IN TD_STRUCT *PtrTDStruct,
2258 IN UINT8 PacketID
2259 )
2260 {
2261 //
2262 // Set the Packet Identification to be used for this transaction.
2263 //
2264 PtrTDStruct->TDData.TDTokenPID = PacketID;
2265 }
2266
2267 /**
2268 Detect whether the TD is active.
2269
2270 @param PtrTDStruct Place to store TD_STRUCT pointer.
2271
2272 @retval The TD is active or not.
2273
2274 **/
2275 BOOLEAN
2276 IsTDStatusActive (
2277 IN TD_STRUCT *PtrTDStruct
2278 )
2279 {
2280 UINT8 TDStatus;
2281
2282 //
2283 // Detect whether the TD is active.
2284 //
2285 TDStatus = (UINT8) (PtrTDStruct->TDData.TDStatus);
2286 return (BOOLEAN) (TDStatus & 0x80);
2287 }
2288
2289 /**
2290 Detect whether the TD is stalled.
2291
2292 @param PtrTDStruct Place to store TD_STRUCT pointer.
2293
2294 @retval The TD is stalled or not.
2295
2296 **/
2297 BOOLEAN
2298 IsTDStatusStalled (
2299 IN TD_STRUCT *PtrTDStruct
2300 )
2301 {
2302 UINT8 TDStatus;
2303
2304 //
2305 // Detect whether the device/endpoint addressed by this TD is stalled.
2306 //
2307 TDStatus = (UINT8) (PtrTDStruct->TDData.TDStatus);
2308 return (BOOLEAN) (TDStatus & 0x40);
2309 }
2310
2311 /**
2312 Detect whether Data Buffer Error is happened.
2313
2314 @param PtrTDStruct Place to store TD_STRUCT pointer.
2315
2316 @retval The Data Buffer Error is happened or not.
2317
2318 **/
2319 BOOLEAN
2320 IsTDStatusBufferError (
2321 IN TD_STRUCT *PtrTDStruct
2322 )
2323 {
2324 UINT8 TDStatus;
2325
2326 //
2327 // Detect whether Data Buffer Error is happened.
2328 //
2329 TDStatus = (UINT8) (PtrTDStruct->TDData.TDStatus);
2330 return (BOOLEAN) (TDStatus & 0x20);
2331 }
2332
2333 /**
2334 Detect whether Babble Error is happened.
2335
2336 @param PtrTDStruct Place to store TD_STRUCT pointer.
2337
2338 @retval The Babble Error is happened or not.
2339
2340 **/
2341 BOOLEAN
2342 IsTDStatusBabbleError (
2343 IN TD_STRUCT *PtrTDStruct
2344 )
2345 {
2346 UINT8 TDStatus;
2347
2348 //
2349 // Detect whether Babble Error is happened.
2350 //
2351 TDStatus = (UINT8) (PtrTDStruct->TDData.TDStatus);
2352 return (BOOLEAN) (TDStatus & 0x10);
2353 }
2354
2355 /**
2356 Detect whether NAK is received.
2357
2358 @param PtrTDStruct Place to store TD_STRUCT pointer.
2359
2360 @retval The NAK is received or not.
2361
2362 **/
2363 BOOLEAN
2364 IsTDStatusNAKReceived (
2365 IN TD_STRUCT *PtrTDStruct
2366 )
2367 {
2368 UINT8 TDStatus;
2369
2370 //
2371 // Detect whether NAK is received.
2372 //
2373 TDStatus = (UINT8) (PtrTDStruct->TDData.TDStatus);
2374 return (BOOLEAN) (TDStatus & 0x08);
2375 }
2376
2377 /**
2378 Detect whether CRC/Time Out Error is encountered.
2379
2380 @param PtrTDStruct Place to store TD_STRUCT pointer.
2381
2382 @retval The CRC/Time Out Error is encountered or not.
2383
2384 **/
2385 BOOLEAN
2386 IsTDStatusCRCTimeOutError (
2387 IN TD_STRUCT *PtrTDStruct
2388 )
2389 {
2390 UINT8 TDStatus;
2391
2392 //
2393 // Detect whether CRC/Time Out Error is encountered.
2394 //
2395 TDStatus = (UINT8) (PtrTDStruct->TDData.TDStatus);
2396 return (BOOLEAN) (TDStatus & 0x04);
2397 }
2398
2399 /**
2400 Detect whether Bitstuff Error is received.
2401
2402 @param PtrTDStruct Place to store TD_STRUCT pointer.
2403
2404 @retval The Bitstuff Error is received or not.
2405
2406 **/
2407 BOOLEAN
2408 IsTDStatusBitStuffError (
2409 IN TD_STRUCT *PtrTDStruct
2410 )
2411 {
2412 UINT8 TDStatus;
2413
2414 //
2415 // Detect whether Bitstuff Error is received.
2416 //
2417 TDStatus = (UINT8) (PtrTDStruct->TDData.TDStatus);
2418 return (BOOLEAN) (TDStatus & 0x02);
2419 }
2420
2421 /**
2422 Retrieve the actual number of bytes that were tansferred.
2423
2424 @param PtrTDStruct Place to store TD_STRUCT pointer.
2425
2426 @retval The actual number of bytes that were tansferred.
2427
2428 **/
2429 UINT16
2430 GetTDStatusActualLength (
2431 IN TD_STRUCT *PtrTDStruct
2432 )
2433 {
2434 //
2435 // Retrieve the actual number of bytes that were tansferred.
2436 // the value is encoded as n-1. so return the decoded value.
2437 //
2438 return (UINT16) ((PtrTDStruct->TDData.TDStatusActualLength) + 1);
2439 }
2440
2441 /**
2442 Retrieve the information of whether the Link Pointer field is valid or not.
2443
2444 @param PtrTDStruct Place to store TD_STRUCT pointer.
2445
2446 @retval The linker pointer field is valid or not.
2447
2448 **/
2449 BOOLEAN
2450 GetTDLinkPtrValidorInvalid (
2451 IN TD_STRUCT *PtrTDStruct
2452 )
2453 {
2454 //
2455 // Retrieve the information of whether the Link Pointer field
2456 // is valid or not.
2457 //
2458 if ((PtrTDStruct->TDData.TDLinkPtrTerminate & BIT0) != 0) {
2459 return FALSE;
2460 } else {
2461 return TRUE;
2462 }
2463
2464 }
2465
2466 /**
2467 Count TD Number from PtrFirstTD.
2468
2469 @param PtrFirstTD Place to store TD_STRUCT pointer.
2470
2471 @retval The queued TDs number.
2472
2473 **/
2474 UINTN
2475 CountTDsNumber (
2476 IN TD_STRUCT *PtrFirstTD
2477 )
2478 {
2479 UINTN Number;
2480 TD_STRUCT *Ptr;
2481
2482 //
2483 // Count the queued TDs number.
2484 //
2485 Number = 0;
2486 Ptr = PtrFirstTD;
2487 while (Ptr != 0) {
2488 Ptr = (TD_STRUCT *) Ptr->PtrNextTD;
2489 Number++;
2490 }
2491
2492 return Number;
2493 }
2494
2495 /**
2496 Link TD To QH.
2497
2498 @param PtrQH Place to store QH_STRUCT pointer.
2499 @param PtrTD Place to store TD_STRUCT pointer.
2500
2501 **/
2502 VOID
2503 LinkTDToQH (
2504 IN QH_STRUCT *PtrQH,
2505 IN TD_STRUCT *PtrTD
2506 )
2507 {
2508 if (PtrQH == NULL || PtrTD == NULL) {
2509 return ;
2510 }
2511 //
2512 // Validate QH Vertical Ptr field
2513 //
2514 SetQHVerticalValidorInvalid (PtrQH, TRUE);
2515
2516 //
2517 // Vertical Ptr pointing to TD structure
2518 //
2519 SetQHVerticalQHorTDSelect (PtrQH, FALSE);
2520
2521 SetQHVerticalLinkPtr (PtrQH, (VOID *) PtrTD);
2522
2523 PtrQH->PtrDown = (VOID *) PtrTD;
2524 }
2525
2526 /**
2527 Link TD To TD.
2528
2529 @param PtrPreTD Place to store TD_STRUCT pointer.
2530 @param PtrTD Place to store TD_STRUCT pointer.
2531
2532 **/
2533 VOID
2534 LinkTDToTD (
2535 IN TD_STRUCT *PtrPreTD,
2536 IN TD_STRUCT *PtrTD
2537 )
2538 {
2539 if (PtrPreTD == NULL || PtrTD == NULL) {
2540 return ;
2541 }
2542 //
2543 // Depth first fashion
2544 //
2545 SetTDLinkPtrDepthorBreadth (PtrPreTD, TRUE);
2546
2547 //
2548 // Link pointer pointing to TD struct
2549 //
2550 SetTDLinkPtrQHorTDSelect (PtrPreTD, FALSE);
2551
2552 //
2553 // Validate the link pointer valid bit
2554 //
2555 SetTDLinkPtrValidorInvalid (PtrPreTD, TRUE);
2556
2557 SetTDLinkPtr (PtrPreTD, PtrTD);
2558
2559 PtrPreTD->PtrNextTD = (VOID *) PtrTD;
2560
2561 PtrTD->PtrNextTD = NULL;
2562 }
2563
2564 /**
2565 Execute Control Transfer.
2566
2567 @param UhcDev The UCHI device.
2568 @param PtrTD A pointer to TD_STRUCT data.
2569 @param ActualLen Actual transfer Length.
2570 @param TimeOut TimeOut value.
2571 @param TransferResult Transfer Result.
2572
2573 @return EFI_DEVICE_ERROR The transfer failed due to transfer error.
2574 @return EFI_TIMEOUT The transfer failed due to time out.
2575 @return EFI_SUCCESS The transfer finished OK.
2576
2577 **/
2578 EFI_STATUS
2579 ExecuteControlTransfer (
2580 IN USB_UHC_DEV *UhcDev,
2581 IN TD_STRUCT *PtrTD,
2582 OUT UINTN *ActualLen,
2583 IN UINTN TimeOut,
2584 OUT UINT32 *TransferResult
2585 )
2586 {
2587 UINTN ErrTDPos;
2588 UINTN Delay;
2589 BOOLEAN InfiniteLoop;
2590
2591 ErrTDPos = 0;
2592 *TransferResult = EFI_USB_NOERROR;
2593 *ActualLen = 0;
2594 InfiniteLoop = FALSE;
2595
2596 Delay = TimeOut * STALL_1_MILLI_SECOND;
2597 //
2598 // If Timeout is 0, then the caller must wait for the function to be completed
2599 // until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
2600 //
2601 if (TimeOut == 0) {
2602 InfiniteLoop = TRUE;
2603 }
2604
2605 do {
2606
2607 CheckTDsResults (PtrTD, TransferResult, &ErrTDPos, ActualLen);
2608
2609 //
2610 // TD is inactive, means the control transfer is end.
2611 //
2612 if ((*TransferResult & EFI_USB_ERR_NOTEXECUTE) != EFI_USB_ERR_NOTEXECUTE) {
2613 break;
2614 }
2615 MicroSecondDelay (STALL_1_MICRO_SECOND);
2616 Delay--;
2617
2618 } while (InfiniteLoop || (Delay != 0));
2619
2620 if (*TransferResult != EFI_USB_NOERROR) {
2621 return EFI_DEVICE_ERROR;
2622 }
2623
2624 return EFI_SUCCESS;
2625 }
2626
2627 /**
2628 Execute Bulk Transfer.
2629
2630 @param UhcDev The UCHI device.
2631 @param PtrTD A pointer to TD_STRUCT data.
2632 @param ActualLen Actual transfer Length.
2633 @param DataToggle DataToggle value.
2634 @param TimeOut TimeOut value.
2635 @param TransferResult Transfer Result.
2636
2637 @return EFI_DEVICE_ERROR The transfer failed due to transfer error.
2638 @return EFI_TIMEOUT The transfer failed due to time out.
2639 @return EFI_SUCCESS The transfer finished OK.
2640
2641 **/
2642 EFI_STATUS
2643 ExecBulkTransfer (
2644 IN USB_UHC_DEV *UhcDev,
2645 IN TD_STRUCT *PtrTD,
2646 IN OUT UINTN *ActualLen,
2647 IN UINT8 *DataToggle,
2648 IN UINTN TimeOut,
2649 OUT UINT32 *TransferResult
2650 )
2651 {
2652 UINTN ErrTDPos;
2653 UINTN ScrollNum;
2654 UINTN Delay;
2655 BOOLEAN InfiniteLoop;
2656
2657 ErrTDPos = 0;
2658 *TransferResult = EFI_USB_NOERROR;
2659 *ActualLen = 0;
2660 InfiniteLoop = FALSE;
2661
2662 Delay = TimeOut * STALL_1_MILLI_SECOND;
2663 //
2664 // If Timeout is 0, then the caller must wait for the function to be completed
2665 // until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
2666 //
2667 if (TimeOut == 0) {
2668 InfiniteLoop = TRUE;
2669 }
2670
2671 do {
2672
2673 CheckTDsResults (PtrTD, TransferResult, &ErrTDPos, ActualLen);
2674 //
2675 // TD is inactive, thus meaning bulk transfer's end.
2676 //
2677 if ((*TransferResult & EFI_USB_ERR_NOTEXECUTE) != EFI_USB_ERR_NOTEXECUTE) {
2678 break;
2679 }
2680 MicroSecondDelay (STALL_1_MICRO_SECOND);
2681 Delay--;
2682
2683 } while (InfiniteLoop || (Delay != 0));
2684
2685 //
2686 // has error
2687 //
2688 if (*TransferResult != EFI_USB_NOERROR) {
2689 //
2690 // scroll the Data Toggle back to the last success TD
2691 //
2692 ScrollNum = CountTDsNumber (PtrTD) - ErrTDPos;
2693 if ((ScrollNum % 2) != 0) {
2694 *DataToggle ^= 1;
2695 }
2696
2697 //
2698 // If error, wait 100ms to retry by upper layer
2699 //
2700 MicroSecondDelay (100 * 1000);
2701 return EFI_DEVICE_ERROR;
2702 }
2703
2704 return EFI_SUCCESS;
2705 }
2706
2707 /**
2708 Delete Queued TDs.
2709
2710 @param UhcDev The UCHI device.
2711 @param PtrFirstTD Place to store TD_STRUCT pointer.
2712
2713 **/
2714 VOID
2715 DeleteQueuedTDs (
2716 IN USB_UHC_DEV *UhcDev,
2717 IN TD_STRUCT *PtrFirstTD
2718 )
2719 {
2720 TD_STRUCT *Tptr1;
2721
2722 TD_STRUCT *Tptr2;
2723
2724 Tptr1 = PtrFirstTD;
2725 //
2726 // Delete all the TDs in a queue.
2727 //
2728 while (Tptr1 != NULL) {
2729
2730 Tptr2 = Tptr1;
2731
2732 if (!GetTDLinkPtrValidorInvalid (Tptr2)) {
2733 Tptr1 = NULL;
2734 } else {
2735 //
2736 // has more than one TD in the queue.
2737 //
2738 Tptr1 = GetTDLinkPtr (Tptr2);
2739 }
2740
2741 UhcFreePool (UhcDev, (UINT8 *) Tptr2, sizeof (TD_STRUCT));
2742 }
2743
2744 return ;
2745 }
2746
2747 /**
2748 Check TDs Results.
2749
2750 @param PtrTD A pointer to TD_STRUCT data.
2751 @param Result The result to return.
2752 @param ErrTDPos The Error TD position.
2753 @param ActualTransferSize Actual transfer size.
2754
2755 @retval The TD is executed successfully or not.
2756
2757 **/
2758 BOOLEAN
2759 CheckTDsResults (
2760 IN TD_STRUCT *PtrTD,
2761 OUT UINT32 *Result,
2762 OUT UINTN *ErrTDPos,
2763 OUT UINTN *ActualTransferSize
2764 )
2765 {
2766 UINTN Len;
2767
2768 *Result = EFI_USB_NOERROR;
2769 *ErrTDPos = 0;
2770
2771 //
2772 // Init to zero.
2773 //
2774 *ActualTransferSize = 0;
2775
2776 while (PtrTD != NULL) {
2777
2778 if (IsTDStatusActive (PtrTD)) {
2779 *Result |= EFI_USB_ERR_NOTEXECUTE;
2780 }
2781
2782 if (IsTDStatusStalled (PtrTD)) {
2783 *Result |= EFI_USB_ERR_STALL;
2784 }
2785
2786 if (IsTDStatusBufferError (PtrTD)) {
2787 *Result |= EFI_USB_ERR_BUFFER;
2788 }
2789
2790 if (IsTDStatusBabbleError (PtrTD)) {
2791 *Result |= EFI_USB_ERR_BABBLE;
2792 }
2793
2794 if (IsTDStatusNAKReceived (PtrTD)) {
2795 *Result |= EFI_USB_ERR_NAK;
2796 }
2797
2798 if (IsTDStatusCRCTimeOutError (PtrTD)) {
2799 *Result |= EFI_USB_ERR_TIMEOUT;
2800 }
2801
2802 if (IsTDStatusBitStuffError (PtrTD)) {
2803 *Result |= EFI_USB_ERR_BITSTUFF;
2804 }
2805 //
2806 // Accumulate actual transferred data length in each TD.
2807 //
2808 Len = GetTDStatusActualLength (PtrTD) & 0x7FF;
2809 *ActualTransferSize += Len;
2810
2811 //
2812 // if any error encountered, stop processing the left TDs.
2813 //
2814 if ((*Result) != 0) {
2815 return FALSE;
2816 }
2817
2818 PtrTD = (TD_STRUCT *) (PtrTD->PtrNextTD);
2819 //
2820 // Record the first Error TD's position in the queue,
2821 // this value is zero-based.
2822 //
2823 (*ErrTDPos)++;
2824 }
2825
2826 return TRUE;
2827 }
2828
2829 /**
2830 Create Memory Block.
2831
2832 @param UhcDev The UCHI device.
2833 @param MemoryHeader The Pointer to allocated memory block.
2834 @param MemoryBlockSizeInPages The page size of memory block to be allocated.
2835
2836 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
2837 @retval EFI_SUCCESS Success.
2838
2839 **/
2840 EFI_STATUS
2841 CreateMemoryBlock (
2842 IN USB_UHC_DEV *UhcDev,
2843 OUT MEMORY_MANAGE_HEADER **MemoryHeader,
2844 IN UINTN MemoryBlockSizeInPages
2845 )
2846 {
2847 EFI_STATUS Status;
2848 UINT8 *TempPtr;
2849 UINTN MemPages;
2850 UINT8 *Ptr;
2851 VOID *Mapping;
2852 EFI_PHYSICAL_ADDRESS MappedAddr;
2853
2854 //
2855 // Memory Block uses MemoryBlockSizeInPages pages,
2856 // memory management header and bit array use 1 page
2857 //
2858 MemPages = MemoryBlockSizeInPages + 1;
2859 Status = IoMmuAllocateBuffer (
2860 UhcDev->IoMmu,
2861 MemPages,
2862 (VOID **) &TempPtr,
2863 &MappedAddr,
2864 &Mapping
2865 );
2866 if (EFI_ERROR (Status) || (TempPtr == NULL)) {
2867 return EFI_OUT_OF_RESOURCES;
2868 }
2869
2870 Ptr = TempPtr;
2871
2872 ZeroMem (Ptr, MemPages * EFI_PAGE_SIZE);
2873
2874 *MemoryHeader = (MEMORY_MANAGE_HEADER *) Ptr;
2875 //
2876 // adjust Ptr pointer to the next empty memory
2877 //
2878 Ptr += sizeof (MEMORY_MANAGE_HEADER);
2879 //
2880 // Set Bit Array initial address
2881 //
2882 (*MemoryHeader)->BitArrayPtr = Ptr;
2883
2884 (*MemoryHeader)->Next = NULL;
2885
2886 //
2887 // Memory block initial address
2888 //
2889 Ptr = TempPtr;
2890 Ptr += EFI_PAGE_SIZE;
2891 (*MemoryHeader)->MemoryBlockPtr = Ptr;
2892 //
2893 // set Memory block size
2894 //
2895 (*MemoryHeader)->MemoryBlockSizeInBytes = MemoryBlockSizeInPages * EFI_PAGE_SIZE;
2896 //
2897 // each bit in Bit Array will manage 32byte memory in memory block
2898 //
2899 (*MemoryHeader)->BitArraySizeInBytes = ((*MemoryHeader)->MemoryBlockSizeInBytes / 32) / 8;
2900
2901 return EFI_SUCCESS;
2902 }
2903
2904 /**
2905 Initialize UHCI memory management.
2906
2907 @param UhcDev The UCHI device.
2908
2909 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
2910 @retval EFI_SUCCESS Success.
2911
2912 **/
2913 EFI_STATUS
2914 InitializeMemoryManagement (
2915 IN USB_UHC_DEV *UhcDev
2916 )
2917 {
2918 MEMORY_MANAGE_HEADER *MemoryHeader;
2919 EFI_STATUS Status;
2920 UINTN MemPages;
2921
2922 MemPages = NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES;
2923 Status = CreateMemoryBlock (UhcDev, &MemoryHeader, MemPages);
2924 if (EFI_ERROR (Status)) {
2925 return Status;
2926 }
2927
2928 UhcDev->Header1 = MemoryHeader;
2929
2930 return EFI_SUCCESS;
2931 }
2932
2933 /**
2934 Initialize UHCI memory management.
2935
2936 @param UhcDev The UCHI device.
2937 @param Pool Buffer pointer to store the buffer pointer.
2938 @param AllocSize 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 UhcAllocatePool (
2946 IN USB_UHC_DEV *UhcDev,
2947 OUT UINT8 **Pool,
2948 IN UINTN AllocSize
2949 )
2950 {
2951 MEMORY_MANAGE_HEADER *MemoryHeader;
2952 MEMORY_MANAGE_HEADER *TempHeaderPtr;
2953 MEMORY_MANAGE_HEADER *NewMemoryHeader;
2954 UINTN RealAllocSize;
2955 UINTN MemoryBlockSizeInPages;
2956 EFI_STATUS Status;
2957
2958 *Pool = NULL;
2959
2960 MemoryHeader = UhcDev->Header1;
2961
2962 //
2963 // allocate unit is 32 byte (align on 32 byte)
2964 //
2965 if ((AllocSize & 0x1F) != 0) {
2966 RealAllocSize = (AllocSize / 32 + 1) * 32;
2967 } else {
2968 RealAllocSize = AllocSize;
2969 }
2970
2971 Status = EFI_NOT_FOUND;
2972 for (TempHeaderPtr = MemoryHeader; TempHeaderPtr != NULL; TempHeaderPtr = TempHeaderPtr->Next) {
2973
2974 Status = AllocMemInMemoryBlock (
2975 TempHeaderPtr,
2976 (VOID **) Pool,
2977 RealAllocSize / 32
2978 );
2979 if (!EFI_ERROR (Status)) {
2980 return EFI_SUCCESS;
2981 }
2982 }
2983 //
2984 // There is no enough memory,
2985 // Create a new Memory Block
2986 //
2987 //
2988 // if pool size is larger than NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES,
2989 // just allocate a large enough memory block.
2990 //
2991 if (RealAllocSize > (NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES * EFI_PAGE_SIZE)) {
2992 MemoryBlockSizeInPages = RealAllocSize / EFI_PAGE_SIZE + 1;
2993 } else {
2994 MemoryBlockSizeInPages = NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES;
2995 }
2996
2997 Status = CreateMemoryBlock (UhcDev, &NewMemoryHeader, MemoryBlockSizeInPages);
2998 if (EFI_ERROR (Status)) {
2999 return Status;
3000 }
3001 //
3002 // Link the new Memory Block to the Memory Header list
3003 //
3004 InsertMemoryHeaderToList (MemoryHeader, NewMemoryHeader);
3005
3006 Status = AllocMemInMemoryBlock (
3007 NewMemoryHeader,
3008 (VOID **) Pool,
3009 RealAllocSize / 32
3010 );
3011 return Status;
3012 }
3013
3014 /**
3015 Alloc Memory In MemoryBlock.
3016
3017 @param MemoryHeader The pointer to memory manage header.
3018 @param Pool Buffer pointer to store the buffer pointer.
3019 @param NumberOfMemoryUnit The size of the pool to be allocated.
3020
3021 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
3022 @retval EFI_SUCCESS Success.
3023
3024 **/
3025 EFI_STATUS
3026 AllocMemInMemoryBlock (
3027 IN MEMORY_MANAGE_HEADER *MemoryHeader,
3028 OUT VOID **Pool,
3029 IN UINTN NumberOfMemoryUnit
3030 )
3031 {
3032 UINTN TempBytePos;
3033 UINTN FoundBytePos;
3034 UINT8 Index;
3035 UINT8 FoundBitPos;
3036 UINT8 ByteValue;
3037 UINT8 BitValue;
3038 UINTN NumberOfZeros;
3039 UINTN Count;
3040
3041 FoundBytePos = 0;
3042 FoundBitPos = 0;
3043
3044 ByteValue = MemoryHeader->BitArrayPtr[0];
3045 NumberOfZeros = 0;
3046 Index = 0;
3047 for (TempBytePos = 0; TempBytePos < MemoryHeader->BitArraySizeInBytes;) {
3048 //
3049 // Pop out BitValue from a byte in TempBytePos.
3050 //
3051 BitValue = (UINT8)(ByteValue & 0x1);
3052
3053 if (BitValue == 0) {
3054 //
3055 // Found a free bit, the NumberOfZeros only record the number of those consecutive zeros
3056 //
3057 NumberOfZeros++;
3058 //
3059 // Found enough consecutive free space, break the loop
3060 //
3061 if (NumberOfZeros >= NumberOfMemoryUnit) {
3062 break;
3063 }
3064 } else {
3065 //
3066 // Encountering a '1', meant the bit is ocupied.
3067 //
3068 if (NumberOfZeros >= NumberOfMemoryUnit) {
3069 //
3070 // Found enough consecutive free space,break the loop
3071 //
3072 break;
3073 } else {
3074 //
3075 // the NumberOfZeros only record the number of those consecutive zeros,
3076 // so reset the NumberOfZeros to 0 when encountering '1' before finding
3077 // enough consecutive '0's
3078 //
3079 NumberOfZeros = 0;
3080 //
3081 // reset the (FoundBytePos,FoundBitPos) to the position of '1'
3082 //
3083 FoundBytePos = TempBytePos;
3084 FoundBitPos = Index;
3085 }
3086 }
3087 //
3088 // right shift the byte
3089 //
3090 ByteValue /= 2;
3091
3092 //
3093 // step forward a bit
3094 //
3095 Index++;
3096 if (Index == 8) {
3097 //
3098 // step forward a byte, getting the byte value,
3099 // and reset the bit pos.
3100 //
3101 TempBytePos += 1;
3102 ByteValue = MemoryHeader->BitArrayPtr[TempBytePos];
3103 Index = 0;
3104 }
3105 }
3106
3107 if (NumberOfZeros < NumberOfMemoryUnit) {
3108 return EFI_NOT_FOUND;
3109 }
3110 //
3111 // Found enough free space.
3112 //
3113 //
3114 // The values recorded in (FoundBytePos,FoundBitPos) have two conditions:
3115 // 1)(FoundBytePos,FoundBitPos) record the position
3116 // of the last '1' before the consecutive '0's, it must
3117 // be adjusted to the start position of the consecutive '0's.
3118 // 2)the start address of the consecutive '0's is just the start of
3119 // the bitarray. so no need to adjust the values of (FoundBytePos,FoundBitPos).
3120 //
3121 if ((MemoryHeader->BitArrayPtr[0] & BIT0) != 0) {
3122 FoundBitPos += 1;
3123 }
3124 //
3125 // Have the (FoundBytePos,FoundBitPos) make sense.
3126 //
3127 if (FoundBitPos > 7) {
3128 FoundBytePos += 1;
3129 FoundBitPos -= 8;
3130 }
3131 //
3132 // Set the memory as allocated
3133 //
3134 for (TempBytePos = FoundBytePos, Index = FoundBitPos, Count = 0; Count < NumberOfMemoryUnit; Count++) {
3135
3136 MemoryHeader->BitArrayPtr[TempBytePos] = (UINT8) (MemoryHeader->BitArrayPtr[TempBytePos] | (1 << Index));
3137 Index++;
3138 if (Index == 8) {
3139 TempBytePos += 1;
3140 Index = 0;
3141 }
3142 }
3143
3144 *Pool = MemoryHeader->MemoryBlockPtr + (FoundBytePos * 8 + FoundBitPos) * 32;
3145
3146 return EFI_SUCCESS;
3147 }
3148
3149 /**
3150 Uhci Free Pool.
3151
3152 @param UhcDev The UHCI device.
3153 @param Pool A pointer to store the buffer address.
3154 @param AllocSize The size of the pool to be freed.
3155
3156 **/
3157 VOID
3158 UhcFreePool (
3159 IN USB_UHC_DEV *UhcDev,
3160 IN UINT8 *Pool,
3161 IN UINTN AllocSize
3162 )
3163 {
3164 MEMORY_MANAGE_HEADER *MemoryHeader;
3165 MEMORY_MANAGE_HEADER *TempHeaderPtr;
3166 UINTN StartBytePos;
3167 UINTN Index;
3168 UINT8 StartBitPos;
3169 UINT8 Index2;
3170 UINTN Count;
3171 UINTN RealAllocSize;
3172
3173 MemoryHeader = UhcDev->Header1;
3174
3175 //
3176 // allocate unit is 32 byte (align on 32 byte)
3177 //
3178 if ((AllocSize & 0x1F) != 0) {
3179 RealAllocSize = (AllocSize / 32 + 1) * 32;
3180 } else {
3181 RealAllocSize = AllocSize;
3182 }
3183
3184 for (TempHeaderPtr = MemoryHeader; TempHeaderPtr != NULL;
3185 TempHeaderPtr = TempHeaderPtr->Next) {
3186
3187 if ((Pool >= TempHeaderPtr->MemoryBlockPtr) &&
3188 ((Pool + RealAllocSize) <= (TempHeaderPtr->MemoryBlockPtr +
3189 TempHeaderPtr->MemoryBlockSizeInBytes))) {
3190
3191 //
3192 // Pool is in the Memory Block area,
3193 // find the start byte and bit in the bit array
3194 //
3195 StartBytePos = ((Pool - TempHeaderPtr->MemoryBlockPtr) / 32) / 8;
3196 StartBitPos = (UINT8) (((Pool - TempHeaderPtr->MemoryBlockPtr) / 32) % 8);
3197
3198 //
3199 // reset associated bits in bit array
3200 //
3201 for (Index = StartBytePos, Index2 = StartBitPos, Count = 0; Count < (RealAllocSize / 32); Count++) {
3202
3203 TempHeaderPtr->BitArrayPtr[Index] = (UINT8) (TempHeaderPtr->BitArrayPtr[Index] ^ (1 << Index2));
3204 Index2++;
3205 if (Index2 == 8) {
3206 Index += 1;
3207 Index2 = 0;
3208 }
3209 }
3210 //
3211 // break the loop
3212 //
3213 break;
3214 }
3215 }
3216
3217 }
3218
3219 /**
3220 Insert a new memory header into list.
3221
3222 @param MemoryHeader A pointer to the memory header list.
3223 @param NewMemoryHeader A new memory header to be inserted into the list.
3224
3225 **/
3226 VOID
3227 InsertMemoryHeaderToList (
3228 IN MEMORY_MANAGE_HEADER *MemoryHeader,
3229 IN MEMORY_MANAGE_HEADER *NewMemoryHeader
3230 )
3231 {
3232 MEMORY_MANAGE_HEADER *TempHeaderPtr;
3233
3234 for (TempHeaderPtr = MemoryHeader; TempHeaderPtr != NULL; TempHeaderPtr = TempHeaderPtr->Next) {
3235 if (TempHeaderPtr->Next == NULL) {
3236 TempHeaderPtr->Next = NewMemoryHeader;
3237 break;
3238 }
3239 }
3240 }
3241
3242 /**
3243 Judge the memory block in the memory header is empty or not.
3244
3245 @param MemoryHeaderPtr A pointer to the memory header list.
3246
3247 @retval Whether the memory block in the memory header is empty or not.
3248
3249 **/
3250 BOOLEAN
3251 IsMemoryBlockEmptied (
3252 IN MEMORY_MANAGE_HEADER *MemoryHeaderPtr
3253 )
3254 {
3255 UINTN Index;
3256
3257 for (Index = 0; Index < MemoryHeaderPtr->BitArraySizeInBytes; Index++) {
3258 if (MemoryHeaderPtr->BitArrayPtr[Index] != 0) {
3259 return FALSE;
3260 }
3261 }
3262
3263 return TRUE;
3264 }
3265
3266 /**
3267 remove a memory header from list.
3268
3269 @param FirstMemoryHeader A pointer to the memory header list.
3270 @param FreeMemoryHeader A memory header to be removed into the list.
3271
3272 **/
3273 VOID
3274 DelinkMemoryBlock (
3275 IN MEMORY_MANAGE_HEADER *FirstMemoryHeader,
3276 IN MEMORY_MANAGE_HEADER *FreeMemoryHeader
3277 )
3278 {
3279 MEMORY_MANAGE_HEADER *TempHeaderPtr;
3280
3281 if ((FirstMemoryHeader == NULL) || (FreeMemoryHeader == NULL)) {
3282 return ;
3283 }
3284
3285 for (TempHeaderPtr = FirstMemoryHeader; TempHeaderPtr != NULL; TempHeaderPtr = TempHeaderPtr->Next) {
3286
3287 if (TempHeaderPtr->Next == FreeMemoryHeader) {
3288 //
3289 // Link the before and after
3290 //
3291 TempHeaderPtr->Next = FreeMemoryHeader->Next;
3292 break;
3293 }
3294 }
3295 }
3296
3297 /**
3298 Map address of request structure buffer.
3299
3300 @param Uhc The UHCI device.
3301 @param Request The user request buffer.
3302 @param MappedAddr Mapped address of request.
3303 @param Map Identificaion of this mapping to return.
3304
3305 @return EFI_SUCCESS Success.
3306 @return EFI_DEVICE_ERROR Fail to map the user request.
3307
3308 **/
3309 EFI_STATUS
3310 UhciMapUserRequest (
3311 IN USB_UHC_DEV *Uhc,
3312 IN OUT VOID *Request,
3313 OUT UINT8 **MappedAddr,
3314 OUT VOID **Map
3315 )
3316 {
3317 EFI_STATUS Status;
3318 UINTN Len;
3319 EFI_PHYSICAL_ADDRESS PhyAddr;
3320
3321 Len = sizeof (EFI_USB_DEVICE_REQUEST);
3322 Status = IoMmuMap (
3323 Uhc->IoMmu,
3324 EdkiiIoMmuOperationBusMasterRead,
3325 Request,
3326 &Len,
3327 &PhyAddr,
3328 Map
3329 );
3330
3331 if (!EFI_ERROR (Status)) {
3332 *MappedAddr = (UINT8 *) (UINTN) PhyAddr;
3333 }
3334
3335 return Status;
3336 }
3337
3338 /**
3339 Map address of user data buffer.
3340
3341 @param Uhc The UHCI device.
3342 @param Direction Direction of the data transfer.
3343 @param Data The user data buffer.
3344 @param Len Length of the user data.
3345 @param PktId Packet identificaion.
3346 @param MappedAddr Mapped address to return.
3347 @param Map Identificaion of this mapping to return.
3348
3349 @return EFI_SUCCESS Success.
3350 @return EFI_DEVICE_ERROR Fail to map the user data.
3351
3352 **/
3353 EFI_STATUS
3354 UhciMapUserData (
3355 IN USB_UHC_DEV *Uhc,
3356 IN EFI_USB_DATA_DIRECTION Direction,
3357 IN VOID *Data,
3358 IN OUT UINTN *Len,
3359 OUT UINT8 *PktId,
3360 OUT UINT8 **MappedAddr,
3361 OUT VOID **Map
3362 )
3363 {
3364 EFI_STATUS Status;
3365 EFI_PHYSICAL_ADDRESS PhyAddr;
3366
3367 Status = EFI_SUCCESS;
3368
3369 switch (Direction) {
3370 case EfiUsbDataIn:
3371 //
3372 // BusMasterWrite means cpu read
3373 //
3374 *PktId = INPUT_PACKET_ID;
3375 Status = IoMmuMap (
3376 Uhc->IoMmu,
3377 EdkiiIoMmuOperationBusMasterWrite,
3378 Data,
3379 Len,
3380 &PhyAddr,
3381 Map
3382 );
3383
3384 if (EFI_ERROR (Status)) {
3385 goto EXIT;
3386 }
3387
3388 *MappedAddr = (UINT8 *) (UINTN) PhyAddr;
3389 break;
3390
3391 case EfiUsbDataOut:
3392 *PktId = OUTPUT_PACKET_ID;
3393 Status = IoMmuMap (
3394 Uhc->IoMmu,
3395 EdkiiIoMmuOperationBusMasterRead,
3396 Data,
3397 Len,
3398 &PhyAddr,
3399 Map
3400 );
3401
3402 if (EFI_ERROR (Status)) {
3403 goto EXIT;
3404 }
3405
3406 *MappedAddr = (UINT8 *) (UINTN) PhyAddr;
3407 break;
3408
3409 case EfiUsbNoData:
3410 if ((Len != NULL) && (*Len != 0)) {
3411 Status = EFI_INVALID_PARAMETER;
3412 goto EXIT;
3413 }
3414
3415 *PktId = OUTPUT_PACKET_ID;
3416 *MappedAddr = NULL;
3417 *Map = NULL;
3418 break;
3419
3420 default:
3421 Status = EFI_INVALID_PARAMETER;
3422 }
3423
3424 EXIT:
3425 return Status;
3426 }
3427