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