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