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