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