]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/XhciDxe/Xhci.c
MdeModulePkg/XhciDxe: Add access xHCI Extended Capabilities Pointer
[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
4b738c76
HT
1245\r
1246 //\r
1247 // Validate the parameters\r
1248 //\r
1249 if ((DataLength == NULL) || (*DataLength == 0) ||\r
1436aea4
MK
1250 (Data == NULL) || (Data[0] == NULL) || (TransferResult == NULL))\r
1251 {\r
4b738c76
HT
1252 return EFI_INVALID_PARAMETER;\r
1253 }\r
1254\r
1255 if ((*DataToggle != 0) && (*DataToggle != 1)) {\r
1256 return EFI_INVALID_PARAMETER;\r
1257 }\r
1258\r
1259 if ((DeviceSpeed == EFI_USB_SPEED_LOW) ||\r
1260 ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) ||\r
1261 ((EFI_USB_SPEED_HIGH == DeviceSpeed) && (MaximumPacketLength > 512)) ||\r
1436aea4
MK
1262 ((EFI_USB_SPEED_SUPER == DeviceSpeed) && (MaximumPacketLength > 1024)))\r
1263 {\r
4b738c76
HT
1264 return EFI_INVALID_PARAMETER;\r
1265 }\r
1266\r
1267 OldTpl = gBS->RaiseTPL (XHC_TPL);\r
1268\r
1436aea4 1269 Xhc = XHC_FROM_THIS (This);\r
4b738c76
HT
1270\r
1271 *TransferResult = EFI_USB_ERR_SYSTEM;\r
1272 Status = EFI_DEVICE_ERROR;\r
1273\r
1274 if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {\r
87000d77 1275 DEBUG ((DEBUG_ERROR, "XhcBulkTransfer: HC is halted\n"));\r
4b738c76
HT
1276 goto ON_EXIT;\r
1277 }\r
1278\r
1279 //\r
1280 // Check if the device is still enabled before every transaction.\r
1281 //\r
1282 SlotId = XhcBusDevAddrToSlotId (Xhc, DeviceAddress);\r
1283 if (SlotId == 0) {\r
1284 goto ON_EXIT;\r
1285 }\r
1286\r
1287 //\r
1288 // Create a new URB, insert it into the asynchronous\r
1289 // schedule list, then poll the execution status.\r
1290 //\r
41fb8ce9
RN
1291 Status = XhcTransfer (\r
1292 Xhc,\r
1293 DeviceAddress,\r
1294 EndPointAddress,\r
1295 DeviceSpeed,\r
1296 MaximumPacketLength,\r
1297 XHC_BULK_TRANSFER,\r
1298 NULL,\r
1299 Data[0],\r
1300 DataLength,\r
1301 Timeout,\r
1302 TransferResult\r
1303 );\r
4b738c76
HT
1304\r
1305ON_EXIT:\r
4b738c76 1306 if (EFI_ERROR (Status)) {\r
87000d77 1307 DEBUG ((DEBUG_ERROR, "XhcBulkTransfer: error - %r, transfer - %x\n", Status, *TransferResult));\r
4b738c76 1308 }\r
1436aea4 1309\r
4b738c76
HT
1310 gBS->RestoreTPL (OldTpl);\r
1311\r
1312 return Status;\r
1313}\r
1314\r
1315/**\r
1316 Submits an asynchronous interrupt transfer to an\r
1317 interrupt endpoint of a USB device.\r
1318\r
1319 @param This This EFI_USB2_HC_PROTOCOL instance.\r
1320 @param DeviceAddress Target device address.\r
1321 @param EndPointAddress Endpoint number and its direction encoded in bit 7\r
1322 @param DeviceSpeed Indicates device speed.\r
1323 @param MaximumPacketLength Maximum packet size the target endpoint is capable\r
1324 @param IsNewTransfer If TRUE, to submit an new asynchronous interrupt\r
1325 transfer If FALSE, to remove the specified\r
1326 asynchronous interrupt.\r
1327 @param DataToggle On input, the initial data toggle to use; on output,\r
1328 it is updated to indicate the next data toggle.\r
1329 @param PollingInterval The he interval, in milliseconds, that the transfer\r
1330 is polled.\r
1331 @param DataLength The length of data to receive at the rate specified\r
1332 by PollingInterval.\r
1333 @param Translator Transaction translator to use.\r
1334 @param CallBackFunction Function to call at the rate specified by\r
1335 PollingInterval.\r
1336 @param Context Context to CallBackFunction.\r
1337\r
1338 @retval EFI_SUCCESS The request has been successfully submitted or canceled.\r
1339 @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
1340 @retval EFI_OUT_OF_RESOURCES The request failed due to a lack of resources.\r
1341 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.\r
1342\r
1343**/\r
1344EFI_STATUS\r
1345EFIAPI\r
1346XhcAsyncInterruptTransfer (\r
1347 IN EFI_USB2_HC_PROTOCOL *This,\r
1348 IN UINT8 DeviceAddress,\r
1349 IN UINT8 EndPointAddress,\r
1350 IN UINT8 DeviceSpeed,\r
1351 IN UINTN MaximumPacketLength,\r
1352 IN BOOLEAN IsNewTransfer,\r
1353 IN OUT UINT8 *DataToggle,\r
1354 IN UINTN PollingInterval,\r
1355 IN UINTN DataLength,\r
1356 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,\r
1357 IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction,\r
1358 IN VOID *Context OPTIONAL\r
1359 )\r
1360{\r
1436aea4
MK
1361 USB_XHCI_INSTANCE *Xhc;\r
1362 URB *Urb;\r
1363 EFI_STATUS Status;\r
1364 UINT8 SlotId;\r
1365 UINT8 Index;\r
1366 EFI_TPL OldTpl;\r
4b738c76
HT
1367\r
1368 //\r
1369 // Validate parameters\r
1370 //\r
1371 if (!XHCI_IS_DATAIN (EndPointAddress)) {\r
1372 return EFI_INVALID_PARAMETER;\r
1373 }\r
1374\r
1375 if (IsNewTransfer) {\r
1376 if (DataLength == 0) {\r
1377 return EFI_INVALID_PARAMETER;\r
1378 }\r
1379\r
1380 if ((*DataToggle != 1) && (*DataToggle != 0)) {\r
1381 return EFI_INVALID_PARAMETER;\r
1382 }\r
1383\r
1384 if ((PollingInterval > 255) || (PollingInterval < 1)) {\r
1385 return EFI_INVALID_PARAMETER;\r
1386 }\r
1387 }\r
1388\r
1389 OldTpl = gBS->RaiseTPL (XHC_TPL);\r
1390\r
1436aea4 1391 Xhc = XHC_FROM_THIS (This);\r
4b738c76
HT
1392\r
1393 //\r
1394 // Delete Async interrupt transfer request.\r
1395 //\r
1396 if (!IsNewTransfer) {\r
1397 //\r
1398 // The delete request may happen after device is detached.\r
1399 //\r
1400 for (Index = 0; Index < 255; Index++) {\r
1401 if (Xhc->UsbDevContext[Index + 1].BusDevAddr == DeviceAddress) {\r
1402 break;\r
1403 }\r
1404 }\r
1405\r
1406 if (Index == 255) {\r
1407 Status = EFI_INVALID_PARAMETER;\r
1408 goto ON_EXIT;\r
1409 }\r
1410\r
1411 Status = XhciDelAsyncIntTransfer (Xhc, DeviceAddress, EndPointAddress);\r
87000d77 1412 DEBUG ((DEBUG_INFO, "XhcAsyncInterruptTransfer: remove old transfer for addr %d, Status = %r\n", DeviceAddress, Status));\r
4b738c76
HT
1413 goto ON_EXIT;\r
1414 }\r
1415\r
1416 Status = EFI_SUCCESS;\r
1417\r
1418 if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {\r
87000d77 1419 DEBUG ((DEBUG_ERROR, "XhcAsyncInterruptTransfer: HC is halt\n"));\r
4b738c76
HT
1420 Status = EFI_DEVICE_ERROR;\r
1421 goto ON_EXIT;\r
1422 }\r
1423\r
1424 //\r
1425 // Check if the device is still enabled before every transaction.\r
1426 //\r
1427 SlotId = XhcBusDevAddrToSlotId (Xhc, DeviceAddress);\r
1428 if (SlotId == 0) {\r
1429 goto ON_EXIT;\r
1430 }\r
1431\r
6681582d 1432 Urb = XhciInsertAsyncIntTransfer (\r
4b738c76
HT
1433 Xhc,\r
1434 DeviceAddress,\r
1435 EndPointAddress,\r
1436 DeviceSpeed,\r
1437 MaximumPacketLength,\r
4b738c76
HT
1438 DataLength,\r
1439 CallBackFunction,\r
1440 Context\r
1441 );\r
4b738c76 1442 if (Urb == NULL) {\r
4b738c76
HT
1443 Status = EFI_OUT_OF_RESOURCES;\r
1444 goto ON_EXIT;\r
1445 }\r
1446\r
4b738c76
HT
1447 //\r
1448 // Ring the doorbell\r
1449 //\r
1450 Status = RingIntTransferDoorBell (Xhc, Urb);\r
1451\r
1452ON_EXIT:\r
1453 Xhc->PciIo->Flush (Xhc->PciIo);\r
1454 gBS->RestoreTPL (OldTpl);\r
1455\r
1456 return Status;\r
1457}\r
1458\r
4b738c76
HT
1459/**\r
1460 Submits synchronous interrupt transfer to an interrupt endpoint\r
1461 of a USB device.\r
1462\r
1463 @param This This EFI_USB2_HC_PROTOCOL instance.\r
1464 @param DeviceAddress Target device address.\r
1465 @param EndPointAddress Endpoint number and its direction encoded in bit 7\r
1466 @param DeviceSpeed Indicates device speed.\r
1467 @param MaximumPacketLength Maximum packet size the target endpoint is capable\r
1468 of sending or receiving.\r
1469 @param Data Buffer of data that will be transmitted to USB\r
1470 device or received from USB device.\r
1471 @param DataLength On input, the size, in bytes, of the data buffer; On\r
1472 output, the number of bytes transferred.\r
1473 @param DataToggle On input, the initial data toggle to use; on output,\r
1474 it is updated to indicate the next data toggle.\r
1475 @param Timeout Maximum time, in second, to complete.\r
1476 @param Translator Transaction translator to use.\r
1477 @param TransferResult Variable to receive the transfer result.\r
1478\r
1479 @return EFI_SUCCESS The transfer was completed successfully.\r
1480 @return EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.\r
1481 @return EFI_INVALID_PARAMETER Some parameters are invalid.\r
1482 @return EFI_TIMEOUT The transfer failed due to timeout.\r
1483 @return EFI_DEVICE_ERROR The failed due to host controller or device error\r
1484\r
1485**/\r
1486EFI_STATUS\r
1487EFIAPI\r
1488XhcSyncInterruptTransfer (\r
1489 IN EFI_USB2_HC_PROTOCOL *This,\r
1490 IN UINT8 DeviceAddress,\r
1491 IN UINT8 EndPointAddress,\r
1492 IN UINT8 DeviceSpeed,\r
1493 IN UINTN MaximumPacketLength,\r
1494 IN OUT VOID *Data,\r
1495 IN OUT UINTN *DataLength,\r
1496 IN OUT UINT8 *DataToggle,\r
1497 IN UINTN Timeout,\r
1498 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,\r
1499 OUT UINT32 *TransferResult\r
1500 )\r
1501{\r
1436aea4
MK
1502 USB_XHCI_INSTANCE *Xhc;\r
1503 UINT8 SlotId;\r
1504 EFI_STATUS Status;\r
1505 EFI_TPL OldTpl;\r
4b738c76
HT
1506\r
1507 //\r
1508 // Validates parameters\r
1509 //\r
1510 if ((DataLength == NULL) || (*DataLength == 0) ||\r
1436aea4
MK
1511 (Data == NULL) || (TransferResult == NULL))\r
1512 {\r
4b738c76
HT
1513 return EFI_INVALID_PARAMETER;\r
1514 }\r
1515\r
4b738c76
HT
1516 if ((*DataToggle != 1) && (*DataToggle != 0)) {\r
1517 return EFI_INVALID_PARAMETER;\r
1518 }\r
1519\r
1520 if (((DeviceSpeed == EFI_USB_SPEED_LOW) && (MaximumPacketLength != 8)) ||\r
1521 ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) ||\r
1436aea4
MK
1522 ((DeviceSpeed == EFI_USB_SPEED_HIGH) && (MaximumPacketLength > 3072)))\r
1523 {\r
4b738c76
HT
1524 return EFI_INVALID_PARAMETER;\r
1525 }\r
1526\r
1527 OldTpl = gBS->RaiseTPL (XHC_TPL);\r
1528\r
1436aea4 1529 Xhc = XHC_FROM_THIS (This);\r
4b738c76
HT
1530\r
1531 *TransferResult = EFI_USB_ERR_SYSTEM;\r
1532 Status = EFI_DEVICE_ERROR;\r
1533\r
1534 if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {\r
87000d77 1535 DEBUG ((DEBUG_ERROR, "EhcSyncInterruptTransfer: HC is halt\n"));\r
4b738c76
HT
1536 goto ON_EXIT;\r
1537 }\r
1538\r
1539 //\r
1540 // Check if the device is still enabled before every transaction.\r
1541 //\r
1542 SlotId = XhcBusDevAddrToSlotId (Xhc, DeviceAddress);\r
1543 if (SlotId == 0) {\r
1544 goto ON_EXIT;\r
1545 }\r
1546\r
41fb8ce9
RN
1547 Status = XhcTransfer (\r
1548 Xhc,\r
1549 DeviceAddress,\r
1550 EndPointAddress,\r
1551 DeviceSpeed,\r
1552 MaximumPacketLength,\r
1553 XHC_INT_TRANSFER_SYNC,\r
1554 NULL,\r
1555 Data,\r
1556 DataLength,\r
1557 Timeout,\r
1558 TransferResult\r
1559 );\r
4b738c76
HT
1560\r
1561ON_EXIT:\r
1562 if (EFI_ERROR (Status)) {\r
87000d77 1563 DEBUG ((DEBUG_ERROR, "XhcSyncInterruptTransfer: error - %r, transfer - %x\n", Status, *TransferResult));\r
4b738c76 1564 }\r
1436aea4 1565\r
4b738c76
HT
1566 gBS->RestoreTPL (OldTpl);\r
1567\r
1568 return Status;\r
1569}\r
1570\r
4b738c76
HT
1571/**\r
1572 Submits isochronous transfer to a target USB device.\r
1573\r
1574 @param This This EFI_USB2_HC_PROTOCOL instance.\r
1575 @param DeviceAddress Target device address.\r
1576 @param EndPointAddress End point address with its direction.\r
1577 @param DeviceSpeed Device speed, Low speed device doesn't support this\r
1578 type.\r
1579 @param MaximumPacketLength Maximum packet size that the endpoint is capable of\r
1580 sending or receiving.\r
1581 @param DataBuffersNumber Number of data buffers prepared for the transfer.\r
1582 @param Data Array of pointers to the buffers of data that will\r
1583 be transmitted to USB device or received from USB\r
1584 device.\r
1585 @param DataLength The size, in bytes, of the data buffer.\r
1586 @param Translator Transaction translator to use.\r
1587 @param TransferResult Variable to receive the transfer result.\r
1588\r
1589 @return EFI_UNSUPPORTED Isochronous transfer is unsupported.\r
1590\r
1591**/\r
1592EFI_STATUS\r
1593EFIAPI\r
1594XhcIsochronousTransfer (\r
1595 IN EFI_USB2_HC_PROTOCOL *This,\r
1596 IN UINT8 DeviceAddress,\r
1597 IN UINT8 EndPointAddress,\r
1598 IN UINT8 DeviceSpeed,\r
1599 IN UINTN MaximumPacketLength,\r
1600 IN UINT8 DataBuffersNumber,\r
1601 IN OUT VOID *Data[EFI_USB_MAX_ISO_BUFFER_NUM],\r
1602 IN UINTN DataLength,\r
1603 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,\r
1604 OUT UINT32 *TransferResult\r
1605 )\r
1606{\r
1607 return EFI_UNSUPPORTED;\r
1608}\r
1609\r
4b738c76
HT
1610/**\r
1611 Submits Async isochronous transfer to a target USB device.\r
1612\r
1613 @param This This EFI_USB2_HC_PROTOCOL instance.\r
1614 @param DeviceAddress Target device address.\r
1615 @param EndPointAddress End point address with its direction.\r
1616 @param DeviceSpeed Device speed, Low speed device doesn't support this\r
1617 type.\r
1618 @param MaximumPacketLength Maximum packet size that the endpoint is capable of\r
1619 sending or receiving.\r
1620 @param DataBuffersNumber Number of data buffers prepared for the transfer.\r
1621 @param Data Array of pointers to the buffers of data that will\r
1622 be transmitted to USB device or received from USB\r
1623 device.\r
1624 @param DataLength The size, in bytes, of the data buffer.\r
1625 @param Translator Transaction translator to use.\r
1626 @param IsochronousCallBack Function to be called when the transfer complete.\r
1627 @param Context Context passed to the call back function as\r
1628 parameter.\r
1629\r
1630 @return EFI_UNSUPPORTED Isochronous transfer isn't supported.\r
1631\r
1632**/\r
1633EFI_STATUS\r
1634EFIAPI\r
1635XhcAsyncIsochronousTransfer (\r
1636 IN EFI_USB2_HC_PROTOCOL *This,\r
1637 IN UINT8 DeviceAddress,\r
1638 IN UINT8 EndPointAddress,\r
1639 IN UINT8 DeviceSpeed,\r
1640 IN UINTN MaximumPacketLength,\r
1641 IN UINT8 DataBuffersNumber,\r
1642 IN OUT VOID *Data[EFI_USB_MAX_ISO_BUFFER_NUM],\r
1643 IN UINTN DataLength,\r
1644 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,\r
1645 IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack,\r
1646 IN VOID *Context\r
1647 )\r
1648{\r
1649 return EFI_UNSUPPORTED;\r
1650}\r
1651\r
1652/**\r
1653 Entry point for EFI drivers.\r
1654\r
1655 @param ImageHandle EFI_HANDLE.\r
1656 @param SystemTable EFI_SYSTEM_TABLE.\r
1657\r
1658 @retval EFI_SUCCESS Success.\r
1659 @retval Others Fail.\r
1660\r
1661**/\r
1662EFI_STATUS\r
1663EFIAPI\r
1664XhcDriverEntryPoint (\r
1436aea4
MK
1665 IN EFI_HANDLE ImageHandle,\r
1666 IN EFI_SYSTEM_TABLE *SystemTable\r
4b738c76
HT
1667 )\r
1668{\r
1669 return EfiLibInstallDriverBindingComponentName2 (\r
1670 ImageHandle,\r
1671 SystemTable,\r
1672 &gXhciDriverBinding,\r
1673 ImageHandle,\r
1674 &gXhciComponentName,\r
1675 &gXhciComponentName2\r
1676 );\r
1677}\r
1678\r
4b738c76
HT
1679/**\r
1680 Test to see if this driver supports ControllerHandle. Any\r
1681 ControllerHandle that has Usb2HcProtocol installed will\r
1682 be supported.\r
1683\r
1684 @param This Protocol instance pointer.\r
1685 @param Controller Handle of device to test.\r
1686 @param RemainingDevicePath Not used.\r
1687\r
1688 @return EFI_SUCCESS This driver supports this device.\r
1689 @return EFI_UNSUPPORTED This driver does not support this device.\r
1690\r
1691**/\r
1692EFI_STATUS\r
1693EFIAPI\r
1694XhcDriverBindingSupported (\r
1436aea4
MK
1695 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1696 IN EFI_HANDLE Controller,\r
1697 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
4b738c76
HT
1698 )\r
1699{\r
1436aea4
MK
1700 EFI_STATUS Status;\r
1701 EFI_PCI_IO_PROTOCOL *PciIo;\r
1702 USB_CLASSC UsbClassCReg;\r
4b738c76
HT
1703\r
1704 //\r
1705 // Test whether there is PCI IO Protocol attached on the controller handle.\r
1706 //\r
1707 Status = gBS->OpenProtocol (\r
1708 Controller,\r
1709 &gEfiPciIoProtocolGuid,\r
1436aea4 1710 (VOID **)&PciIo,\r
4b738c76
HT
1711 This->DriverBindingHandle,\r
1712 Controller,\r
1713 EFI_OPEN_PROTOCOL_BY_DRIVER\r
1714 );\r
1715\r
1716 if (EFI_ERROR (Status)) {\r
1717 return EFI_UNSUPPORTED;\r
1718 }\r
1719\r
1720 Status = PciIo->Pci.Read (\r
1721 PciIo,\r
1722 EfiPciIoWidthUint8,\r
1723 PCI_CLASSCODE_OFFSET,\r
1724 sizeof (USB_CLASSC) / sizeof (UINT8),\r
1725 &UsbClassCReg\r
1726 );\r
1727\r
1728 if (EFI_ERROR (Status)) {\r
1729 Status = EFI_UNSUPPORTED;\r
1730 goto ON_EXIT;\r
1731 }\r
1732\r
1733 //\r
1734 // Test whether the controller belongs to Xhci type\r
1735 //\r
1736 if ((UsbClassCReg.BaseCode != PCI_CLASS_SERIAL) ||\r
1737 (UsbClassCReg.SubClassCode != PCI_CLASS_SERIAL_USB) ||\r
1436aea4
MK
1738 (UsbClassCReg.ProgInterface != PCI_IF_XHCI))\r
1739 {\r
4b738c76
HT
1740 Status = EFI_UNSUPPORTED;\r
1741 }\r
1742\r
1743ON_EXIT:\r
1744 gBS->CloseProtocol (\r
1745 Controller,\r
1746 &gEfiPciIoProtocolGuid,\r
1747 This->DriverBindingHandle,\r
1748 Controller\r
1749 );\r
1750\r
1751 return Status;\r
1752}\r
1753\r
1754/**\r
1755 Create and initialize a USB_XHCI_INSTANCE structure.\r
1756\r
1757 @param PciIo The PciIo on this device.\r
1758 @param DevicePath The device path of host controller.\r
1759 @param OriginalPciAttributes Original PCI attributes.\r
1760\r
1761 @return The allocated and initialized USB_XHCI_INSTANCE structure if created,\r
1762 otherwise NULL.\r
1763\r
1764**/\r
1436aea4 1765USB_XHCI_INSTANCE *\r
4b738c76
HT
1766XhcCreateUsbHc (\r
1767 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1768 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
1769 IN UINT64 OriginalPciAttributes\r
1770 )\r
1771{\r
1436aea4
MK
1772 USB_XHCI_INSTANCE *Xhc;\r
1773 EFI_STATUS Status;\r
1774 UINT32 PageSize;\r
1775 UINT16 ExtCapReg;\r
1776 UINT8 ReleaseNumber;\r
4b738c76
HT
1777\r
1778 Xhc = AllocateZeroPool (sizeof (USB_XHCI_INSTANCE));\r
1779\r
1780 if (Xhc == NULL) {\r
1781 return NULL;\r
1782 }\r
1783\r
1784 //\r
1785 // Initialize private data structure\r
1786 //\r
1787 Xhc->Signature = XHCI_INSTANCE_SIG;\r
1788 Xhc->PciIo = PciIo;\r
1789 Xhc->DevicePath = DevicePath;\r
1790 Xhc->OriginalPciAttributes = OriginalPciAttributes;\r
1791 CopyMem (&Xhc->Usb2Hc, &gXhciUsb2HcTemplate, sizeof (EFI_USB2_HC_PROTOCOL));\r
1792\r
fed6cf25
SZ
1793 Status = PciIo->Pci.Read (\r
1794 PciIo,\r
1795 EfiPciIoWidthUint8,\r
1796 XHC_PCI_SBRN_OFFSET,\r
1797 1,\r
1798 &ReleaseNumber\r
1799 );\r
1800\r
1801 if (!EFI_ERROR (Status)) {\r
1802 Xhc->Usb2Hc.MajorRevision = (ReleaseNumber & 0xF0) >> 4;\r
1803 Xhc->Usb2Hc.MinorRevision = (ReleaseNumber & 0x0F);\r
1804 }\r
1805\r
4b738c76
HT
1806 InitializeListHead (&Xhc->AsyncIntTransfers);\r
1807\r
1808 //\r
1809 // Be caution that the Offset passed to XhcReadCapReg() should be Dword align\r
1810 //\r
1811 Xhc->CapLength = XhcReadCapReg8 (Xhc, XHC_CAPLENGTH_OFFSET);\r
1812 Xhc->HcSParams1.Dword = XhcReadCapReg (Xhc, XHC_HCSPARAMS1_OFFSET);\r
1813 Xhc->HcSParams2.Dword = XhcReadCapReg (Xhc, XHC_HCSPARAMS2_OFFSET);\r
1814 Xhc->HcCParams.Dword = XhcReadCapReg (Xhc, XHC_HCCPARAMS_OFFSET);\r
1815 Xhc->DBOff = XhcReadCapReg (Xhc, XHC_DBOFF_OFFSET);\r
1816 Xhc->RTSOff = XhcReadCapReg (Xhc, XHC_RTSOFF_OFFSET);\r
1817\r
1818 //\r
1819 // This PageSize field defines the page size supported by the xHC implementation.\r
1820 // This xHC supports a page size of 2^(n+12) if bit n is Set. For example,\r
1821 // if bit 0 is Set, the xHC supports 4k byte page sizes.\r
1822 //\r
b97243de
LH
1823 PageSize = XhcReadOpReg (Xhc, XHC_PAGESIZE_OFFSET);\r
1824 if ((PageSize & (~XHC_PAGESIZE_MASK)) != 0) {\r
1825 DEBUG ((DEBUG_ERROR, "XhcCreateUsb3Hc: Reserved bits are not 0 for PageSize\n"));\r
1826 goto ON_ERROR;\r
1827 }\r
1828\r
1829 PageSize &= XHC_PAGESIZE_MASK;\r
1436aea4 1830 Xhc->PageSize = 1 << (HighBitSet32 (PageSize) + 12);\r
4b738c76 1831\r
1436aea4
MK
1832 ExtCapReg = (UINT16)(Xhc->HcCParams.Data.ExtCapReg);\r
1833 Xhc->ExtCapRegBase = ExtCapReg << 2;\r
1834 Xhc->UsbLegSupOffset = XhcGetCapabilityAddr (Xhc, XHC_CAP_USB_LEGACY);\r
4b738c76 1835 Xhc->DebugCapSupOffset = XhcGetCapabilityAddr (Xhc, XHC_CAP_USB_DEBUG);\r
7f4eca4c
IC
1836 Xhc->Usb2SupOffset = XhcGetSupportedProtocolCapabilityAddr (Xhc, XHC_SUPPORTED_PROTOCOL_DW0_MAJOR_REVISION_USB2);\r
1837 Xhc->Usb3SupOffset = XhcGetSupportedProtocolCapabilityAddr (Xhc, XHC_SUPPORTED_PROTOCOL_DW0_MAJOR_REVISION_USB3);\r
4b738c76 1838\r
87000d77
MK
1839 DEBUG ((DEBUG_INFO, "XhcCreateUsb3Hc: Capability length 0x%x\n", Xhc->CapLength));\r
1840 DEBUG ((DEBUG_INFO, "XhcCreateUsb3Hc: HcSParams1 0x%x\n", Xhc->HcSParams1));\r
1841 DEBUG ((DEBUG_INFO, "XhcCreateUsb3Hc: HcSParams2 0x%x\n", Xhc->HcSParams2));\r
1842 DEBUG ((DEBUG_INFO, "XhcCreateUsb3Hc: HcCParams 0x%x\n", Xhc->HcCParams));\r
1843 DEBUG ((DEBUG_INFO, "XhcCreateUsb3Hc: DBOff 0x%x\n", Xhc->DBOff));\r
1844 DEBUG ((DEBUG_INFO, "XhcCreateUsb3Hc: RTSOff 0x%x\n", Xhc->RTSOff));\r
1845 DEBUG ((DEBUG_INFO, "XhcCreateUsb3Hc: UsbLegSupOffset 0x%x\n", Xhc->UsbLegSupOffset));\r
1846 DEBUG ((DEBUG_INFO, "XhcCreateUsb3Hc: DebugCapSupOffset 0x%x\n", Xhc->DebugCapSupOffset));\r
7f4eca4c
IC
1847 DEBUG ((DEBUG_INFO, "XhcCreateUsb3Hc: Usb2SupOffset 0x%x\n", Xhc->Usb2SupOffset));\r
1848 DEBUG ((DEBUG_INFO, "XhcCreateUsb3Hc: Usb3SupOffset 0x%x\n", Xhc->Usb3SupOffset));\r
4b738c76
HT
1849\r
1850 //\r
1851 // Create AsyncRequest Polling Timer\r
1852 //\r
1853 Status = gBS->CreateEvent (\r
1854 EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
3cf6450e 1855 TPL_NOTIFY,\r
4b738c76
HT
1856 XhcMonitorAsyncRequests,\r
1857 Xhc,\r
1858 &Xhc->PollTimer\r
1859 );\r
1860\r
1861 if (EFI_ERROR (Status)) {\r
1862 goto ON_ERROR;\r
1863 }\r
1864\r
1865 return Xhc;\r
1866\r
1867ON_ERROR:\r
1868 FreePool (Xhc);\r
1869 return NULL;\r
1870}\r
1871\r
1872/**\r
1873 One notified function to stop the Host Controller when gBS->ExitBootServices() called.\r
1874\r
1875 @param Event Pointer to this event\r
e3644786 1876 @param Context Event handler private data\r
4b738c76
HT
1877\r
1878**/\r
1879VOID\r
1880EFIAPI\r
1881XhcExitBootService (\r
1882 EFI_EVENT Event,\r
1883 VOID *Context\r
1884 )\r
1885\r
1886{\r
1887 USB_XHCI_INSTANCE *Xhc;\r
1888 EFI_PCI_IO_PROTOCOL *PciIo;\r
1889\r
1436aea4 1890 Xhc = (USB_XHCI_INSTANCE *)Context;\r
4b738c76
HT
1891 PciIo = Xhc->PciIo;\r
1892\r
1893 //\r
1894 // Stop AsyncRequest Polling timer then stop the XHCI driver\r
1895 // and uninstall the XHCI protocl.\r
1896 //\r
1897 gBS->SetTimer (Xhc->PollTimer, TimerCancel, 0);\r
1898 XhcHaltHC (Xhc, XHC_GENERIC_TIMEOUT);\r
1899\r
1900 if (Xhc->PollTimer != NULL) {\r
1901 gBS->CloseEvent (Xhc->PollTimer);\r
1902 }\r
1903\r
1904 XhcClearBiosOwnership (Xhc);\r
1905\r
1906 //\r
1907 // Restore original PCI attributes\r
1908 //\r
1909 PciIo->Attributes (\r
1436aea4
MK
1910 PciIo,\r
1911 EfiPciIoAttributeOperationSet,\r
1912 Xhc->OriginalPciAttributes,\r
1913 NULL\r
1914 );\r
4b738c76
HT
1915}\r
1916\r
1917/**\r
1918 Starting the Usb XHCI Driver.\r
1919\r
1920 @param This Protocol instance pointer.\r
1921 @param Controller Handle of device to test.\r
1922 @param RemainingDevicePath Not used.\r
1923\r
1924 @return EFI_SUCCESS supports this device.\r
1925 @return EFI_UNSUPPORTED do not support this device.\r
1926 @return EFI_DEVICE_ERROR cannot be started due to device Error.\r
1927 @return EFI_OUT_OF_RESOURCES cannot allocate resources.\r
1928\r
1929**/\r
1930EFI_STATUS\r
1931EFIAPI\r
1932XhcDriverBindingStart (\r
1436aea4
MK
1933 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1934 IN EFI_HANDLE Controller,\r
1935 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
4b738c76
HT
1936 )\r
1937{\r
1436aea4
MK
1938 EFI_STATUS Status;\r
1939 EFI_PCI_IO_PROTOCOL *PciIo;\r
1940 UINT64 Supports;\r
1941 UINT64 OriginalPciAttributes;\r
1942 BOOLEAN PciAttributesSaved;\r
1943 USB_XHCI_INSTANCE *Xhc;\r
4b738c76
HT
1944 EFI_DEVICE_PATH_PROTOCOL *HcDevicePath;\r
1945\r
1946 //\r
1947 // Open the PciIo Protocol, then enable the USB host controller\r
1948 //\r
1949 Status = gBS->OpenProtocol (\r
1950 Controller,\r
1951 &gEfiPciIoProtocolGuid,\r
1436aea4 1952 (VOID **)&PciIo,\r
4b738c76
HT
1953 This->DriverBindingHandle,\r
1954 Controller,\r
1955 EFI_OPEN_PROTOCOL_BY_DRIVER\r
1956 );\r
1957\r
1958 if (EFI_ERROR (Status)) {\r
1959 return Status;\r
1960 }\r
1961\r
1962 //\r
1963 // Open Device Path Protocol for on USB host controller\r
1964 //\r
1965 HcDevicePath = NULL;\r
1436aea4
MK
1966 Status = gBS->OpenProtocol (\r
1967 Controller,\r
1968 &gEfiDevicePathProtocolGuid,\r
1969 (VOID **)&HcDevicePath,\r
1970 This->DriverBindingHandle,\r
1971 Controller,\r
1972 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1973 );\r
4b738c76
HT
1974\r
1975 PciAttributesSaved = FALSE;\r
1976 //\r
1977 // Save original PCI attributes\r
1978 //\r
1979 Status = PciIo->Attributes (\r
1980 PciIo,\r
1981 EfiPciIoAttributeOperationGet,\r
1982 0,\r
1983 &OriginalPciAttributes\r
1984 );\r
1985\r
1986 if (EFI_ERROR (Status)) {\r
1987 goto CLOSE_PCIIO;\r
1988 }\r
1436aea4 1989\r
4b738c76
HT
1990 PciAttributesSaved = TRUE;\r
1991\r
1992 Status = PciIo->Attributes (\r
1993 PciIo,\r
1994 EfiPciIoAttributeOperationSupported,\r
1995 0,\r
1996 &Supports\r
1997 );\r
1998 if (!EFI_ERROR (Status)) {\r
6e1e5405 1999 Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE;\r
1436aea4
MK
2000 Status = PciIo->Attributes (\r
2001 PciIo,\r
2002 EfiPciIoAttributeOperationEnable,\r
2003 Supports,\r
2004 NULL\r
2005 );\r
4b738c76
HT
2006 }\r
2007\r
2008 if (EFI_ERROR (Status)) {\r
87000d77 2009 DEBUG ((DEBUG_ERROR, "XhcDriverBindingStart: failed to enable controller\n"));\r
4b738c76
HT
2010 goto CLOSE_PCIIO;\r
2011 }\r
2012\r
2013 //\r
2014 // Create then install USB2_HC_PROTOCOL\r
2015 //\r
2016 Xhc = XhcCreateUsbHc (PciIo, HcDevicePath, OriginalPciAttributes);\r
2017\r
2018 if (Xhc == NULL) {\r
87000d77 2019 DEBUG ((DEBUG_ERROR, "XhcDriverBindingStart: failed to create USB2_HC\n"));\r
4b738c76
HT
2020 return EFI_OUT_OF_RESOURCES;\r
2021 }\r
2022\r
5c1b371a
AB
2023 //\r
2024 // Enable 64-bit DMA support in the PCI layer if this controller\r
2025 // supports it.\r
2026 //\r
2027 if (Xhc->HcCParams.Data.Ac64 != 0) {\r
2028 Status = PciIo->Attributes (\r
2029 PciIo,\r
2030 EfiPciIoAttributeOperationEnable,\r
2031 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE,\r
2032 NULL\r
2033 );\r
2034 if (!EFI_ERROR (Status)) {\r
2035 Xhc->Support64BitDma = TRUE;\r
2036 } else {\r
1436aea4
MK
2037 DEBUG ((\r
2038 DEBUG_WARN,\r
5c1b371a 2039 "%a: failed to enable 64-bit DMA on 64-bit capable controller @ %p (%r)\n",\r
1436aea4
MK
2040 __FUNCTION__,\r
2041 Controller,\r
2042 Status\r
2043 ));\r
5c1b371a
AB
2044 }\r
2045 }\r
2046\r
4b738c76
HT
2047 XhcSetBiosOwnership (Xhc);\r
2048\r
2049 XhcResetHC (Xhc, XHC_RESET_TIMEOUT);\r
2050 ASSERT (XhcIsHalt (Xhc));\r
2051\r
2052 //\r
2053 // After Chip Hardware Reset wait until the Controller Not Ready (CNR) flag\r
2054 // in the USBSTS is '0' before writing any xHC Operational or Runtime registers.\r
2055 //\r
2056 ASSERT (!(XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_CNR)));\r
2057\r
2058 //\r
2059 // Initialize the schedule\r
2060 //\r
2061 XhcInitSched (Xhc);\r
2062\r
2063 //\r
2064 // Start the Host Controller\r
2065 //\r
1436aea4 2066 XhcRunHC (Xhc, XHC_GENERIC_TIMEOUT);\r
4b738c76
HT
2067\r
2068 //\r
2069 // Start the asynchronous interrupt monitor\r
2070 //\r
2071 Status = gBS->SetTimer (Xhc->PollTimer, TimerPeriodic, XHC_ASYNC_TIMER_INTERVAL);\r
2072 if (EFI_ERROR (Status)) {\r
87000d77 2073 DEBUG ((DEBUG_ERROR, "XhcDriverBindingStart: failed to start async interrupt monitor\n"));\r
4b738c76
HT
2074 XhcHaltHC (Xhc, XHC_GENERIC_TIMEOUT);\r
2075 goto FREE_POOL;\r
2076 }\r
2077\r
2078 //\r
2079 // Create event to stop the HC when exit boot service.\r
2080 //\r
2081 Status = gBS->CreateEventEx (\r
2082 EVT_NOTIFY_SIGNAL,\r
2083 TPL_NOTIFY,\r
2084 XhcExitBootService,\r
2085 Xhc,\r
2086 &gEfiEventExitBootServicesGuid,\r
2087 &Xhc->ExitBootServiceEvent\r
2088 );\r
2089 if (EFI_ERROR (Status)) {\r
2090 goto FREE_POOL;\r
2091 }\r
2092\r
2093 //\r
2094 // Install the component name protocol, don't fail the start\r
2095 // because of something for display.\r
2096 //\r
2097 AddUnicodeString2 (\r
2098 "eng",\r
2099 gXhciComponentName.SupportedLanguages,\r
2100 &Xhc->ControllerNameTable,\r
2101 L"eXtensible Host Controller (USB 3.0)",\r
2102 TRUE\r
2103 );\r
2104 AddUnicodeString2 (\r
2105 "en",\r
2106 gXhciComponentName2.SupportedLanguages,\r
2107 &Xhc->ControllerNameTable,\r
2108 L"eXtensible Host Controller (USB 3.0)",\r
2109 FALSE\r
2110 );\r
2111\r
2112 Status = gBS->InstallProtocolInterface (\r
2113 &Controller,\r
2114 &gEfiUsb2HcProtocolGuid,\r
2115 EFI_NATIVE_INTERFACE,\r
2116 &Xhc->Usb2Hc\r
2117 );\r
2118 if (EFI_ERROR (Status)) {\r
87000d77 2119 DEBUG ((DEBUG_ERROR, "XhcDriverBindingStart: failed to install USB2_HC Protocol\n"));\r
4b738c76
HT
2120 goto FREE_POOL;\r
2121 }\r
2122\r
87000d77 2123 DEBUG ((DEBUG_INFO, "XhcDriverBindingStart: XHCI started for controller @ %x\n", Controller));\r
4b738c76
HT
2124 return EFI_SUCCESS;\r
2125\r
2126FREE_POOL:\r
2127 gBS->CloseEvent (Xhc->PollTimer);\r
2128 XhcFreeSched (Xhc);\r
2129 FreePool (Xhc);\r
2130\r
2131CLOSE_PCIIO:\r
2132 if (PciAttributesSaved) {\r
2133 //\r
2134 // Restore original PCI attributes\r
2135 //\r
2136 PciIo->Attributes (\r
1436aea4
MK
2137 PciIo,\r
2138 EfiPciIoAttributeOperationSet,\r
2139 OriginalPciAttributes,\r
2140 NULL\r
2141 );\r
4b738c76
HT
2142 }\r
2143\r
2144 gBS->CloseProtocol (\r
2145 Controller,\r
2146 &gEfiPciIoProtocolGuid,\r
2147 This->DriverBindingHandle,\r
2148 Controller\r
2149 );\r
2150\r
2151 return Status;\r
2152}\r
2153\r
4b738c76 2154/**\r
ed356b9e 2155 Stop this driver on ControllerHandle. Support stopping any child handles\r
4b738c76
HT
2156 created by this driver.\r
2157\r
2158 @param This Protocol instance pointer.\r
2159 @param Controller Handle of device to stop driver on.\r
2160 @param NumberOfChildren Number of Children in the ChildHandleBuffer.\r
2161 @param ChildHandleBuffer List of handles for the children we need to stop.\r
2162\r
2163 @return EFI_SUCCESS Success.\r
2164 @return EFI_DEVICE_ERROR Fail.\r
2165\r
2166**/\r
2167EFI_STATUS\r
2168EFIAPI\r
2169XhcDriverBindingStop (\r
1436aea4
MK
2170 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
2171 IN EFI_HANDLE Controller,\r
2172 IN UINTN NumberOfChildren,\r
2173 IN EFI_HANDLE *ChildHandleBuffer\r
4b738c76
HT
2174 )\r
2175{\r
2176 EFI_STATUS Status;\r
2177 EFI_USB2_HC_PROTOCOL *Usb2Hc;\r
2178 EFI_PCI_IO_PROTOCOL *PciIo;\r
2179 USB_XHCI_INSTANCE *Xhc;\r
2180 UINT8 Index;\r
2181\r
2182 //\r
2183 // Test whether the Controller handler passed in is a valid\r
2184 // Usb controller handle that should be supported, if not,\r
2185 // return the error status directly\r
2186 //\r
2187 Status = gBS->OpenProtocol (\r
2188 Controller,\r
2189 &gEfiUsb2HcProtocolGuid,\r
1436aea4 2190 (VOID **)&Usb2Hc,\r
4b738c76
HT
2191 This->DriverBindingHandle,\r
2192 Controller,\r
2193 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
2194 );\r
2195\r
2196 if (EFI_ERROR (Status)) {\r
2197 return Status;\r
2198 }\r
2199\r
2200 Status = gBS->UninstallProtocolInterface (\r
2201 Controller,\r
2202 &gEfiUsb2HcProtocolGuid,\r
2203 Usb2Hc\r
2204 );\r
2205\r
2206 if (EFI_ERROR (Status)) {\r
2207 return Status;\r
2208 }\r
2209\r
2210 Xhc = XHC_FROM_THIS (Usb2Hc);\r
2211 PciIo = Xhc->PciIo;\r
2212\r
2213 //\r
2214 // Stop AsyncRequest Polling timer then stop the XHCI driver\r
2215 // and uninstall the XHCI protocl.\r
2216 //\r
2217 gBS->SetTimer (Xhc->PollTimer, TimerCancel, 0);\r
2218\r
2219 //\r
2220 // Disable the device slots occupied by these devices on its downstream ports.\r
2221 // Entry 0 is reserved.\r
2222 //\r
2223 for (Index = 0; Index < 255; Index++) {\r
2224 if (!Xhc->UsbDevContext[Index + 1].Enabled ||\r
1436aea4
MK
2225 (Xhc->UsbDevContext[Index + 1].SlotId == 0))\r
2226 {\r
4b738c76
HT
2227 continue;\r
2228 }\r
1436aea4 2229\r
4b738c76
HT
2230 if (Xhc->HcCParams.Data.Csz == 0) {\r
2231 XhcDisableSlotCmd (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);\r
2232 } else {\r
2233 XhcDisableSlotCmd64 (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);\r
2234 }\r
2235 }\r
2236\r
2237 if (Xhc->PollTimer != NULL) {\r
2238 gBS->CloseEvent (Xhc->PollTimer);\r
2239 }\r
2240\r
2241 if (Xhc->ExitBootServiceEvent != NULL) {\r
2242 gBS->CloseEvent (Xhc->ExitBootServiceEvent);\r
2243 }\r
2244\r
2245 XhcHaltHC (Xhc, XHC_GENERIC_TIMEOUT);\r
2246 XhcClearBiosOwnership (Xhc);\r
2247 XhciDelAllAsyncIntTransfers (Xhc);\r
2248 XhcFreeSched (Xhc);\r
2249\r
2250 if (Xhc->ControllerNameTable) {\r
2251 FreeUnicodeStringTable (Xhc->ControllerNameTable);\r
2252 }\r
2253\r
2254 //\r
2255 // Restore original PCI attributes\r
2256 //\r
2257 PciIo->Attributes (\r
2258 PciIo,\r
2259 EfiPciIoAttributeOperationSet,\r
2260 Xhc->OriginalPciAttributes,\r
2261 NULL\r
2262 );\r
2263\r
2264 gBS->CloseProtocol (\r
2265 Controller,\r
2266 &gEfiPciIoProtocolGuid,\r
2267 This->DriverBindingHandle,\r
2268 Controller\r
2269 );\r
2270\r
2271 FreePool (Xhc);\r
2272\r
2273 return EFI_SUCCESS;\r
2274}\r