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