]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/XhciDxe/Xhci.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / XhciDxe / Xhci.c
CommitLineData
4b738c76
HT
1/** @file\r
2 The XHCI controller driver.\r
3\r
b97243de 4Copyright (c) 2011 - 2022, Intel Corporation. All rights reserved.<BR>\r
9d510e61 5SPDX-License-Identifier: BSD-2-Clause-Patent\r
4b738c76
HT
6\r
7**/\r
8\r
9#include "Xhci.h"\r
10\r
11//\r
12// Two arrays used to translate the XHCI port state (change)\r
13// to the UEFI protocol's port state (change).\r
14//\r
15USB_PORT_STATE_MAP mUsbPortStateMap[] = {\r
1436aea4
MK
16 { XHC_PORTSC_CCS, USB_PORT_STAT_CONNECTION },\r
17 { XHC_PORTSC_PED, USB_PORT_STAT_ENABLE },\r
18 { XHC_PORTSC_OCA, USB_PORT_STAT_OVERCURRENT },\r
19 { XHC_PORTSC_RESET, USB_PORT_STAT_RESET }\r
4b738c76
HT
20};\r
21\r
22USB_PORT_STATE_MAP mUsbPortChangeMap[] = {\r
1436aea4
MK
23 { XHC_PORTSC_CSC, USB_PORT_STAT_C_CONNECTION },\r
24 { XHC_PORTSC_PEC, USB_PORT_STAT_C_ENABLE },\r
25 { XHC_PORTSC_OCC, USB_PORT_STAT_C_OVERCURRENT },\r
26 { XHC_PORTSC_PRC, USB_PORT_STAT_C_RESET }\r
4b738c76
HT
27};\r
28\r
1436aea4
MK
29USB_CLEAR_PORT_MAP mUsbClearPortChangeMap[] = {\r
30 { XHC_PORTSC_CSC, EfiUsbPortConnectChange },\r
31 { XHC_PORTSC_PEC, EfiUsbPortEnableChange },\r
32 { XHC_PORTSC_OCC, EfiUsbPortOverCurrentChange },\r
33 { XHC_PORTSC_PRC, EfiUsbPortResetChange }\r
4b738c76
HT
34};\r
35\r
36USB_PORT_STATE_MAP mUsbHubPortStateMap[] = {\r
1436aea4
MK
37 { XHC_HUB_PORTSC_CCS, USB_PORT_STAT_CONNECTION },\r
38 { XHC_HUB_PORTSC_PED, USB_PORT_STAT_ENABLE },\r
39 { XHC_HUB_PORTSC_OCA, USB_PORT_STAT_OVERCURRENT },\r
40 { XHC_HUB_PORTSC_RESET, USB_PORT_STAT_RESET }\r
4b738c76
HT
41};\r
42\r
43USB_PORT_STATE_MAP mUsbHubPortChangeMap[] = {\r
1436aea4
MK
44 { XHC_HUB_PORTSC_CSC, USB_PORT_STAT_C_CONNECTION },\r
45 { XHC_HUB_PORTSC_PEC, USB_PORT_STAT_C_ENABLE },\r
46 { XHC_HUB_PORTSC_OCC, USB_PORT_STAT_C_OVERCURRENT },\r
47 { XHC_HUB_PORTSC_PRC, USB_PORT_STAT_C_RESET }\r
4b738c76
HT
48};\r
49\r
1436aea4
MK
50USB_CLEAR_PORT_MAP mUsbHubClearPortChangeMap[] = {\r
51 { XHC_HUB_PORTSC_CSC, EfiUsbPortConnectChange },\r
52 { XHC_HUB_PORTSC_PEC, EfiUsbPortEnableChange },\r
53 { XHC_HUB_PORTSC_OCC, EfiUsbPortOverCurrentChange },\r
54 { XHC_HUB_PORTSC_PRC, EfiUsbPortResetChange },\r
55 { XHC_HUB_PORTSC_BHRC, Usb3PortBHPortResetChange }\r
4b738c76
HT
56};\r
57\r
58EFI_DRIVER_BINDING_PROTOCOL gXhciDriverBinding = {\r
59 XhcDriverBindingSupported,\r
60 XhcDriverBindingStart,\r
61 XhcDriverBindingStop,\r
62 0x30,\r
63 NULL,\r
64 NULL\r
65};\r
66\r
67//\r
68// Template for Xhci's Usb2 Host Controller Protocol Instance.\r
69//\r
1436aea4 70EFI_USB2_HC_PROTOCOL gXhciUsb2HcTemplate = {\r
4b738c76
HT
71 XhcGetCapability,\r
72 XhcReset,\r
73 XhcGetState,\r
74 XhcSetState,\r
75 XhcControlTransfer,\r
76 XhcBulkTransfer,\r
77 XhcAsyncInterruptTransfer,\r
78 XhcSyncInterruptTransfer,\r
79 XhcIsochronousTransfer,\r
80 XhcAsyncIsochronousTransfer,\r
81 XhcGetRootHubPortStatus,\r
82 XhcSetRootHubPortFeature,\r
83 XhcClearRootHubPortFeature,\r
84 0x3,\r
85 0x0\r
86};\r
87\r
88/**\r
89 Retrieves the capability of root hub ports.\r
90\r
91 @param This The EFI_USB2_HC_PROTOCOL instance.\r
92 @param MaxSpeed Max speed supported by the controller.\r
93 @param PortNumber Number of the root hub ports.\r
94 @param Is64BitCapable Whether the controller supports 64-bit memory\r
95 addressing.\r
96\r
97 @retval EFI_SUCCESS Host controller capability were retrieved successfully.\r
98 @retval EFI_INVALID_PARAMETER Either of the three capability pointer is NULL.\r
99\r
100**/\r
101EFI_STATUS\r
102EFIAPI\r
103XhcGetCapability (\r
104 IN EFI_USB2_HC_PROTOCOL *This,\r
105 OUT UINT8 *MaxSpeed,\r
106 OUT UINT8 *PortNumber,\r
107 OUT UINT8 *Is64BitCapable\r
108 )\r
109{\r
110 USB_XHCI_INSTANCE *Xhc;\r
111 EFI_TPL OldTpl;\r
112\r
113 if ((MaxSpeed == NULL) || (PortNumber == NULL) || (Is64BitCapable == NULL)) {\r
114 return EFI_INVALID_PARAMETER;\r
115 }\r
116\r
1436aea4 117 OldTpl = gBS->RaiseTPL (XHC_TPL);\r
4b738c76
HT
118\r
119 Xhc = XHC_FROM_THIS (This);\r
120 *MaxSpeed = EFI_USB_SPEED_SUPER;\r
1436aea4
MK
121 *PortNumber = (UINT8)(Xhc->HcSParams1.Data.MaxPorts);\r
122 *Is64BitCapable = (UINT8)Xhc->Support64BitDma;\r
87000d77 123 DEBUG ((DEBUG_INFO, "XhcGetCapability: %d ports, 64 bit %d\n", *PortNumber, *Is64BitCapable));\r
4b738c76
HT
124\r
125 gBS->RestoreTPL (OldTpl);\r
126\r
127 return EFI_SUCCESS;\r
128}\r
129\r
4b738c76
HT
130/**\r
131 Provides software reset for the USB host controller.\r
132\r
133 @param This This EFI_USB2_HC_PROTOCOL instance.\r
134 @param Attributes A bit mask of the reset operation to perform.\r
135\r
136 @retval EFI_SUCCESS The reset operation succeeded.\r
137 @retval EFI_INVALID_PARAMETER Attributes is not valid.\r
138 @retval EFI_UNSUPPOURTED The type of reset specified by Attributes is\r
139 not currently supported by the host controller.\r
140 @retval EFI_DEVICE_ERROR Host controller isn't halted to reset.\r
141\r
142**/\r
143EFI_STATUS\r
144EFIAPI\r
145XhcReset (\r
146 IN EFI_USB2_HC_PROTOCOL *This,\r
147 IN UINT16 Attributes\r
148 )\r
149{\r
150 USB_XHCI_INSTANCE *Xhc;\r
151 EFI_STATUS Status;\r
152 EFI_TPL OldTpl;\r
153\r
154 Xhc = XHC_FROM_THIS (This);\r
d1102dba 155\r
4b738c76
HT
156 if (Xhc->DevicePath != NULL) {\r
157 //\r
158 // Report Status Code to indicate reset happens\r
159 //\r
160 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
161 EFI_PROGRESS_CODE,\r
162 (EFI_IO_BUS_USB | EFI_IOB_PC_RESET),\r
163 Xhc->DevicePath\r
164 );\r
d1102dba 165 }\r
4b738c76
HT
166\r
167 OldTpl = gBS->RaiseTPL (XHC_TPL);\r
168\r
169 switch (Attributes) {\r
1436aea4 170 case EFI_USB_HC_RESET_GLOBAL:\r
4b738c76 171 //\r
1436aea4 172 // Flow through, same behavior as Host Controller Reset\r
4b738c76 173 //\r
1436aea4
MK
174 case EFI_USB_HC_RESET_HOST_CONTROLLER:\r
175 if ((Xhc->DebugCapSupOffset != 0xFFFFFFFF) && ((XhcReadExtCapReg (Xhc, Xhc->DebugCapSupOffset) & 0xFF) == XHC_CAP_USB_DEBUG) &&\r
176 ((XhcReadExtCapReg (Xhc, Xhc->DebugCapSupOffset + XHC_DC_DCCTRL) & BIT0) != 0))\r
177 {\r
178 Status = EFI_SUCCESS;\r
179 goto ON_EXIT;\r
180 }\r
181\r
182 //\r
183 // Host Controller must be Halt when Reset it\r
184 //\r
185 if (!XhcIsHalt (Xhc)) {\r
186 Status = XhcHaltHC (Xhc, XHC_GENERIC_TIMEOUT);\r
187\r
188 if (EFI_ERROR (Status)) {\r
189 Status = EFI_DEVICE_ERROR;\r
190 goto ON_EXIT;\r
191 }\r
192 }\r
193\r
194 Status = XhcResetHC (Xhc, XHC_RESET_TIMEOUT);\r
195 ASSERT (!(XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_CNR)));\r
4b738c76
HT
196\r
197 if (EFI_ERROR (Status)) {\r
4b738c76
HT
198 goto ON_EXIT;\r
199 }\r
4b738c76 200\r
1436aea4
MK
201 //\r
202 // Clean up the asynchronous transfers, currently only\r
203 // interrupt supports asynchronous operation.\r
204 //\r
205 XhciDelAllAsyncIntTransfers (Xhc);\r
206 XhcFreeSched (Xhc);\r
4b738c76 207\r
1436aea4
MK
208 XhcInitSched (Xhc);\r
209 break;\r
4b738c76 210\r
1436aea4
MK
211 case EFI_USB_HC_RESET_GLOBAL_WITH_DEBUG:\r
212 case EFI_USB_HC_RESET_HOST_WITH_DEBUG:\r
213 Status = EFI_UNSUPPORTED;\r
214 break;\r
4b738c76 215\r
1436aea4
MK
216 default:\r
217 Status = EFI_INVALID_PARAMETER;\r
4b738c76
HT
218 }\r
219\r
220ON_EXIT:\r
87000d77 221 DEBUG ((DEBUG_INFO, "XhcReset: status %r\n", Status));\r
4b738c76
HT
222 gBS->RestoreTPL (OldTpl);\r
223\r
224 return Status;\r
225}\r
226\r
4b738c76
HT
227/**\r
228 Retrieve the current state of the USB host controller.\r
229\r
230 @param This This EFI_USB2_HC_PROTOCOL instance.\r
231 @param State Variable to return the current host controller\r
232 state.\r
233\r
234 @retval EFI_SUCCESS Host controller state was returned in State.\r
235 @retval EFI_INVALID_PARAMETER State is NULL.\r
236 @retval EFI_DEVICE_ERROR An error was encountered while attempting to\r
237 retrieve the host controller's current state.\r
238\r
239**/\r
240EFI_STATUS\r
241EFIAPI\r
242XhcGetState (\r
243 IN EFI_USB2_HC_PROTOCOL *This,\r
244 OUT EFI_USB_HC_STATE *State\r
245 )\r
246{\r
247 USB_XHCI_INSTANCE *Xhc;\r
248 EFI_TPL OldTpl;\r
249\r
250 if (State == NULL) {\r
251 return EFI_INVALID_PARAMETER;\r
252 }\r
253\r
254 OldTpl = gBS->RaiseTPL (XHC_TPL);\r
255\r
1436aea4 256 Xhc = XHC_FROM_THIS (This);\r
4b738c76
HT
257\r
258 if (XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT)) {\r
259 *State = EfiUsbHcStateHalt;\r
260 } else {\r
261 *State = EfiUsbHcStateOperational;\r
262 }\r
263\r
87000d77 264 DEBUG ((DEBUG_INFO, "XhcGetState: current state %d\n", *State));\r
4b738c76
HT
265 gBS->RestoreTPL (OldTpl);\r
266\r
267 return EFI_SUCCESS;\r
268}\r
269\r
270/**\r
271 Sets the USB host controller to a specific state.\r
272\r
273 @param This This EFI_USB2_HC_PROTOCOL instance.\r
274 @param State The state of the host controller that will be set.\r
275\r
276 @retval EFI_SUCCESS The USB host controller was successfully placed\r
277 in the state specified by State.\r
278 @retval EFI_INVALID_PARAMETER State is invalid.\r
279 @retval EFI_DEVICE_ERROR Failed to set the state due to device error.\r
280\r
281**/\r
282EFI_STATUS\r
283EFIAPI\r
284XhcSetState (\r
285 IN EFI_USB2_HC_PROTOCOL *This,\r
286 IN EFI_USB_HC_STATE State\r
287 )\r
288{\r
1436aea4
MK
289 USB_XHCI_INSTANCE *Xhc;\r
290 EFI_STATUS Status;\r
291 EFI_USB_HC_STATE CurState;\r
292 EFI_TPL OldTpl;\r
4b738c76
HT
293\r
294 Status = XhcGetState (This, &CurState);\r
295\r
296 if (EFI_ERROR (Status)) {\r
297 return EFI_DEVICE_ERROR;\r
298 }\r
299\r
300 if (CurState == State) {\r
301 return EFI_SUCCESS;\r
302 }\r
303\r
304 OldTpl = gBS->RaiseTPL (XHC_TPL);\r
305\r
1436aea4 306 Xhc = XHC_FROM_THIS (This);\r
4b738c76
HT
307\r
308 switch (State) {\r
1436aea4
MK
309 case EfiUsbHcStateHalt:\r
310 Status = XhcHaltHC (Xhc, XHC_GENERIC_TIMEOUT);\r
4b738c76 311 break;\r
4b738c76 312\r
1436aea4
MK
313 case EfiUsbHcStateOperational:\r
314 if (XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HSE)) {\r
315 Status = EFI_DEVICE_ERROR;\r
316 break;\r
317 }\r
4b738c76 318\r
1436aea4
MK
319 //\r
320 // Software must not write a one to this field unless the host controller\r
321 // is in the Halted state. Doing so will yield undefined results.\r
322 // refers to Spec[XHCI1.0-2.3.1]\r
323 //\r
324 if (!XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT)) {\r
325 Status = EFI_DEVICE_ERROR;\r
326 break;\r
327 }\r
4b738c76 328\r
1436aea4
MK
329 Status = XhcRunHC (Xhc, XHC_GENERIC_TIMEOUT);\r
330 break;\r
4b738c76 331\r
1436aea4
MK
332 case EfiUsbHcStateSuspend:\r
333 Status = EFI_UNSUPPORTED;\r
334 break;\r
335\r
336 default:\r
337 Status = EFI_INVALID_PARAMETER;\r
4b738c76
HT
338 }\r
339\r
87000d77 340 DEBUG ((DEBUG_INFO, "XhcSetState: status %r\n", Status));\r
4b738c76
HT
341 gBS->RestoreTPL (OldTpl);\r
342\r
343 return Status;\r
344}\r
345\r
346/**\r
347 Retrieves the current status of a USB root hub port.\r
348\r
349 @param This This EFI_USB2_HC_PROTOCOL instance.\r
350 @param PortNumber The root hub port to retrieve the state from.\r
351 This value is zero-based.\r
352 @param PortStatus Variable to receive the port state.\r
353\r
354 @retval EFI_SUCCESS The status of the USB root hub port specified.\r
355 by PortNumber was returned in PortStatus.\r
356 @retval EFI_INVALID_PARAMETER PortNumber is invalid.\r
357 @retval EFI_DEVICE_ERROR Can't read register.\r
358\r
359**/\r
360EFI_STATUS\r
361EFIAPI\r
362XhcGetRootHubPortStatus (\r
363 IN EFI_USB2_HC_PROTOCOL *This,\r
364 IN UINT8 PortNumber,\r
365 OUT EFI_USB_PORT_STATUS *PortStatus\r
366 )\r
367{\r
1436aea4
MK
368 USB_XHCI_INSTANCE *Xhc;\r
369 UINT32 Offset;\r
370 UINT32 State;\r
371 UINT32 TotalPort;\r
372 UINTN Index;\r
373 UINTN MapSize;\r
01c2fb0d 374 UINT8 PortSpeed;\r
1436aea4
MK
375 EFI_STATUS Status;\r
376 USB_DEV_ROUTE ParentRouteChart;\r
377 EFI_TPL OldTpl;\r
4b738c76
HT
378\r
379 if (PortStatus == NULL) {\r
380 return EFI_INVALID_PARAMETER;\r
381 }\r
382\r
383 OldTpl = gBS->RaiseTPL (XHC_TPL);\r
384\r
1436aea4
MK
385 Xhc = XHC_FROM_THIS (This);\r
386 Status = EFI_SUCCESS;\r
4b738c76
HT
387\r
388 TotalPort = Xhc->HcSParams1.Data.MaxPorts;\r
389\r
390 if (PortNumber >= TotalPort) {\r
391 Status = EFI_INVALID_PARAMETER;\r
392 goto ON_EXIT;\r
393 }\r
394\r
1436aea4 395 Offset = (UINT32)(XHC_PORTSC_OFFSET + (0x10 * PortNumber));\r
4b738c76
HT
396 PortStatus->PortStatus = 0;\r
397 PortStatus->PortChangeStatus = 0;\r
398\r
399 State = XhcReadOpReg (Xhc, Offset);\r
400\r
01c2fb0d
MD
401 PortSpeed = (State & XHC_PORTSC_PS) >> 10;\r
402\r
4b738c76 403 //\r
4a723d3d 404 // According to XHCI 1.1 spec November 2017,\r
7f4eca4c 405 // Section 7.2 xHCI Support Protocol Capability\r
4b738c76 406 //\r
01c2fb0d 407 if (PortSpeed > 0) {\r
ec25e904 408 PortStatus->PortStatus = XhcCheckUsbPortSpeedUsedPsic (Xhc, PortSpeed, PortNumber);\r
01c2fb0d
MD
409 // If no match found in ext cap reg, fall back to PORTSC\r
410 if (PortStatus->PortStatus == 0) {\r
411 //\r
412 // According to XHCI 1.1 spec November 2017,\r
413 // bit 10~13 of the root port status register identifies the speed of the attached device.\r
414 //\r
415 switch (PortSpeed) {\r
416 case 2:\r
417 PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;\r
418 break;\r
419\r
420 case 3:\r
421 PortStatus->PortStatus |= USB_PORT_STAT_HIGH_SPEED;\r
422 break;\r
423\r
424 case 4:\r
425 case 5:\r
426 PortStatus->PortStatus |= USB_PORT_STAT_SUPER_SPEED;\r
427 break;\r
428\r
429 default:\r
430 break;\r
431 }\r
7f4eca4c 432 }\r
4b738c76
HT
433 }\r
434\r
435 //\r
436 // Convert the XHCI port/port change state to UEFI status\r
437 //\r
438 MapSize = sizeof (mUsbPortStateMap) / sizeof (USB_PORT_STATE_MAP);\r
439\r
440 for (Index = 0; Index < MapSize; Index++) {\r
441 if (XHC_BIT_IS_SET (State, mUsbPortStateMap[Index].HwState)) {\r
1436aea4 442 PortStatus->PortStatus = (UINT16)(PortStatus->PortStatus | mUsbPortStateMap[Index].UefiState);\r
4b738c76
HT
443 }\r
444 }\r
1436aea4 445\r
4b738c76
HT
446 //\r
447 // Bit5~8 reflects its current link state.\r
448 //\r
449 if ((State & XHC_PORTSC_PLS) >> 5 == 3) {\r
450 PortStatus->PortStatus |= USB_PORT_STAT_SUSPEND;\r
451 }\r
452\r
453 MapSize = sizeof (mUsbPortChangeMap) / sizeof (USB_PORT_STATE_MAP);\r
454\r
455 for (Index = 0; Index < MapSize; Index++) {\r
456 if (XHC_BIT_IS_SET (State, mUsbPortChangeMap[Index].HwState)) {\r
1436aea4 457 PortStatus->PortChangeStatus = (UINT16)(PortStatus->PortChangeStatus | mUsbPortChangeMap[Index].UefiState);\r
4b738c76
HT
458 }\r
459 }\r
460\r
461 MapSize = sizeof (mUsbClearPortChangeMap) / sizeof (USB_CLEAR_PORT_MAP);\r
462\r
463 for (Index = 0; Index < MapSize; Index++) {\r
464 if (XHC_BIT_IS_SET (State, mUsbClearPortChangeMap[Index].HwState)) {\r
465 XhcClearRootHubPortFeature (This, PortNumber, (EFI_USB_PORT_FEATURE)mUsbClearPortChangeMap[Index].Selector);\r
466 }\r
467 }\r
468\r
469 //\r
470 // Poll the root port status register to enable/disable corresponding device slot if there is a device attached/detached.\r
471 // For those devices behind hub, we get its attach/detach event by hooking Get_Port_Status request at control transfer for those hub.\r
472 //\r
473 ParentRouteChart.Dword = 0;\r
992d5451
SR
474 Status = XhcPollPortStatusChange (Xhc, ParentRouteChart, PortNumber, PortStatus);\r
475\r
476 //\r
477 // Force resetting the port by clearing the USB_PORT_STAT_C_RESET bit in PortChangeStatus\r
478 // when XhcPollPortStatusChange fails\r
479 //\r
480 if (EFI_ERROR (Status)) {\r
481 PortStatus->PortChangeStatus &= ~(USB_PORT_STAT_C_RESET);\r
482 Status = EFI_SUCCESS;\r
483 }\r
4b738c76
HT
484\r
485ON_EXIT:\r
486 gBS->RestoreTPL (OldTpl);\r
487 return Status;\r
488}\r
489\r
4b738c76
HT
490/**\r
491 Sets a feature for the specified root hub port.\r
492\r
493 @param This This EFI_USB2_HC_PROTOCOL instance.\r
494 @param PortNumber Root hub port to set.\r
495 @param PortFeature Feature to set.\r
496\r
497 @retval EFI_SUCCESS The feature specified by PortFeature was set.\r
498 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.\r
499 @retval EFI_DEVICE_ERROR Can't read register.\r
500\r
501**/\r
502EFI_STATUS\r
503EFIAPI\r
504XhcSetRootHubPortFeature (\r
505 IN EFI_USB2_HC_PROTOCOL *This,\r
506 IN UINT8 PortNumber,\r
507 IN EFI_USB_PORT_FEATURE PortFeature\r
508 )\r
509{\r
1436aea4
MK
510 USB_XHCI_INSTANCE *Xhc;\r
511 UINT32 Offset;\r
512 UINT32 State;\r
513 UINT32 TotalPort;\r
514 EFI_STATUS Status;\r
515 EFI_TPL OldTpl;\r
4b738c76
HT
516\r
517 OldTpl = gBS->RaiseTPL (XHC_TPL);\r
518\r
519 Xhc = XHC_FROM_THIS (This);\r
520 Status = EFI_SUCCESS;\r
521\r
522 TotalPort = (Xhc->HcSParams1.Data.MaxPorts);\r
523\r
524 if (PortNumber >= TotalPort) {\r
525 Status = EFI_INVALID_PARAMETER;\r
526 goto ON_EXIT;\r
527 }\r
528\r
1436aea4 529 Offset = (UINT32)(XHC_PORTSC_OFFSET + (0x10 * PortNumber));\r
4b738c76
HT
530 State = XhcReadOpReg (Xhc, Offset);\r
531\r
532 //\r
533 // Mask off the port status change bits, these bits are\r
534 // write clean bit\r
535 //\r
1436aea4 536 State &= ~(BIT1 | BIT17 | BIT18 | BIT19 | BIT20 | BIT21 | BIT22 | BIT23);\r
4b738c76
HT
537\r
538 switch (PortFeature) {\r
1436aea4
MK
539 case EfiUsbPortEnable:\r
540 //\r
541 // Ports may only be enabled by the xHC. Software cannot enable a port by writing a '1' to this flag.\r
542 // A port may be disabled by software writing a '1' to this flag.\r
543 //\r
544 Status = EFI_SUCCESS;\r
545 break;\r
4b738c76 546\r
1436aea4
MK
547 case EfiUsbPortSuspend:\r
548 State |= XHC_PORTSC_LWS;\r
549 XhcWriteOpReg (Xhc, Offset, State);\r
550 State &= ~XHC_PORTSC_PLS;\r
551 State |= (3 << 5);\r
552 XhcWriteOpReg (Xhc, Offset, State);\r
553 break;\r
554\r
555 case EfiUsbPortReset:\r
556 DEBUG ((DEBUG_INFO, "XhcUsbPortReset!\n"));\r
557 //\r
558 // Make sure Host Controller not halt before reset it\r
559 //\r
560 if (XhcIsHalt (Xhc)) {\r
561 Status = XhcRunHC (Xhc, XHC_GENERIC_TIMEOUT);\r
562\r
563 if (EFI_ERROR (Status)) {\r
564 DEBUG ((DEBUG_INFO, "XhcSetRootHubPortFeature :failed to start HC - %r\n", Status));\r
565 break;\r
566 }\r
4b738c76 567 }\r
4b738c76 568\r
1436aea4
MK
569 //\r
570 // 4.3.1 Resetting a Root Hub Port\r
571 // 1) Write the PORTSC register with the Port Reset (PR) bit set to '1'.\r
572 //\r
573 State |= XHC_PORTSC_RESET;\r
574 XhcWriteOpReg (Xhc, Offset, State);\r
575 XhcWaitOpRegBit (Xhc, Offset, XHC_PORTSC_PRC, TRUE, XHC_GENERIC_TIMEOUT);\r
576 break;\r
4b738c76 577\r
1436aea4
MK
578 case EfiUsbPortPower:\r
579 //\r
580 // Not supported, ignore the operation\r
581 //\r
582 Status = EFI_SUCCESS;\r
583 break;\r
4b738c76 584\r
1436aea4
MK
585 case EfiUsbPortOwner:\r
586 //\r
587 // XHCI root hub port don't has the owner bit, ignore the operation\r
588 //\r
589 Status = EFI_SUCCESS;\r
590 break;\r
4b738c76 591\r
1436aea4
MK
592 default:\r
593 Status = EFI_INVALID_PARAMETER;\r
4b738c76
HT
594 }\r
595\r
596ON_EXIT:\r
87000d77 597 DEBUG ((DEBUG_INFO, "XhcSetRootHubPortFeature: status %r\n", Status));\r
4b738c76
HT
598 gBS->RestoreTPL (OldTpl);\r
599\r
600 return Status;\r
601}\r
602\r
4b738c76
HT
603/**\r
604 Clears a feature for the specified root hub port.\r
605\r
606 @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.\r
607 @param PortNumber Specifies the root hub port whose feature is\r
608 requested to be cleared.\r
609 @param PortFeature Indicates the feature selector associated with the\r
610 feature clear request.\r
611\r
612 @retval EFI_SUCCESS The feature specified by PortFeature was cleared\r
613 for the USB root hub port specified by PortNumber.\r
614 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.\r
615 @retval EFI_DEVICE_ERROR Can't read register.\r
616\r
617**/\r
618EFI_STATUS\r
619EFIAPI\r
620XhcClearRootHubPortFeature (\r
621 IN EFI_USB2_HC_PROTOCOL *This,\r
622 IN UINT8 PortNumber,\r
623 IN EFI_USB_PORT_FEATURE PortFeature\r
624 )\r
625{\r
1436aea4
MK
626 USB_XHCI_INSTANCE *Xhc;\r
627 UINT32 Offset;\r
628 UINT32 State;\r
629 UINT32 TotalPort;\r
630 EFI_STATUS Status;\r
631 EFI_TPL OldTpl;\r
4b738c76
HT
632\r
633 OldTpl = gBS->RaiseTPL (XHC_TPL);\r
634\r
1436aea4
MK
635 Xhc = XHC_FROM_THIS (This);\r
636 Status = EFI_SUCCESS;\r
4b738c76
HT
637\r
638 TotalPort = (Xhc->HcSParams1.Data.MaxPorts);\r
639\r
640 if (PortNumber >= TotalPort) {\r
641 Status = EFI_INVALID_PARAMETER;\r
642 goto ON_EXIT;\r
643 }\r
644\r
645 Offset = XHC_PORTSC_OFFSET + (0x10 * PortNumber);\r
646\r
647 //\r
648 // Mask off the port status change bits, these bits are\r
649 // write clean bit\r
650 //\r
651 State = XhcReadOpReg (Xhc, Offset);\r
1436aea4 652 State &= ~(BIT1 | BIT17 | BIT18 | BIT19 | BIT20 | BIT21 | BIT22 | BIT23);\r
4b738c76
HT
653\r
654 switch (PortFeature) {\r
1436aea4
MK
655 case EfiUsbPortEnable:\r
656 //\r
657 // Ports may only be enabled by the xHC. Software cannot enable a port by writing a '1' to this flag.\r
658 // A port may be disabled by software writing a '1' to this flag.\r
659 //\r
660 State |= XHC_PORTSC_PED;\r
661 State &= ~XHC_PORTSC_RESET;\r
662 XhcWriteOpReg (Xhc, Offset, State);\r
663 break;\r
4b738c76 664\r
1436aea4
MK
665 case EfiUsbPortSuspend:\r
666 State |= XHC_PORTSC_LWS;\r
667 XhcWriteOpReg (Xhc, Offset, State);\r
668 State &= ~XHC_PORTSC_PLS;\r
669 XhcWriteOpReg (Xhc, Offset, State);\r
670 break;\r
4b738c76 671\r
1436aea4
MK
672 case EfiUsbPortReset:\r
673 //\r
674 // PORTSC_RESET BIT(4) bit is RW1S attribute, which means Write-1-to-set status:\r
675 // Register bits indicate status when read, a clear bit may be set by\r
676 // writing a '1'. Writing a '0' to RW1S bits has no effect.\r
677 //\r
678 break;\r
4b738c76 679\r
1436aea4
MK
680 case EfiUsbPortOwner:\r
681 //\r
682 // XHCI root hub port don't has the owner bit, ignore the operation\r
683 //\r
684 break;\r
4b738c76 685\r
1436aea4
MK
686 case EfiUsbPortConnectChange:\r
687 //\r
688 // Clear connect status change\r
689 //\r
690 State |= XHC_PORTSC_CSC;\r
691 XhcWriteOpReg (Xhc, Offset, State);\r
692 break;\r
4b738c76 693\r
1436aea4
MK
694 case EfiUsbPortEnableChange:\r
695 //\r
696 // Clear enable status change\r
697 //\r
698 State |= XHC_PORTSC_PEC;\r
699 XhcWriteOpReg (Xhc, Offset, State);\r
700 break;\r
4b738c76 701\r
1436aea4
MK
702 case EfiUsbPortOverCurrentChange:\r
703 //\r
704 // Clear PortOverCurrent change\r
705 //\r
706 State |= XHC_PORTSC_OCC;\r
707 XhcWriteOpReg (Xhc, Offset, State);\r
708 break;\r
4b738c76 709\r
1436aea4
MK
710 case EfiUsbPortResetChange:\r
711 //\r
712 // Clear Port Reset change\r
713 //\r
714 State |= XHC_PORTSC_PRC;\r
715 XhcWriteOpReg (Xhc, Offset, State);\r
716 break;\r
717\r
718 case EfiUsbPortPower:\r
719 case EfiUsbPortSuspendChange:\r
720 //\r
721 // Not supported or not related operation\r
722 //\r
723 break;\r
724\r
725 default:\r
726 Status = EFI_INVALID_PARAMETER;\r
727 break;\r
4b738c76
HT
728 }\r
729\r
730ON_EXIT:\r
87000d77 731 DEBUG ((DEBUG_INFO, "XhcClearRootHubPortFeature: status %r\n", Status));\r
4b738c76
HT
732 gBS->RestoreTPL (OldTpl);\r
733\r
734 return Status;\r
735}\r
736\r
41fb8ce9
RN
737/**\r
738 Submits a new transaction to a target USB device.\r
739\r
740 @param Xhc The XHCI Instance.\r
741 @param DeviceAddress The target device address.\r
742 @param EndPointAddress Endpoint number and its direction encoded in bit 7\r
743 @param DeviceSpeed Target device speed.\r
744 @param MaximumPacketLength Maximum packet size the default control transfer\r
745 endpoint is capable of sending or receiving.\r
746 @param Type The transaction type.\r
747 @param Request USB device request to send.\r
748 @param Data Data buffer to be transmitted or received from USB\r
749 device.\r
750 @param DataLength The size (in bytes) of the data buffer.\r
751 @param Timeout Indicates the maximum timeout, in millisecond.\r
752 @param TransferResult Return the result of this control transfer.\r
753\r
754 @retval EFI_SUCCESS Transfer was completed successfully.\r
755 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources.\r
756 @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
757 @retval EFI_TIMEOUT Transfer failed due to timeout.\r
758 @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error.\r
759**/\r
760EFI_STATUS\r
761XhcTransfer (\r
1436aea4
MK
762 IN USB_XHCI_INSTANCE *Xhc,\r
763 IN UINT8 DeviceAddress,\r
764 IN UINT8 EndPointAddress,\r
765 IN UINT8 DeviceSpeed,\r
766 IN UINTN MaximumPacketLength,\r
767 IN UINTN Type,\r
768 IN EFI_USB_DEVICE_REQUEST *Request,\r
769 IN OUT VOID *Data,\r
770 IN OUT UINTN *DataLength,\r
771 IN UINTN Timeout,\r
772 OUT UINT32 *TransferResult\r
41fb8ce9
RN
773 )\r
774{\r
1436aea4
MK
775 EFI_STATUS Status;\r
776 EFI_STATUS RecoveryStatus;\r
777 URB *Urb;\r
41fb8ce9
RN
778\r
779 ASSERT ((Type == XHC_CTRL_TRANSFER) || (Type == XHC_BULK_TRANSFER) || (Type == XHC_INT_TRANSFER_SYNC));\r
780 Urb = XhcCreateUrb (\r
781 Xhc,\r
782 DeviceAddress,\r
783 EndPointAddress,\r
784 DeviceSpeed,\r
785 MaximumPacketLength,\r
786 Type,\r
787 Request,\r
788 Data,\r
789 *DataLength,\r
790 NULL,\r
791 NULL\r
792 );\r
793\r
794 if (Urb == NULL) {\r
795 DEBUG ((DEBUG_ERROR, "XhcTransfer[Type=%d]: failed to create URB!\n", Type));\r
796 return EFI_OUT_OF_RESOURCES;\r
797 }\r
798\r
799 Status = XhcExecTransfer (Xhc, FALSE, Urb, Timeout);\r
800\r
41fb8ce9
RN
801 if (Status == EFI_TIMEOUT) {\r
802 //\r
803 // The transfer timed out. Abort the transfer by dequeueing of the TD.\r
804 //\r
1436aea4 805 RecoveryStatus = XhcDequeueTrbFromEndpoint (Xhc, Urb);\r
49be9c3c
RN
806 if (RecoveryStatus == EFI_ALREADY_STARTED) {\r
807 //\r
808 // The URB is finished just before stopping endpoint.\r
809 // Change returning status from EFI_TIMEOUT to EFI_SUCCESS.\r
810 //\r
811 ASSERT (Urb->Result == EFI_USB_NOERROR);\r
41fb8ce9 812 Status = EFI_SUCCESS;\r
49be9c3c 813 DEBUG ((DEBUG_ERROR, "XhcTransfer[Type=%d]: pending URB is finished, Length = %d.\n", Type, Urb->Completed));\r
1436aea4
MK
814 } else if (EFI_ERROR (RecoveryStatus)) {\r
815 DEBUG ((DEBUG_ERROR, "XhcTransfer[Type=%d]: XhcDequeueTrbFromEndpoint failed!\n", Type));\r
49be9c3c
RN
816 }\r
817 }\r
818\r
819 *TransferResult = Urb->Result;\r
820 *DataLength = Urb->Completed;\r
821\r
958a8181 822 if ((*TransferResult == EFI_USB_ERR_STALL) || (*TransferResult == EFI_USB_ERR_BABBLE)) {\r
49be9c3c 823 ASSERT (Status == EFI_DEVICE_ERROR);\r
1436aea4 824 RecoveryStatus = XhcRecoverHaltedEndpoint (Xhc, Urb);\r
49be9c3c
RN
825 if (EFI_ERROR (RecoveryStatus)) {\r
826 DEBUG ((DEBUG_ERROR, "XhcTransfer[Type=%d]: XhcRecoverHaltedEndpoint failed!\n", Type));\r
41fb8ce9
RN
827 }\r
828 }\r
829\r
830 Xhc->PciIo->Flush (Xhc->PciIo);\r
831 XhcFreeUrb (Xhc, Urb);\r
832 return Status;\r
833}\r
4b738c76
HT
834\r
835/**\r
836 Submits control transfer to a target USB device.\r
837\r
838 @param This This EFI_USB2_HC_PROTOCOL instance.\r
839 @param DeviceAddress The target device address.\r
840 @param DeviceSpeed Target device speed.\r
841 @param MaximumPacketLength Maximum packet size the default control transfer\r
842 endpoint is capable of sending or receiving.\r
843 @param Request USB device request to send.\r
844 @param TransferDirection Specifies the data direction for the data stage\r
845 @param Data Data buffer to be transmitted or received from USB\r
846 device.\r
847 @param DataLength The size (in bytes) of the data buffer.\r
848 @param Timeout Indicates the maximum timeout, in millisecond.\r
849 @param Translator Transaction translator to be used by this device.\r
850 @param TransferResult Return the result of this control transfer.\r
851\r
852 @retval EFI_SUCCESS Transfer was completed successfully.\r
853 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources.\r
854 @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
855 @retval EFI_TIMEOUT Transfer failed due to timeout.\r
856 @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error.\r
857\r
858**/\r
859EFI_STATUS\r
860EFIAPI\r
861XhcControlTransfer (\r
862 IN EFI_USB2_HC_PROTOCOL *This,\r
863 IN UINT8 DeviceAddress,\r
864 IN UINT8 DeviceSpeed,\r
865 IN UINTN MaximumPacketLength,\r
866 IN EFI_USB_DEVICE_REQUEST *Request,\r
867 IN EFI_USB_DATA_DIRECTION TransferDirection,\r
868 IN OUT VOID *Data,\r
869 IN OUT UINTN *DataLength,\r
870 IN UINTN Timeout,\r
871 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,\r
872 OUT UINT32 *TransferResult\r
873 )\r
874{\r
875 USB_XHCI_INSTANCE *Xhc;\r
4b738c76
HT
876 UINT8 Endpoint;\r
877 UINT8 Index;\r
878 UINT8 DescriptorType;\r
879 UINT8 SlotId;\r
880 UINT8 TTT;\r
881 UINT8 MTT;\r
882 UINT32 MaxPacket0;\r
883 EFI_USB_HUB_DESCRIPTOR *HubDesc;\r
884 EFI_TPL OldTpl;\r
885 EFI_STATUS Status;\r
4b738c76
HT
886 UINTN MapSize;\r
887 EFI_USB_PORT_STATUS PortStatus;\r
888 UINT32 State;\r
889 EFI_USB_DEVICE_REQUEST ClearPortRequest;\r
890 UINTN Len;\r
891\r
892 //\r
893 // Validate parameters\r
894 //\r
895 if ((Request == NULL) || (TransferResult == NULL)) {\r
896 return EFI_INVALID_PARAMETER;\r
897 }\r
898\r
899 if ((TransferDirection != EfiUsbDataIn) &&\r
900 (TransferDirection != EfiUsbDataOut) &&\r
1436aea4
MK
901 (TransferDirection != EfiUsbNoData))\r
902 {\r
4b738c76
HT
903 return EFI_INVALID_PARAMETER;\r
904 }\r
905\r
906 if ((TransferDirection == EfiUsbNoData) &&\r
1436aea4
MK
907 ((Data != NULL) || (*DataLength != 0)))\r
908 {\r
4b738c76
HT
909 return EFI_INVALID_PARAMETER;\r
910 }\r
911\r
912 if ((TransferDirection != EfiUsbNoData) &&\r
1436aea4
MK
913 ((Data == NULL) || (*DataLength == 0)))\r
914 {\r
4b738c76
HT
915 return EFI_INVALID_PARAMETER;\r
916 }\r
917\r
918 if ((MaximumPacketLength != 8) && (MaximumPacketLength != 16) &&\r
919 (MaximumPacketLength != 32) && (MaximumPacketLength != 64) &&\r
920 (MaximumPacketLength != 512)\r
1436aea4
MK
921 )\r
922 {\r
4b738c76
HT
923 return EFI_INVALID_PARAMETER;\r
924 }\r
925\r
926 if ((DeviceSpeed == EFI_USB_SPEED_LOW) && (MaximumPacketLength != 8)) {\r
927 return EFI_INVALID_PARAMETER;\r
928 }\r
929\r
930 if ((DeviceSpeed == EFI_USB_SPEED_SUPER) && (MaximumPacketLength != 512)) {\r
931 return EFI_INVALID_PARAMETER;\r
932 }\r
933\r
934 OldTpl = gBS->RaiseTPL (XHC_TPL);\r
935\r
1436aea4 936 Xhc = XHC_FROM_THIS (This);\r
4b738c76
HT
937\r
938 Status = EFI_DEVICE_ERROR;\r
939 *TransferResult = EFI_USB_ERR_SYSTEM;\r
940 Len = 0;\r
941\r
942 if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {\r
87000d77 943 DEBUG ((DEBUG_ERROR, "XhcControlTransfer: HC halted at entrance\n"));\r
4b738c76
HT
944 goto ON_EXIT;\r
945 }\r
946\r
947 //\r
948 // Check if the device is still enabled before every transaction.\r
949 //\r
950 SlotId = XhcBusDevAddrToSlotId (Xhc, DeviceAddress);\r
951 if (SlotId == 0) {\r
952 goto ON_EXIT;\r
953 }\r
954\r
955 //\r
956 // Hook the Set_Address request from UsbBus.\r
957 // According to XHCI 1.0 spec, the Set_Address request is replaced by XHCI's Address_Device cmd.\r
958 //\r
959 if ((Request->Request == USB_REQ_SET_ADDRESS) &&\r
1436aea4
MK
960 (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD, USB_TARGET_DEVICE)))\r
961 {\r
4b738c76
HT
962 //\r
963 // Reset the BusDevAddr field of all disabled entries in UsbDevContext array firstly.\r
964 // This way is used to clean the history to avoid using wrong device address by XhcAsyncInterruptTransfer().\r
965 //\r
966 for (Index = 0; Index < 255; Index++) {\r
967 if (!Xhc->UsbDevContext[Index + 1].Enabled &&\r
968 (Xhc->UsbDevContext[Index + 1].SlotId == 0) &&\r
1436aea4
MK
969 (Xhc->UsbDevContext[Index + 1].BusDevAddr == (UINT8)Request->Value))\r
970 {\r
4b738c76
HT
971 Xhc->UsbDevContext[Index + 1].BusDevAddr = 0;\r
972 }\r
973 }\r
974\r
975 if (Xhc->UsbDevContext[SlotId].XhciDevAddr == 0) {\r
976 Status = EFI_DEVICE_ERROR;\r
977 goto ON_EXIT;\r
978 }\r
1436aea4 979\r
4b738c76
HT
980 //\r
981 // The actual device address has been assigned by XHCI during initializing the device slot.\r
982 // So we just need establish the mapping relationship between the device address requested from UsbBus\r
983 // and the actual device address assigned by XHCI. The the following invocations through EFI_USB2_HC_PROTOCOL interface\r
984 // can find out the actual device address by it.\r
985 //\r
986 Xhc->UsbDevContext[SlotId].BusDevAddr = (UINT8)Request->Value;\r
1436aea4 987 Status = EFI_SUCCESS;\r
4b738c76
HT
988 goto ON_EXIT;\r
989 }\r
990\r
991 //\r
992 // Create a new URB, insert it into the asynchronous\r
993 // schedule list, then poll the execution status.\r
994 // Note that we encode the direction in address although default control\r
995 // endpoint is bidirectional. XhcCreateUrb expects this\r
996 // combination of Ep addr and its direction.\r
997 //\r
1436aea4
MK
998 Endpoint = (UINT8)(0 | ((TransferDirection == EfiUsbDataIn) ? 0x80 : 0));\r
999 Status = XhcTransfer (\r
1000 Xhc,\r
1001 DeviceAddress,\r
1002 Endpoint,\r
1003 DeviceSpeed,\r
1004 MaximumPacketLength,\r
1005 XHC_CTRL_TRANSFER,\r
1006 Request,\r
1007 Data,\r
1008 DataLength,\r
1009 Timeout,\r
1010 TransferResult\r
1011 );\r
4b738c76 1012\r
41fb8ce9 1013 if (EFI_ERROR (Status)) {\r
4b738c76
HT
1014 goto ON_EXIT;\r
1015 }\r
1016\r
4b738c76
HT
1017 //\r
1018 // Hook Get_Descriptor request from UsbBus as we need evaluate context and configure endpoint.\r
1019 // Hook Get_Status request form UsbBus as we need trace device attach/detach event happened at hub.\r
1020 // Hook Set_Config request from UsbBus as we need configure device endpoint.\r
1021 //\r
1022 if ((Request->Request == USB_REQ_GET_DESCRIPTOR) &&\r
d1102dba 1023 ((Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_STANDARD, USB_TARGET_DEVICE)) ||\r
1436aea4
MK
1024 ((Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_CLASS, USB_TARGET_DEVICE)))))\r
1025 {\r
4b738c76
HT
1026 DescriptorType = (UINT8)(Request->Value >> 8);\r
1027 if ((DescriptorType == USB_DESC_TYPE_DEVICE) && ((*DataLength == sizeof (EFI_USB_DEVICE_DESCRIPTOR)) || ((DeviceSpeed == EFI_USB_SPEED_FULL) && (*DataLength == 8)))) {\r
1436aea4
MK
1028 ASSERT (Data != NULL);\r
1029 //\r
1030 // Store a copy of device scriptor as hub device need this info to configure endpoint.\r
1031 //\r
1032 CopyMem (&Xhc->UsbDevContext[SlotId].DevDesc, Data, *DataLength);\r
1033 if (Xhc->UsbDevContext[SlotId].DevDesc.BcdUSB >= 0x0300) {\r
4b738c76 1034 //\r
1436aea4 1035 // If it's a usb3.0 device, then its max packet size is a 2^n.\r
4b738c76 1036 //\r
1436aea4
MK
1037 MaxPacket0 = 1 << Xhc->UsbDevContext[SlotId].DevDesc.MaxPacketSize0;\r
1038 } else {\r
1039 MaxPacket0 = Xhc->UsbDevContext[SlotId].DevDesc.MaxPacketSize0;\r
1040 }\r
1041\r
1042 Xhc->UsbDevContext[SlotId].ConfDesc = AllocateZeroPool (Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations * sizeof (EFI_USB_CONFIG_DESCRIPTOR *));\r
1043 if (Xhc->HcCParams.Data.Csz == 0) {\r
1044 Status = XhcEvaluateContext (Xhc, SlotId, MaxPacket0);\r
1045 } else {\r
1046 Status = XhcEvaluateContext64 (Xhc, SlotId, MaxPacket0);\r
1047 }\r
4b738c76
HT
1048 } else if (DescriptorType == USB_DESC_TYPE_CONFIG) {\r
1049 ASSERT (Data != NULL);\r
1050 if (*DataLength == ((UINT16 *)Data)[1]) {\r
1051 //\r
1052 // Get configuration value from request, Store the configuration descriptor for Configure_Endpoint cmd.\r
1053 //\r
1054 Index = (UINT8)Request->Value;\r
1055 ASSERT (Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations);\r
1436aea4 1056 Xhc->UsbDevContext[SlotId].ConfDesc[Index] = AllocateZeroPool (*DataLength);\r
4b738c76 1057 CopyMem (Xhc->UsbDevContext[SlotId].ConfDesc[Index], Data, *DataLength);\r
e1f2dfec
SZ
1058 //\r
1059 // Default to use AlternateSetting 0 for all interfaces.\r
1060 //\r
1061 Xhc->UsbDevContext[SlotId].ActiveAlternateSetting = AllocateZeroPool (Xhc->UsbDevContext[SlotId].ConfDesc[Index]->NumInterfaces * sizeof (UINT8));\r
4b738c76
HT
1062 }\r
1063 } else if (((DescriptorType == USB_DESC_TYPE_HUB) ||\r
1436aea4
MK
1064 (DescriptorType == USB_DESC_TYPE_HUB_SUPER_SPEED)) && (*DataLength > 2))\r
1065 {\r
4b738c76
HT
1066 ASSERT (Data != NULL);\r
1067 HubDesc = (EFI_USB_HUB_DESCRIPTOR *)Data;\r
1068 ASSERT (HubDesc->NumPorts <= 15);\r
1069 //\r
1070 // The bit 5,6 of HubCharacter field of Hub Descriptor is TTT.\r
1071 //\r
1072 TTT = (UINT8)((HubDesc->HubCharacter & (BIT5 | BIT6)) >> 5);\r
1073 if (Xhc->UsbDevContext[SlotId].DevDesc.DeviceProtocol == 2) {\r
1074 //\r
1075 // Don't support multi-TT feature for super speed hub now.\r
1076 //\r
1077 MTT = 0;\r
87000d77 1078 DEBUG ((DEBUG_ERROR, "XHCI: Don't support multi-TT feature for Hub now. (force to disable MTT)\n"));\r
4b738c76
HT
1079 } else {\r
1080 MTT = 0;\r
1081 }\r
1082\r
1083 if (Xhc->HcCParams.Data.Csz == 0) {\r
1084 Status = XhcConfigHubContext (Xhc, SlotId, HubDesc->NumPorts, TTT, MTT);\r
1085 } else {\r
1086 Status = XhcConfigHubContext64 (Xhc, SlotId, HubDesc->NumPorts, TTT, MTT);\r
1087 }\r
1088 }\r
1089 } else if ((Request->Request == USB_REQ_SET_CONFIG) &&\r
1436aea4
MK
1090 (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD, USB_TARGET_DEVICE)))\r
1091 {\r
4b738c76
HT
1092 //\r
1093 // Hook Set_Config request from UsbBus as we need configure device endpoint.\r
1094 //\r
1095 for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {\r
1096 if (Xhc->UsbDevContext[SlotId].ConfDesc[Index]->ConfigurationValue == (UINT8)Request->Value) {\r
1097 if (Xhc->HcCParams.Data.Csz == 0) {\r
1098 Status = XhcSetConfigCmd (Xhc, SlotId, DeviceSpeed, Xhc->UsbDevContext[SlotId].ConfDesc[Index]);\r
1099 } else {\r
1100 Status = XhcSetConfigCmd64 (Xhc, SlotId, DeviceSpeed, Xhc->UsbDevContext[SlotId].ConfDesc[Index]);\r
1101 }\r
1436aea4 1102\r
4b738c76
HT
1103 break;\r
1104 }\r
1105 }\r
e1f2dfec 1106 } else if ((Request->Request == USB_REQ_SET_INTERFACE) &&\r
1436aea4
MK
1107 (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD, USB_TARGET_INTERFACE)))\r
1108 {\r
e1f2dfec
SZ
1109 //\r
1110 // Hook Set_Interface request from UsbBus as we need configure interface setting.\r
1111 // Request->Value indicates AlterlateSetting to set\r
1112 // Request->Index indicates Interface to set\r
1113 //\r
1436aea4 1114 if (Xhc->UsbDevContext[SlotId].ActiveAlternateSetting[(UINT8)Request->Index] != (UINT8)Request->Value) {\r
e1f2dfec
SZ
1115 if (Xhc->HcCParams.Data.Csz == 0) {\r
1116 Status = XhcSetInterface (Xhc, SlotId, DeviceSpeed, Xhc->UsbDevContext[SlotId].ConfDesc[Xhc->UsbDevContext[SlotId].ActiveConfiguration - 1], Request);\r
1117 } else {\r
1118 Status = XhcSetInterface64 (Xhc, SlotId, DeviceSpeed, Xhc->UsbDevContext[SlotId].ConfDesc[Xhc->UsbDevContext[SlotId].ActiveConfiguration - 1], Request);\r
1119 }\r
1120 }\r
4b738c76 1121 } else if ((Request->Request == USB_REQ_GET_STATUS) &&\r
1436aea4
MK
1122 (Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_CLASS, USB_TARGET_OTHER)))\r
1123 {\r
4b738c76
HT
1124 ASSERT (Data != NULL);\r
1125 //\r
1126 // Hook Get_Status request from UsbBus to keep track of the port status change.\r
1127 //\r
1128 State = *(UINT32 *)Data;\r
1129 PortStatus.PortStatus = 0;\r
1130 PortStatus.PortChangeStatus = 0;\r
1131\r
1132 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {\r
1133 //\r
1134 // For super speed hub, its bit10~12 presents the attached device speed.\r
1135 //\r
1136 if ((State & XHC_PORTSC_PS) >> 10 == 0) {\r
1137 PortStatus.PortStatus |= USB_PORT_STAT_SUPER_SPEED;\r
1138 }\r
1139 } else {\r
1140 //\r
1141 // For high or full/low speed hub, its bit9~10 presents the attached device speed.\r
1142 //\r
1143 if (XHC_BIT_IS_SET (State, BIT9)) {\r
1144 PortStatus.PortStatus |= USB_PORT_STAT_LOW_SPEED;\r
1145 } else if (XHC_BIT_IS_SET (State, BIT10)) {\r
1146 PortStatus.PortStatus |= USB_PORT_STAT_HIGH_SPEED;\r
1147 }\r
1148 }\r
1149\r
1150 //\r
1151 // Convert the XHCI port/port change state to UEFI status\r
1152 //\r
1153 MapSize = sizeof (mUsbHubPortStateMap) / sizeof (USB_PORT_STATE_MAP);\r
1154 for (Index = 0; Index < MapSize; Index++) {\r
1155 if (XHC_BIT_IS_SET (State, mUsbHubPortStateMap[Index].HwState)) {\r
1436aea4 1156 PortStatus.PortStatus = (UINT16)(PortStatus.PortStatus | mUsbHubPortStateMap[Index].UefiState);\r
4b738c76
HT
1157 }\r
1158 }\r
1159\r
1160 MapSize = sizeof (mUsbHubPortChangeMap) / sizeof (USB_PORT_STATE_MAP);\r
1161 for (Index = 0; Index < MapSize; Index++) {\r
1162 if (XHC_BIT_IS_SET (State, mUsbHubPortChangeMap[Index].HwState)) {\r
1436aea4 1163 PortStatus.PortChangeStatus = (UINT16)(PortStatus.PortChangeStatus | mUsbHubPortChangeMap[Index].UefiState);\r
4b738c76
HT
1164 }\r
1165 }\r
1166\r
1167 MapSize = sizeof (mUsbHubClearPortChangeMap) / sizeof (USB_CLEAR_PORT_MAP);\r
1168\r
1169 for (Index = 0; Index < MapSize; Index++) {\r
1170 if (XHC_BIT_IS_SET (State, mUsbHubClearPortChangeMap[Index].HwState)) {\r
1171 ZeroMem (&ClearPortRequest, sizeof (EFI_USB_DEVICE_REQUEST));\r
1436aea4
MK
1172 ClearPortRequest.RequestType = USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_CLASS, USB_TARGET_OTHER);\r
1173 ClearPortRequest.Request = (UINT8)USB_REQ_CLEAR_FEATURE;\r
1174 ClearPortRequest.Value = mUsbHubClearPortChangeMap[Index].Selector;\r
1175 ClearPortRequest.Index = Request->Index;\r
1176 ClearPortRequest.Length = 0;\r
4b738c76
HT
1177\r
1178 XhcControlTransfer (\r
d1102dba 1179 This,\r
4b738c76
HT
1180 DeviceAddress,\r
1181 DeviceSpeed,\r
1182 MaximumPacketLength,\r
1183 &ClearPortRequest,\r
1184 EfiUsbNoData,\r
1185 NULL,\r
1186 &Len,\r
1187 Timeout,\r
1188 Translator,\r
1189 TransferResult\r
1190 );\r
1191 }\r
1192 }\r
1193\r
1194 XhcPollPortStatusChange (Xhc, Xhc->UsbDevContext[SlotId].RouteString, (UINT8)Request->Index, &PortStatus);\r
1195\r
1436aea4 1196 *(UINT32 *)Data = *(UINT32 *)&PortStatus;\r
4b738c76
HT
1197 }\r
1198\r
4b738c76 1199ON_EXIT:\r
4b738c76 1200 if (EFI_ERROR (Status)) {\r
87000d77 1201 DEBUG ((DEBUG_ERROR, "XhcControlTransfer: error - %r, transfer - %x\n", Status, *TransferResult));\r
4b738c76
HT
1202 }\r
1203\r
1204 gBS->RestoreTPL (OldTpl);\r
1205\r
1206 return Status;\r
1207}\r
1208\r
4b738c76
HT
1209/**\r
1210 Submits bulk transfer to a bulk endpoint of a USB device.\r
1211\r
1212 @param This This EFI_USB2_HC_PROTOCOL instance.\r
1213 @param DeviceAddress Target device address.\r
1214 @param EndPointAddress Endpoint number and its direction in bit 7.\r
1215 @param DeviceSpeed Device speed, Low speed device doesn't support bulk\r
1216 transfer.\r
1217 @param MaximumPacketLength Maximum packet size the endpoint is capable of\r
1218 sending or receiving.\r
1219 @param DataBuffersNumber Number of data buffers prepared for the transfer.\r
1220 @param Data Array of pointers to the buffers of data to transmit\r
1221 from or receive into.\r
1222 @param DataLength The lenght of the data buffer.\r
1223 @param DataToggle On input, the initial data toggle for the transfer;\r
1224 On output, it is updated to to next data toggle to\r
1225 use of the subsequent bulk transfer.\r
1226 @param Timeout Indicates the maximum time, in millisecond, which\r
1227 the transfer is allowed to complete.\r
1228 @param Translator A pointr to the transaction translator data.\r
1229 @param TransferResult A pointer to the detailed result information of the\r
1230 bulk transfer.\r
1231\r
1232 @retval EFI_SUCCESS The transfer was completed successfully.\r
1233 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.\r
1234 @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
1235 @retval EFI_TIMEOUT The transfer failed due to timeout.\r
1236 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.\r
1237\r
1238**/\r
1239EFI_STATUS\r
1240EFIAPI\r
1241XhcBulkTransfer (\r
1242 IN EFI_USB2_HC_PROTOCOL *This,\r
1243 IN UINT8 DeviceAddress,\r
1244 IN UINT8 EndPointAddress,\r
1245 IN UINT8 DeviceSpeed,\r
1246 IN UINTN MaximumPacketLength,\r
1247 IN UINT8 DataBuffersNumber,\r
1248 IN OUT VOID *Data[EFI_USB_MAX_BULK_BUFFER_NUM],\r
1249 IN OUT UINTN *DataLength,\r
1250 IN OUT UINT8 *DataToggle,\r
1251 IN UINTN Timeout,\r
1252 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,\r
1253 OUT UINT32 *TransferResult\r
1254 )\r
1255{\r
1436aea4
MK
1256 USB_XHCI_INSTANCE *Xhc;\r
1257 UINT8 SlotId;\r
1258 EFI_STATUS Status;\r
1259 EFI_TPL OldTpl;\r
d9e7f6fe 1260 UINTN DebugErrorLevel;\r
4b738c76
HT
1261\r
1262 //\r
1263 // Validate the parameters\r
1264 //\r
1265 if ((DataLength == NULL) || (*DataLength == 0) ||\r
1436aea4
MK
1266 (Data == NULL) || (Data[0] == NULL) || (TransferResult == NULL))\r
1267 {\r
4b738c76
HT
1268 return EFI_INVALID_PARAMETER;\r
1269 }\r
1270\r
1271 if ((*DataToggle != 0) && (*DataToggle != 1)) {\r
1272 return EFI_INVALID_PARAMETER;\r
1273 }\r
1274\r
1275 if ((DeviceSpeed == EFI_USB_SPEED_LOW) ||\r
1276 ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) ||\r
1277 ((EFI_USB_SPEED_HIGH == DeviceSpeed) && (MaximumPacketLength > 512)) ||\r
1436aea4
MK
1278 ((EFI_USB_SPEED_SUPER == DeviceSpeed) && (MaximumPacketLength > 1024)))\r
1279 {\r
4b738c76
HT
1280 return EFI_INVALID_PARAMETER;\r
1281 }\r
1282\r
1283 OldTpl = gBS->RaiseTPL (XHC_TPL);\r
1284\r
1436aea4 1285 Xhc = XHC_FROM_THIS (This);\r
4b738c76
HT
1286\r
1287 *TransferResult = EFI_USB_ERR_SYSTEM;\r
1288 Status = EFI_DEVICE_ERROR;\r
1289\r
1290 if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {\r
87000d77 1291 DEBUG ((DEBUG_ERROR, "XhcBulkTransfer: HC is halted\n"));\r
4b738c76
HT
1292 goto ON_EXIT;\r
1293 }\r
1294\r
1295 //\r
1296 // Check if the device is still enabled before every transaction.\r
1297 //\r
1298 SlotId = XhcBusDevAddrToSlotId (Xhc, DeviceAddress);\r
1299 if (SlotId == 0) {\r
1300 goto ON_EXIT;\r
1301 }\r
1302\r
1303 //\r
1304 // Create a new URB, insert it into the asynchronous\r
1305 // schedule list, then poll the execution status.\r
1306 //\r
41fb8ce9
RN
1307 Status = XhcTransfer (\r
1308 Xhc,\r
1309 DeviceAddress,\r
1310 EndPointAddress,\r
1311 DeviceSpeed,\r
1312 MaximumPacketLength,\r
1313 XHC_BULK_TRANSFER,\r
1314 NULL,\r
1315 Data[0],\r
1316 DataLength,\r
1317 Timeout,\r
1318 TransferResult\r
1319 );\r
4b738c76
HT
1320\r
1321ON_EXIT:\r
4b738c76 1322 if (EFI_ERROR (Status)) {\r
d9e7f6fe
RC
1323 if (Status == EFI_TIMEOUT) {\r
1324 DebugErrorLevel = DEBUG_VERBOSE;\r
1325 } else {\r
1326 DebugErrorLevel = DEBUG_ERROR;\r
1327 }\r
1328\r
1329 DEBUG ((DebugErrorLevel, "XhcBulkTransfer: error - %r, transfer - %x\n", Status, *TransferResult));\r
4b738c76 1330 }\r
1436aea4 1331\r
4b738c76
HT
1332 gBS->RestoreTPL (OldTpl);\r
1333\r
1334 return Status;\r
1335}\r
1336\r
1337/**\r
1338 Submits an asynchronous interrupt transfer to an\r
1339 interrupt endpoint of a USB device.\r
1340\r
1341 @param This This EFI_USB2_HC_PROTOCOL instance.\r
1342 @param DeviceAddress Target device address.\r
1343 @param EndPointAddress Endpoint number and its direction encoded in bit 7\r
1344 @param DeviceSpeed Indicates device speed.\r
1345 @param MaximumPacketLength Maximum packet size the target endpoint is capable\r
1346 @param IsNewTransfer If TRUE, to submit an new asynchronous interrupt\r
1347 transfer If FALSE, to remove the specified\r
1348 asynchronous interrupt.\r
1349 @param DataToggle On input, the initial data toggle to use; on output,\r
1350 it is updated to indicate the next data toggle.\r
1351 @param PollingInterval The he interval, in milliseconds, that the transfer\r
1352 is polled.\r
1353 @param DataLength The length of data to receive at the rate specified\r
1354 by PollingInterval.\r
1355 @param Translator Transaction translator to use.\r
1356 @param CallBackFunction Function to call at the rate specified by\r
1357 PollingInterval.\r
1358 @param Context Context to CallBackFunction.\r
1359\r
1360 @retval EFI_SUCCESS The request has been successfully submitted or canceled.\r
1361 @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
1362 @retval EFI_OUT_OF_RESOURCES The request failed due to a lack of resources.\r
1363 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.\r
1364\r
1365**/\r
1366EFI_STATUS\r
1367EFIAPI\r
1368XhcAsyncInterruptTransfer (\r
1369 IN EFI_USB2_HC_PROTOCOL *This,\r
1370 IN UINT8 DeviceAddress,\r
1371 IN UINT8 EndPointAddress,\r
1372 IN UINT8 DeviceSpeed,\r
1373 IN UINTN MaximumPacketLength,\r
1374 IN BOOLEAN IsNewTransfer,\r
1375 IN OUT UINT8 *DataToggle,\r
1376 IN UINTN PollingInterval,\r
1377 IN UINTN DataLength,\r
1378 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,\r
1379 IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction,\r
1380 IN VOID *Context OPTIONAL\r
1381 )\r
1382{\r
1436aea4
MK
1383 USB_XHCI_INSTANCE *Xhc;\r
1384 URB *Urb;\r
1385 EFI_STATUS Status;\r
1386 UINT8 SlotId;\r
1387 UINT8 Index;\r
1388 EFI_TPL OldTpl;\r
4b738c76
HT
1389\r
1390 //\r
1391 // Validate parameters\r
1392 //\r
1393 if (!XHCI_IS_DATAIN (EndPointAddress)) {\r
1394 return EFI_INVALID_PARAMETER;\r
1395 }\r
1396\r
1397 if (IsNewTransfer) {\r
1398 if (DataLength == 0) {\r
1399 return EFI_INVALID_PARAMETER;\r
1400 }\r
1401\r
1402 if ((*DataToggle != 1) && (*DataToggle != 0)) {\r
1403 return EFI_INVALID_PARAMETER;\r
1404 }\r
1405\r
1406 if ((PollingInterval > 255) || (PollingInterval < 1)) {\r
1407 return EFI_INVALID_PARAMETER;\r
1408 }\r
1409 }\r
1410\r
1411 OldTpl = gBS->RaiseTPL (XHC_TPL);\r
1412\r
1436aea4 1413 Xhc = XHC_FROM_THIS (This);\r
4b738c76
HT
1414\r
1415 //\r
1416 // Delete Async interrupt transfer request.\r
1417 //\r
1418 if (!IsNewTransfer) {\r
1419 //\r
1420 // The delete request may happen after device is detached.\r
1421 //\r
1422 for (Index = 0; Index < 255; Index++) {\r
1423 if (Xhc->UsbDevContext[Index + 1].BusDevAddr == DeviceAddress) {\r
1424 break;\r
1425 }\r
1426 }\r
1427\r
1428 if (Index == 255) {\r
1429 Status = EFI_INVALID_PARAMETER;\r
1430 goto ON_EXIT;\r
1431 }\r
1432\r
1433 Status = XhciDelAsyncIntTransfer (Xhc, DeviceAddress, EndPointAddress);\r
87000d77 1434 DEBUG ((DEBUG_INFO, "XhcAsyncInterruptTransfer: remove old transfer for addr %d, Status = %r\n", DeviceAddress, Status));\r
4b738c76
HT
1435 goto ON_EXIT;\r
1436 }\r
1437\r
1438 Status = EFI_SUCCESS;\r
1439\r
1440 if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {\r
87000d77 1441 DEBUG ((DEBUG_ERROR, "XhcAsyncInterruptTransfer: HC is halt\n"));\r
4b738c76
HT
1442 Status = EFI_DEVICE_ERROR;\r
1443 goto ON_EXIT;\r
1444 }\r
1445\r
1446 //\r
1447 // Check if the device is still enabled before every transaction.\r
1448 //\r
1449 SlotId = XhcBusDevAddrToSlotId (Xhc, DeviceAddress);\r
1450 if (SlotId == 0) {\r
1451 goto ON_EXIT;\r
1452 }\r
1453\r
6681582d 1454 Urb = XhciInsertAsyncIntTransfer (\r
4b738c76
HT
1455 Xhc,\r
1456 DeviceAddress,\r
1457 EndPointAddress,\r
1458 DeviceSpeed,\r
1459 MaximumPacketLength,\r
4b738c76
HT
1460 DataLength,\r
1461 CallBackFunction,\r
1462 Context\r
1463 );\r
4b738c76 1464 if (Urb == NULL) {\r
4b738c76
HT
1465 Status = EFI_OUT_OF_RESOURCES;\r
1466 goto ON_EXIT;\r
1467 }\r
1468\r
4b738c76
HT
1469 //\r
1470 // Ring the doorbell\r
1471 //\r
1472 Status = RingIntTransferDoorBell (Xhc, Urb);\r
1473\r
1474ON_EXIT:\r
1475 Xhc->PciIo->Flush (Xhc->PciIo);\r
1476 gBS->RestoreTPL (OldTpl);\r
1477\r
1478 return Status;\r
1479}\r
1480\r
4b738c76
HT
1481/**\r
1482 Submits synchronous interrupt transfer to an interrupt endpoint\r
1483 of a USB device.\r
1484\r
1485 @param This This EFI_USB2_HC_PROTOCOL instance.\r
1486 @param DeviceAddress Target device address.\r
1487 @param EndPointAddress Endpoint number and its direction encoded in bit 7\r
1488 @param DeviceSpeed Indicates device speed.\r
1489 @param MaximumPacketLength Maximum packet size the target endpoint is capable\r
1490 of sending or receiving.\r
1491 @param Data Buffer of data that will be transmitted to USB\r
1492 device or received from USB device.\r
1493 @param DataLength On input, the size, in bytes, of the data buffer; On\r
1494 output, the number of bytes transferred.\r
1495 @param DataToggle On input, the initial data toggle to use; on output,\r
1496 it is updated to indicate the next data toggle.\r
1497 @param Timeout Maximum time, in second, to complete.\r
1498 @param Translator Transaction translator to use.\r
1499 @param TransferResult Variable to receive the transfer result.\r
1500\r
1501 @return EFI_SUCCESS The transfer was completed successfully.\r
1502 @return EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.\r
1503 @return EFI_INVALID_PARAMETER Some parameters are invalid.\r
1504 @return EFI_TIMEOUT The transfer failed due to timeout.\r
1505 @return EFI_DEVICE_ERROR The failed due to host controller or device error\r
1506\r
1507**/\r
1508EFI_STATUS\r
1509EFIAPI\r
1510XhcSyncInterruptTransfer (\r
1511 IN EFI_USB2_HC_PROTOCOL *This,\r
1512 IN UINT8 DeviceAddress,\r
1513 IN UINT8 EndPointAddress,\r
1514 IN UINT8 DeviceSpeed,\r
1515 IN UINTN MaximumPacketLength,\r
1516 IN OUT VOID *Data,\r
1517 IN OUT UINTN *DataLength,\r
1518 IN OUT UINT8 *DataToggle,\r
1519 IN UINTN Timeout,\r
1520 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,\r
1521 OUT UINT32 *TransferResult\r
1522 )\r
1523{\r
1436aea4
MK
1524 USB_XHCI_INSTANCE *Xhc;\r
1525 UINT8 SlotId;\r
1526 EFI_STATUS Status;\r
1527 EFI_TPL OldTpl;\r
4b738c76
HT
1528\r
1529 //\r
1530 // Validates parameters\r
1531 //\r
1532 if ((DataLength == NULL) || (*DataLength == 0) ||\r
1436aea4
MK
1533 (Data == NULL) || (TransferResult == NULL))\r
1534 {\r
4b738c76
HT
1535 return EFI_INVALID_PARAMETER;\r
1536 }\r
1537\r
4b738c76
HT
1538 if ((*DataToggle != 1) && (*DataToggle != 0)) {\r
1539 return EFI_INVALID_PARAMETER;\r
1540 }\r
1541\r
1542 if (((DeviceSpeed == EFI_USB_SPEED_LOW) && (MaximumPacketLength != 8)) ||\r
1543 ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) ||\r
1436aea4
MK
1544 ((DeviceSpeed == EFI_USB_SPEED_HIGH) && (MaximumPacketLength > 3072)))\r
1545 {\r
4b738c76
HT
1546 return EFI_INVALID_PARAMETER;\r
1547 }\r
1548\r
1549 OldTpl = gBS->RaiseTPL (XHC_TPL);\r
1550\r
1436aea4 1551 Xhc = XHC_FROM_THIS (This);\r
4b738c76
HT
1552\r
1553 *TransferResult = EFI_USB_ERR_SYSTEM;\r
1554 Status = EFI_DEVICE_ERROR;\r
1555\r
1556 if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {\r
87000d77 1557 DEBUG ((DEBUG_ERROR, "EhcSyncInterruptTransfer: HC is halt\n"));\r
4b738c76
HT
1558 goto ON_EXIT;\r
1559 }\r
1560\r
1561 //\r
1562 // Check if the device is still enabled before every transaction.\r
1563 //\r
1564 SlotId = XhcBusDevAddrToSlotId (Xhc, DeviceAddress);\r
1565 if (SlotId == 0) {\r
1566 goto ON_EXIT;\r
1567 }\r
1568\r
41fb8ce9
RN
1569 Status = XhcTransfer (\r
1570 Xhc,\r
1571 DeviceAddress,\r
1572 EndPointAddress,\r
1573 DeviceSpeed,\r
1574 MaximumPacketLength,\r
1575 XHC_INT_TRANSFER_SYNC,\r
1576 NULL,\r
1577 Data,\r
1578 DataLength,\r
1579 Timeout,\r
1580 TransferResult\r
1581 );\r
4b738c76
HT
1582\r
1583ON_EXIT:\r
1584 if (EFI_ERROR (Status)) {\r
87000d77 1585 DEBUG ((DEBUG_ERROR, "XhcSyncInterruptTransfer: error - %r, transfer - %x\n", Status, *TransferResult));\r
4b738c76 1586 }\r
1436aea4 1587\r
4b738c76
HT
1588 gBS->RestoreTPL (OldTpl);\r
1589\r
1590 return Status;\r
1591}\r
1592\r
4b738c76
HT
1593/**\r
1594 Submits isochronous transfer to a target USB device.\r
1595\r
1596 @param This This EFI_USB2_HC_PROTOCOL instance.\r
1597 @param DeviceAddress Target device address.\r
1598 @param EndPointAddress End point address with its direction.\r
1599 @param DeviceSpeed Device speed, Low speed device doesn't support this\r
1600 type.\r
1601 @param MaximumPacketLength Maximum packet size that the endpoint is capable of\r
1602 sending or receiving.\r
1603 @param DataBuffersNumber Number of data buffers prepared for the transfer.\r
1604 @param Data Array of pointers to the buffers of data that will\r
1605 be transmitted to USB device or received from USB\r
1606 device.\r
1607 @param DataLength The size, in bytes, of the data buffer.\r
1608 @param Translator Transaction translator to use.\r
1609 @param TransferResult Variable to receive the transfer result.\r
1610\r
1611 @return EFI_UNSUPPORTED Isochronous transfer is unsupported.\r
1612\r
1613**/\r
1614EFI_STATUS\r
1615EFIAPI\r
1616XhcIsochronousTransfer (\r
1617 IN EFI_USB2_HC_PROTOCOL *This,\r
1618 IN UINT8 DeviceAddress,\r
1619 IN UINT8 EndPointAddress,\r
1620 IN UINT8 DeviceSpeed,\r
1621 IN UINTN MaximumPacketLength,\r
1622 IN UINT8 DataBuffersNumber,\r
1623 IN OUT VOID *Data[EFI_USB_MAX_ISO_BUFFER_NUM],\r
1624 IN UINTN DataLength,\r
1625 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,\r
1626 OUT UINT32 *TransferResult\r
1627 )\r
1628{\r
1629 return EFI_UNSUPPORTED;\r
1630}\r
1631\r
4b738c76
HT
1632/**\r
1633 Submits Async isochronous transfer to a target USB device.\r
1634\r
1635 @param This This EFI_USB2_HC_PROTOCOL instance.\r
1636 @param DeviceAddress Target device address.\r
1637 @param EndPointAddress End point address with its direction.\r
1638 @param DeviceSpeed Device speed, Low speed device doesn't support this\r
1639 type.\r
1640 @param MaximumPacketLength Maximum packet size that the endpoint is capable of\r
1641 sending or receiving.\r
1642 @param DataBuffersNumber Number of data buffers prepared for the transfer.\r
1643 @param Data Array of pointers to the buffers of data that will\r
1644 be transmitted to USB device or received from USB\r
1645 device.\r
1646 @param DataLength The size, in bytes, of the data buffer.\r
1647 @param Translator Transaction translator to use.\r
1648 @param IsochronousCallBack Function to be called when the transfer complete.\r
1649 @param Context Context passed to the call back function as\r
1650 parameter.\r
1651\r
1652 @return EFI_UNSUPPORTED Isochronous transfer isn't supported.\r
1653\r
1654**/\r
1655EFI_STATUS\r
1656EFIAPI\r
1657XhcAsyncIsochronousTransfer (\r
1658 IN EFI_USB2_HC_PROTOCOL *This,\r
1659 IN UINT8 DeviceAddress,\r
1660 IN UINT8 EndPointAddress,\r
1661 IN UINT8 DeviceSpeed,\r
1662 IN UINTN MaximumPacketLength,\r
1663 IN UINT8 DataBuffersNumber,\r
1664 IN OUT VOID *Data[EFI_USB_MAX_ISO_BUFFER_NUM],\r
1665 IN UINTN DataLength,\r
1666 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,\r
1667 IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack,\r
1668 IN VOID *Context\r
1669 )\r
1670{\r
1671 return EFI_UNSUPPORTED;\r
1672}\r
1673\r
1674/**\r
1675 Entry point for EFI drivers.\r
1676\r
1677 @param ImageHandle EFI_HANDLE.\r
1678 @param SystemTable EFI_SYSTEM_TABLE.\r
1679\r
1680 @retval EFI_SUCCESS Success.\r
1681 @retval Others Fail.\r
1682\r
1683**/\r
1684EFI_STATUS\r
1685EFIAPI\r
1686XhcDriverEntryPoint (\r
1436aea4
MK
1687 IN EFI_HANDLE ImageHandle,\r
1688 IN EFI_SYSTEM_TABLE *SystemTable\r
4b738c76
HT
1689 )\r
1690{\r
1691 return EfiLibInstallDriverBindingComponentName2 (\r
1692 ImageHandle,\r
1693 SystemTable,\r
1694 &gXhciDriverBinding,\r
1695 ImageHandle,\r
1696 &gXhciComponentName,\r
1697 &gXhciComponentName2\r
1698 );\r
1699}\r
1700\r
4b738c76
HT
1701/**\r
1702 Test to see if this driver supports ControllerHandle. Any\r
1703 ControllerHandle that has Usb2HcProtocol installed will\r
1704 be supported.\r
1705\r
1706 @param This Protocol instance pointer.\r
1707 @param Controller Handle of device to test.\r
1708 @param RemainingDevicePath Not used.\r
1709\r
1710 @return EFI_SUCCESS This driver supports this device.\r
1711 @return EFI_UNSUPPORTED This driver does not support this device.\r
1712\r
1713**/\r
1714EFI_STATUS\r
1715EFIAPI\r
1716XhcDriverBindingSupported (\r
1436aea4
MK
1717 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1718 IN EFI_HANDLE Controller,\r
1719 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
4b738c76
HT
1720 )\r
1721{\r
1436aea4
MK
1722 EFI_STATUS Status;\r
1723 EFI_PCI_IO_PROTOCOL *PciIo;\r
1724 USB_CLASSC UsbClassCReg;\r
4b738c76
HT
1725\r
1726 //\r
1727 // Test whether there is PCI IO Protocol attached on the controller handle.\r
1728 //\r
1729 Status = gBS->OpenProtocol (\r
1730 Controller,\r
1731 &gEfiPciIoProtocolGuid,\r
1436aea4 1732 (VOID **)&PciIo,\r
4b738c76
HT
1733 This->DriverBindingHandle,\r
1734 Controller,\r
1735 EFI_OPEN_PROTOCOL_BY_DRIVER\r
1736 );\r
1737\r
1738 if (EFI_ERROR (Status)) {\r
1739 return EFI_UNSUPPORTED;\r
1740 }\r
1741\r
1742 Status = PciIo->Pci.Read (\r
1743 PciIo,\r
1744 EfiPciIoWidthUint8,\r
1745 PCI_CLASSCODE_OFFSET,\r
1746 sizeof (USB_CLASSC) / sizeof (UINT8),\r
1747 &UsbClassCReg\r
1748 );\r
1749\r
1750 if (EFI_ERROR (Status)) {\r
1751 Status = EFI_UNSUPPORTED;\r
1752 goto ON_EXIT;\r
1753 }\r
1754\r
1755 //\r
1756 // Test whether the controller belongs to Xhci type\r
1757 //\r
1758 if ((UsbClassCReg.BaseCode != PCI_CLASS_SERIAL) ||\r
1759 (UsbClassCReg.SubClassCode != PCI_CLASS_SERIAL_USB) ||\r
1436aea4
MK
1760 (UsbClassCReg.ProgInterface != PCI_IF_XHCI))\r
1761 {\r
4b738c76
HT
1762 Status = EFI_UNSUPPORTED;\r
1763 }\r
1764\r
1765ON_EXIT:\r
1766 gBS->CloseProtocol (\r
1767 Controller,\r
1768 &gEfiPciIoProtocolGuid,\r
1769 This->DriverBindingHandle,\r
1770 Controller\r
1771 );\r
1772\r
1773 return Status;\r
1774}\r
1775\r
1776/**\r
1777 Create and initialize a USB_XHCI_INSTANCE structure.\r
1778\r
1779 @param PciIo The PciIo on this device.\r
1780 @param DevicePath The device path of host controller.\r
1781 @param OriginalPciAttributes Original PCI attributes.\r
1782\r
1783 @return The allocated and initialized USB_XHCI_INSTANCE structure if created,\r
1784 otherwise NULL.\r
1785\r
1786**/\r
1436aea4 1787USB_XHCI_INSTANCE *\r
4b738c76
HT
1788XhcCreateUsbHc (\r
1789 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1790 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
1791 IN UINT64 OriginalPciAttributes\r
1792 )\r
1793{\r
1436aea4
MK
1794 USB_XHCI_INSTANCE *Xhc;\r
1795 EFI_STATUS Status;\r
1796 UINT32 PageSize;\r
1797 UINT16 ExtCapReg;\r
1798 UINT8 ReleaseNumber;\r
4b738c76
HT
1799\r
1800 Xhc = AllocateZeroPool (sizeof (USB_XHCI_INSTANCE));\r
1801\r
1802 if (Xhc == NULL) {\r
1803 return NULL;\r
1804 }\r
1805\r
1806 //\r
1807 // Initialize private data structure\r
1808 //\r
1809 Xhc->Signature = XHCI_INSTANCE_SIG;\r
1810 Xhc->PciIo = PciIo;\r
1811 Xhc->DevicePath = DevicePath;\r
1812 Xhc->OriginalPciAttributes = OriginalPciAttributes;\r
1813 CopyMem (&Xhc->Usb2Hc, &gXhciUsb2HcTemplate, sizeof (EFI_USB2_HC_PROTOCOL));\r
1814\r
fed6cf25
SZ
1815 Status = PciIo->Pci.Read (\r
1816 PciIo,\r
1817 EfiPciIoWidthUint8,\r
1818 XHC_PCI_SBRN_OFFSET,\r
1819 1,\r
1820 &ReleaseNumber\r
1821 );\r
1822\r
1823 if (!EFI_ERROR (Status)) {\r
1824 Xhc->Usb2Hc.MajorRevision = (ReleaseNumber & 0xF0) >> 4;\r
1825 Xhc->Usb2Hc.MinorRevision = (ReleaseNumber & 0x0F);\r
1826 }\r
1827\r
4b738c76
HT
1828 InitializeListHead (&Xhc->AsyncIntTransfers);\r
1829\r
1830 //\r
1831 // Be caution that the Offset passed to XhcReadCapReg() should be Dword align\r
1832 //\r
1833 Xhc->CapLength = XhcReadCapReg8 (Xhc, XHC_CAPLENGTH_OFFSET);\r
1834 Xhc->HcSParams1.Dword = XhcReadCapReg (Xhc, XHC_HCSPARAMS1_OFFSET);\r
1835 Xhc->HcSParams2.Dword = XhcReadCapReg (Xhc, XHC_HCSPARAMS2_OFFSET);\r
1836 Xhc->HcCParams.Dword = XhcReadCapReg (Xhc, XHC_HCCPARAMS_OFFSET);\r
1837 Xhc->DBOff = XhcReadCapReg (Xhc, XHC_DBOFF_OFFSET);\r
1838 Xhc->RTSOff = XhcReadCapReg (Xhc, XHC_RTSOFF_OFFSET);\r
1839\r
1840 //\r
1841 // This PageSize field defines the page size supported by the xHC implementation.\r
1842 // This xHC supports a page size of 2^(n+12) if bit n is Set. For example,\r
1843 // if bit 0 is Set, the xHC supports 4k byte page sizes.\r
1844 //\r
b97243de
LH
1845 PageSize = XhcReadOpReg (Xhc, XHC_PAGESIZE_OFFSET);\r
1846 if ((PageSize & (~XHC_PAGESIZE_MASK)) != 0) {\r
1847 DEBUG ((DEBUG_ERROR, "XhcCreateUsb3Hc: Reserved bits are not 0 for PageSize\n"));\r
1848 goto ON_ERROR;\r
1849 }\r
1850\r
1851 PageSize &= XHC_PAGESIZE_MASK;\r
1436aea4 1852 Xhc->PageSize = 1 << (HighBitSet32 (PageSize) + 12);\r
4b738c76 1853\r
1436aea4
MK
1854 ExtCapReg = (UINT16)(Xhc->HcCParams.Data.ExtCapReg);\r
1855 Xhc->ExtCapRegBase = ExtCapReg << 2;\r
1856 Xhc->UsbLegSupOffset = XhcGetCapabilityAddr (Xhc, XHC_CAP_USB_LEGACY);\r
4b738c76 1857 Xhc->DebugCapSupOffset = XhcGetCapabilityAddr (Xhc, XHC_CAP_USB_DEBUG);\r
7f4eca4c
IC
1858 Xhc->Usb2SupOffset = XhcGetSupportedProtocolCapabilityAddr (Xhc, XHC_SUPPORTED_PROTOCOL_DW0_MAJOR_REVISION_USB2);\r
1859 Xhc->Usb3SupOffset = XhcGetSupportedProtocolCapabilityAddr (Xhc, XHC_SUPPORTED_PROTOCOL_DW0_MAJOR_REVISION_USB3);\r
4b738c76 1860\r
87000d77
MK
1861 DEBUG ((DEBUG_INFO, "XhcCreateUsb3Hc: Capability length 0x%x\n", Xhc->CapLength));\r
1862 DEBUG ((DEBUG_INFO, "XhcCreateUsb3Hc: HcSParams1 0x%x\n", Xhc->HcSParams1));\r
1863 DEBUG ((DEBUG_INFO, "XhcCreateUsb3Hc: HcSParams2 0x%x\n", Xhc->HcSParams2));\r
1864 DEBUG ((DEBUG_INFO, "XhcCreateUsb3Hc: HcCParams 0x%x\n", Xhc->HcCParams));\r
1865 DEBUG ((DEBUG_INFO, "XhcCreateUsb3Hc: DBOff 0x%x\n", Xhc->DBOff));\r
1866 DEBUG ((DEBUG_INFO, "XhcCreateUsb3Hc: RTSOff 0x%x\n", Xhc->RTSOff));\r
1867 DEBUG ((DEBUG_INFO, "XhcCreateUsb3Hc: UsbLegSupOffset 0x%x\n", Xhc->UsbLegSupOffset));\r
1868 DEBUG ((DEBUG_INFO, "XhcCreateUsb3Hc: DebugCapSupOffset 0x%x\n", Xhc->DebugCapSupOffset));\r
7f4eca4c
IC
1869 DEBUG ((DEBUG_INFO, "XhcCreateUsb3Hc: Usb2SupOffset 0x%x\n", Xhc->Usb2SupOffset));\r
1870 DEBUG ((DEBUG_INFO, "XhcCreateUsb3Hc: Usb3SupOffset 0x%x\n", Xhc->Usb3SupOffset));\r
4b738c76
HT
1871\r
1872 //\r
1873 // Create AsyncRequest Polling Timer\r
1874 //\r
1875 Status = gBS->CreateEvent (\r
1876 EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
3cf6450e 1877 TPL_NOTIFY,\r
4b738c76
HT
1878 XhcMonitorAsyncRequests,\r
1879 Xhc,\r
1880 &Xhc->PollTimer\r
1881 );\r
1882\r
1883 if (EFI_ERROR (Status)) {\r
1884 goto ON_ERROR;\r
1885 }\r
1886\r
1887 return Xhc;\r
1888\r
1889ON_ERROR:\r
1890 FreePool (Xhc);\r
1891 return NULL;\r
1892}\r
1893\r
1894/**\r
1895 One notified function to stop the Host Controller when gBS->ExitBootServices() called.\r
1896\r
1897 @param Event Pointer to this event\r
e3644786 1898 @param Context Event handler private data\r
4b738c76
HT
1899\r
1900**/\r
1901VOID\r
1902EFIAPI\r
1903XhcExitBootService (\r
1904 EFI_EVENT Event,\r
1905 VOID *Context\r
1906 )\r
1907\r
1908{\r
1909 USB_XHCI_INSTANCE *Xhc;\r
1910 EFI_PCI_IO_PROTOCOL *PciIo;\r
1911\r
1436aea4 1912 Xhc = (USB_XHCI_INSTANCE *)Context;\r
4b738c76
HT
1913 PciIo = Xhc->PciIo;\r
1914\r
1915 //\r
1916 // Stop AsyncRequest Polling timer then stop the XHCI driver\r
1917 // and uninstall the XHCI protocl.\r
1918 //\r
1919 gBS->SetTimer (Xhc->PollTimer, TimerCancel, 0);\r
1920 XhcHaltHC (Xhc, XHC_GENERIC_TIMEOUT);\r
1921\r
1922 if (Xhc->PollTimer != NULL) {\r
1923 gBS->CloseEvent (Xhc->PollTimer);\r
1924 }\r
1925\r
1926 XhcClearBiosOwnership (Xhc);\r
1927\r
1928 //\r
1929 // Restore original PCI attributes\r
1930 //\r
1931 PciIo->Attributes (\r
1436aea4
MK
1932 PciIo,\r
1933 EfiPciIoAttributeOperationSet,\r
1934 Xhc->OriginalPciAttributes,\r
1935 NULL\r
1936 );\r
4b738c76
HT
1937}\r
1938\r
1939/**\r
1940 Starting the Usb XHCI Driver.\r
1941\r
1942 @param This Protocol instance pointer.\r
1943 @param Controller Handle of device to test.\r
1944 @param RemainingDevicePath Not used.\r
1945\r
1946 @return EFI_SUCCESS supports this device.\r
1947 @return EFI_UNSUPPORTED do not support this device.\r
1948 @return EFI_DEVICE_ERROR cannot be started due to device Error.\r
1949 @return EFI_OUT_OF_RESOURCES cannot allocate resources.\r
1950\r
1951**/\r
1952EFI_STATUS\r
1953EFIAPI\r
1954XhcDriverBindingStart (\r
1436aea4
MK
1955 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1956 IN EFI_HANDLE Controller,\r
1957 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
4b738c76
HT
1958 )\r
1959{\r
1436aea4
MK
1960 EFI_STATUS Status;\r
1961 EFI_PCI_IO_PROTOCOL *PciIo;\r
1962 UINT64 Supports;\r
1963 UINT64 OriginalPciAttributes;\r
1964 BOOLEAN PciAttributesSaved;\r
1965 USB_XHCI_INSTANCE *Xhc;\r
4b738c76
HT
1966 EFI_DEVICE_PATH_PROTOCOL *HcDevicePath;\r
1967\r
1968 //\r
1969 // Open the PciIo Protocol, then enable the USB host controller\r
1970 //\r
1971 Status = gBS->OpenProtocol (\r
1972 Controller,\r
1973 &gEfiPciIoProtocolGuid,\r
1436aea4 1974 (VOID **)&PciIo,\r
4b738c76
HT
1975 This->DriverBindingHandle,\r
1976 Controller,\r
1977 EFI_OPEN_PROTOCOL_BY_DRIVER\r
1978 );\r
1979\r
1980 if (EFI_ERROR (Status)) {\r
1981 return Status;\r
1982 }\r
1983\r
1984 //\r
1985 // Open Device Path Protocol for on USB host controller\r
1986 //\r
1987 HcDevicePath = NULL;\r
1436aea4
MK
1988 Status = gBS->OpenProtocol (\r
1989 Controller,\r
1990 &gEfiDevicePathProtocolGuid,\r
1991 (VOID **)&HcDevicePath,\r
1992 This->DriverBindingHandle,\r
1993 Controller,\r
1994 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1995 );\r
4b738c76
HT
1996\r
1997 PciAttributesSaved = FALSE;\r
1998 //\r
1999 // Save original PCI attributes\r
2000 //\r
2001 Status = PciIo->Attributes (\r
2002 PciIo,\r
2003 EfiPciIoAttributeOperationGet,\r
2004 0,\r
2005 &OriginalPciAttributes\r
2006 );\r
2007\r
2008 if (EFI_ERROR (Status)) {\r
2009 goto CLOSE_PCIIO;\r
2010 }\r
1436aea4 2011\r
4b738c76
HT
2012 PciAttributesSaved = TRUE;\r
2013\r
2014 Status = PciIo->Attributes (\r
2015 PciIo,\r
2016 EfiPciIoAttributeOperationSupported,\r
2017 0,\r
2018 &Supports\r
2019 );\r
2020 if (!EFI_ERROR (Status)) {\r
6e1e5405 2021 Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE;\r
1436aea4
MK
2022 Status = PciIo->Attributes (\r
2023 PciIo,\r
2024 EfiPciIoAttributeOperationEnable,\r
2025 Supports,\r
2026 NULL\r
2027 );\r
4b738c76
HT
2028 }\r
2029\r
2030 if (EFI_ERROR (Status)) {\r
87000d77 2031 DEBUG ((DEBUG_ERROR, "XhcDriverBindingStart: failed to enable controller\n"));\r
4b738c76
HT
2032 goto CLOSE_PCIIO;\r
2033 }\r
2034\r
2035 //\r
2036 // Create then install USB2_HC_PROTOCOL\r
2037 //\r
2038 Xhc = XhcCreateUsbHc (PciIo, HcDevicePath, OriginalPciAttributes);\r
2039\r
2040 if (Xhc == NULL) {\r
87000d77 2041 DEBUG ((DEBUG_ERROR, "XhcDriverBindingStart: failed to create USB2_HC\n"));\r
4b738c76
HT
2042 return EFI_OUT_OF_RESOURCES;\r
2043 }\r
2044\r
5c1b371a
AB
2045 //\r
2046 // Enable 64-bit DMA support in the PCI layer if this controller\r
2047 // supports it.\r
2048 //\r
2049 if (Xhc->HcCParams.Data.Ac64 != 0) {\r
2050 Status = PciIo->Attributes (\r
2051 PciIo,\r
2052 EfiPciIoAttributeOperationEnable,\r
2053 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE,\r
2054 NULL\r
2055 );\r
2056 if (!EFI_ERROR (Status)) {\r
2057 Xhc->Support64BitDma = TRUE;\r
2058 } else {\r
1436aea4
MK
2059 DEBUG ((\r
2060 DEBUG_WARN,\r
5c1b371a 2061 "%a: failed to enable 64-bit DMA on 64-bit capable controller @ %p (%r)\n",\r
1436aea4
MK
2062 __FUNCTION__,\r
2063 Controller,\r
2064 Status\r
2065 ));\r
5c1b371a
AB
2066 }\r
2067 }\r
2068\r
4b738c76
HT
2069 XhcSetBiosOwnership (Xhc);\r
2070\r
2071 XhcResetHC (Xhc, XHC_RESET_TIMEOUT);\r
2072 ASSERT (XhcIsHalt (Xhc));\r
2073\r
2074 //\r
2075 // After Chip Hardware Reset wait until the Controller Not Ready (CNR) flag\r
2076 // in the USBSTS is '0' before writing any xHC Operational or Runtime registers.\r
2077 //\r
2078 ASSERT (!(XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_CNR)));\r
2079\r
2080 //\r
2081 // Initialize the schedule\r
2082 //\r
2083 XhcInitSched (Xhc);\r
2084\r
2085 //\r
2086 // Start the Host Controller\r
2087 //\r
1436aea4 2088 XhcRunHC (Xhc, XHC_GENERIC_TIMEOUT);\r
4b738c76
HT
2089\r
2090 //\r
2091 // Start the asynchronous interrupt monitor\r
2092 //\r
2093 Status = gBS->SetTimer (Xhc->PollTimer, TimerPeriodic, XHC_ASYNC_TIMER_INTERVAL);\r
2094 if (EFI_ERROR (Status)) {\r
87000d77 2095 DEBUG ((DEBUG_ERROR, "XhcDriverBindingStart: failed to start async interrupt monitor\n"));\r
4b738c76
HT
2096 XhcHaltHC (Xhc, XHC_GENERIC_TIMEOUT);\r
2097 goto FREE_POOL;\r
2098 }\r
2099\r
2100 //\r
2101 // Create event to stop the HC when exit boot service.\r
2102 //\r
2103 Status = gBS->CreateEventEx (\r
2104 EVT_NOTIFY_SIGNAL,\r
2105 TPL_NOTIFY,\r
2106 XhcExitBootService,\r
2107 Xhc,\r
2108 &gEfiEventExitBootServicesGuid,\r
2109 &Xhc->ExitBootServiceEvent\r
2110 );\r
2111 if (EFI_ERROR (Status)) {\r
2112 goto FREE_POOL;\r
2113 }\r
2114\r
2115 //\r
2116 // Install the component name protocol, don't fail the start\r
2117 // because of something for display.\r
2118 //\r
2119 AddUnicodeString2 (\r
2120 "eng",\r
2121 gXhciComponentName.SupportedLanguages,\r
2122 &Xhc->ControllerNameTable,\r
2123 L"eXtensible Host Controller (USB 3.0)",\r
2124 TRUE\r
2125 );\r
2126 AddUnicodeString2 (\r
2127 "en",\r
2128 gXhciComponentName2.SupportedLanguages,\r
2129 &Xhc->ControllerNameTable,\r
2130 L"eXtensible Host Controller (USB 3.0)",\r
2131 FALSE\r
2132 );\r
2133\r
2134 Status = gBS->InstallProtocolInterface (\r
2135 &Controller,\r
2136 &gEfiUsb2HcProtocolGuid,\r
2137 EFI_NATIVE_INTERFACE,\r
2138 &Xhc->Usb2Hc\r
2139 );\r
2140 if (EFI_ERROR (Status)) {\r
87000d77 2141 DEBUG ((DEBUG_ERROR, "XhcDriverBindingStart: failed to install USB2_HC Protocol\n"));\r
4b738c76
HT
2142 goto FREE_POOL;\r
2143 }\r
2144\r
87000d77 2145 DEBUG ((DEBUG_INFO, "XhcDriverBindingStart: XHCI started for controller @ %x\n", Controller));\r
4b738c76
HT
2146 return EFI_SUCCESS;\r
2147\r
2148FREE_POOL:\r
2149 gBS->CloseEvent (Xhc->PollTimer);\r
2150 XhcFreeSched (Xhc);\r
2151 FreePool (Xhc);\r
2152\r
2153CLOSE_PCIIO:\r
2154 if (PciAttributesSaved) {\r
2155 //\r
2156 // Restore original PCI attributes\r
2157 //\r
2158 PciIo->Attributes (\r
1436aea4
MK
2159 PciIo,\r
2160 EfiPciIoAttributeOperationSet,\r
2161 OriginalPciAttributes,\r
2162 NULL\r
2163 );\r
4b738c76
HT
2164 }\r
2165\r
2166 gBS->CloseProtocol (\r
2167 Controller,\r
2168 &gEfiPciIoProtocolGuid,\r
2169 This->DriverBindingHandle,\r
2170 Controller\r
2171 );\r
2172\r
2173 return Status;\r
2174}\r
2175\r
4b738c76 2176/**\r
ed356b9e 2177 Stop this driver on ControllerHandle. Support stopping any child handles\r
4b738c76
HT
2178 created by this driver.\r
2179\r
2180 @param This Protocol instance pointer.\r
2181 @param Controller Handle of device to stop driver on.\r
2182 @param NumberOfChildren Number of Children in the ChildHandleBuffer.\r
2183 @param ChildHandleBuffer List of handles for the children we need to stop.\r
2184\r
2185 @return EFI_SUCCESS Success.\r
2186 @return EFI_DEVICE_ERROR Fail.\r
2187\r
2188**/\r
2189EFI_STATUS\r
2190EFIAPI\r
2191XhcDriverBindingStop (\r
1436aea4
MK
2192 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
2193 IN EFI_HANDLE Controller,\r
2194 IN UINTN NumberOfChildren,\r
2195 IN EFI_HANDLE *ChildHandleBuffer\r
4b738c76
HT
2196 )\r
2197{\r
2198 EFI_STATUS Status;\r
2199 EFI_USB2_HC_PROTOCOL *Usb2Hc;\r
2200 EFI_PCI_IO_PROTOCOL *PciIo;\r
2201 USB_XHCI_INSTANCE *Xhc;\r
2202 UINT8 Index;\r
2203\r
2204 //\r
2205 // Test whether the Controller handler passed in is a valid\r
2206 // Usb controller handle that should be supported, if not,\r
2207 // return the error status directly\r
2208 //\r
2209 Status = gBS->OpenProtocol (\r
2210 Controller,\r
2211 &gEfiUsb2HcProtocolGuid,\r
1436aea4 2212 (VOID **)&Usb2Hc,\r
4b738c76
HT
2213 This->DriverBindingHandle,\r
2214 Controller,\r
2215 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
2216 );\r
2217\r
2218 if (EFI_ERROR (Status)) {\r
2219 return Status;\r
2220 }\r
2221\r
2222 Status = gBS->UninstallProtocolInterface (\r
2223 Controller,\r
2224 &gEfiUsb2HcProtocolGuid,\r
2225 Usb2Hc\r
2226 );\r
2227\r
2228 if (EFI_ERROR (Status)) {\r
2229 return Status;\r
2230 }\r
2231\r
2232 Xhc = XHC_FROM_THIS (Usb2Hc);\r
2233 PciIo = Xhc->PciIo;\r
2234\r
2235 //\r
2236 // Stop AsyncRequest Polling timer then stop the XHCI driver\r
2237 // and uninstall the XHCI protocl.\r
2238 //\r
2239 gBS->SetTimer (Xhc->PollTimer, TimerCancel, 0);\r
2240\r
2241 //\r
2242 // Disable the device slots occupied by these devices on its downstream ports.\r
2243 // Entry 0 is reserved.\r
2244 //\r
2245 for (Index = 0; Index < 255; Index++) {\r
2246 if (!Xhc->UsbDevContext[Index + 1].Enabled ||\r
1436aea4
MK
2247 (Xhc->UsbDevContext[Index + 1].SlotId == 0))\r
2248 {\r
4b738c76
HT
2249 continue;\r
2250 }\r
1436aea4 2251\r
4b738c76
HT
2252 if (Xhc->HcCParams.Data.Csz == 0) {\r
2253 XhcDisableSlotCmd (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);\r
2254 } else {\r
2255 XhcDisableSlotCmd64 (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);\r
2256 }\r
2257 }\r
2258\r
2259 if (Xhc->PollTimer != NULL) {\r
2260 gBS->CloseEvent (Xhc->PollTimer);\r
2261 }\r
2262\r
2263 if (Xhc->ExitBootServiceEvent != NULL) {\r
2264 gBS->CloseEvent (Xhc->ExitBootServiceEvent);\r
2265 }\r
2266\r
2267 XhcHaltHC (Xhc, XHC_GENERIC_TIMEOUT);\r
2268 XhcClearBiosOwnership (Xhc);\r
2269 XhciDelAllAsyncIntTransfers (Xhc);\r
2270 XhcFreeSched (Xhc);\r
2271\r
2272 if (Xhc->ControllerNameTable) {\r
2273 FreeUnicodeStringTable (Xhc->ControllerNameTable);\r
2274 }\r
2275\r
2276 //\r
2277 // Restore original PCI attributes\r
2278 //\r
2279 PciIo->Attributes (\r
2280 PciIo,\r
2281 EfiPciIoAttributeOperationSet,\r
2282 Xhc->OriginalPciAttributes,\r
2283 NULL\r
2284 );\r
2285\r
2286 gBS->CloseProtocol (\r
2287 Controller,\r
2288 &gEfiPciIoProtocolGuid,\r
2289 This->DriverBindingHandle,\r
2290 Controller\r
2291 );\r
2292\r
2293 FreePool (Xhc);\r
2294\r
2295 return EFI_SUCCESS;\r
2296}\r