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