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