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