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