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