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