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