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