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