]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/XhciDxe/Xhci.c
Add type cast for better coding style.
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / XhciDxe / Xhci.c
CommitLineData
4b738c76
HT
1/** @file\r
2 The XHCI controller driver.\r
3\r
e1f2dfec 4Copyright (c) 2011 - 2014, 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
1486 if (!XHCI_IS_DATAIN (EndPointAddress)) {\r
1487 return EFI_INVALID_PARAMETER;\r
1488 }\r
1489\r
1490 if ((*DataToggle != 1) && (*DataToggle != 0)) {\r
1491 return EFI_INVALID_PARAMETER;\r
1492 }\r
1493\r
1494 if (((DeviceSpeed == EFI_USB_SPEED_LOW) && (MaximumPacketLength != 8)) ||\r
1495 ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) ||\r
1496 ((DeviceSpeed == EFI_USB_SPEED_HIGH) && (MaximumPacketLength > 3072))) {\r
1497 return EFI_INVALID_PARAMETER;\r
1498 }\r
1499\r
1500 OldTpl = gBS->RaiseTPL (XHC_TPL);\r
1501\r
1502 Xhc = XHC_FROM_THIS (This);\r
1503\r
1504 *TransferResult = EFI_USB_ERR_SYSTEM;\r
1505 Status = EFI_DEVICE_ERROR;\r
1506\r
1507 if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {\r
1508 DEBUG ((EFI_D_ERROR, "EhcSyncInterruptTransfer: HC is halt\n"));\r
1509 goto ON_EXIT;\r
1510 }\r
1511\r
1512 //\r
1513 // Check if the device is still enabled before every transaction.\r
1514 //\r
1515 SlotId = XhcBusDevAddrToSlotId (Xhc, DeviceAddress);\r
1516 if (SlotId == 0) {\r
1517 goto ON_EXIT;\r
1518 }\r
1519\r
1520 Urb = XhcCreateUrb (\r
1521 Xhc,\r
1522 DeviceAddress,\r
1523 EndPointAddress,\r
1524 DeviceSpeed,\r
1525 MaximumPacketLength,\r
1526 XHC_INT_TRANSFER_SYNC,\r
1527 NULL,\r
1528 Data,\r
1529 *DataLength,\r
1530 NULL,\r
1531 NULL\r
1532 );\r
1533\r
1534 if (Urb == NULL) {\r
1535 DEBUG ((EFI_D_ERROR, "XhcSyncInterruptTransfer: failed to create URB\n"));\r
1536 Status = EFI_OUT_OF_RESOURCES;\r
1537 goto ON_EXIT;\r
1538 }\r
1539\r
1540 Status = XhcExecTransfer (Xhc, FALSE, Urb, Timeout);\r
1541\r
1542 *TransferResult = Urb->Result;\r
1543 *DataLength = Urb->Completed;\r
1544\r
1545 if (*TransferResult == EFI_USB_NOERROR) {\r
1546 Status = EFI_SUCCESS;\r
1547 } else if (*TransferResult == EFI_USB_ERR_STALL) {\r
1548 RecoveryStatus = XhcRecoverHaltedEndpoint(Xhc, Urb);\r
1549 if (EFI_ERROR (RecoveryStatus)) {\r
1550 DEBUG ((EFI_D_ERROR, "XhcSyncInterruptTransfer: XhcRecoverHaltedEndpoint failed\n"));\r
1551 }\r
1552 Status = EFI_DEVICE_ERROR;\r
1553 }\r
1554\r
1555 Xhc->PciIo->Flush (Xhc->PciIo);\r
1556 XhcFreeUrb (Xhc, Urb);\r
1557\r
1558ON_EXIT:\r
1559 if (EFI_ERROR (Status)) {\r
1560 DEBUG ((EFI_D_ERROR, "XhcSyncInterruptTransfer: error - %r, transfer - %x\n", Status, *TransferResult));\r
1561 }\r
1562 gBS->RestoreTPL (OldTpl);\r
1563\r
1564 return Status;\r
1565}\r
1566\r
1567\r
1568/**\r
1569 Submits isochronous transfer to a target USB device.\r
1570\r
1571 @param This This EFI_USB2_HC_PROTOCOL instance.\r
1572 @param DeviceAddress Target device address.\r
1573 @param EndPointAddress End point address with its direction.\r
1574 @param DeviceSpeed Device speed, Low speed device doesn't support this\r
1575 type.\r
1576 @param MaximumPacketLength Maximum packet size that the endpoint is capable of\r
1577 sending or receiving.\r
1578 @param DataBuffersNumber Number of data buffers prepared for the transfer.\r
1579 @param Data Array of pointers to the buffers of data that will\r
1580 be transmitted to USB device or received from USB\r
1581 device.\r
1582 @param DataLength The size, in bytes, of the data buffer.\r
1583 @param Translator Transaction translator to use.\r
1584 @param TransferResult Variable to receive the transfer result.\r
1585\r
1586 @return EFI_UNSUPPORTED Isochronous transfer is unsupported.\r
1587\r
1588**/\r
1589EFI_STATUS\r
1590EFIAPI\r
1591XhcIsochronousTransfer (\r
1592 IN EFI_USB2_HC_PROTOCOL *This,\r
1593 IN UINT8 DeviceAddress,\r
1594 IN UINT8 EndPointAddress,\r
1595 IN UINT8 DeviceSpeed,\r
1596 IN UINTN MaximumPacketLength,\r
1597 IN UINT8 DataBuffersNumber,\r
1598 IN OUT VOID *Data[EFI_USB_MAX_ISO_BUFFER_NUM],\r
1599 IN UINTN DataLength,\r
1600 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,\r
1601 OUT UINT32 *TransferResult\r
1602 )\r
1603{\r
1604 return EFI_UNSUPPORTED;\r
1605}\r
1606\r
1607\r
1608/**\r
1609 Submits Async isochronous transfer to a target USB device.\r
1610\r
1611 @param This This EFI_USB2_HC_PROTOCOL instance.\r
1612 @param DeviceAddress Target device address.\r
1613 @param EndPointAddress End point address with its direction.\r
1614 @param DeviceSpeed Device speed, Low speed device doesn't support this\r
1615 type.\r
1616 @param MaximumPacketLength Maximum packet size that the endpoint is capable of\r
1617 sending or receiving.\r
1618 @param DataBuffersNumber Number of data buffers prepared for the transfer.\r
1619 @param Data Array of pointers to the buffers of data that will\r
1620 be transmitted to USB device or received from USB\r
1621 device.\r
1622 @param DataLength The size, in bytes, of the data buffer.\r
1623 @param Translator Transaction translator to use.\r
1624 @param IsochronousCallBack Function to be called when the transfer complete.\r
1625 @param Context Context passed to the call back function as\r
1626 parameter.\r
1627\r
1628 @return EFI_UNSUPPORTED Isochronous transfer isn't supported.\r
1629\r
1630**/\r
1631EFI_STATUS\r
1632EFIAPI\r
1633XhcAsyncIsochronousTransfer (\r
1634 IN EFI_USB2_HC_PROTOCOL *This,\r
1635 IN UINT8 DeviceAddress,\r
1636 IN UINT8 EndPointAddress,\r
1637 IN UINT8 DeviceSpeed,\r
1638 IN UINTN MaximumPacketLength,\r
1639 IN UINT8 DataBuffersNumber,\r
1640 IN OUT VOID *Data[EFI_USB_MAX_ISO_BUFFER_NUM],\r
1641 IN UINTN DataLength,\r
1642 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,\r
1643 IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack,\r
1644 IN VOID *Context\r
1645 )\r
1646{\r
1647 return EFI_UNSUPPORTED;\r
1648}\r
1649\r
1650/**\r
1651 Entry point for EFI drivers.\r
1652\r
1653 @param ImageHandle EFI_HANDLE.\r
1654 @param SystemTable EFI_SYSTEM_TABLE.\r
1655\r
1656 @retval EFI_SUCCESS Success.\r
1657 @retval Others Fail.\r
1658\r
1659**/\r
1660EFI_STATUS\r
1661EFIAPI\r
1662XhcDriverEntryPoint (\r
1663 IN EFI_HANDLE ImageHandle,\r
1664 IN EFI_SYSTEM_TABLE *SystemTable\r
1665 )\r
1666{\r
1667 return EfiLibInstallDriverBindingComponentName2 (\r
1668 ImageHandle,\r
1669 SystemTable,\r
1670 &gXhciDriverBinding,\r
1671 ImageHandle,\r
1672 &gXhciComponentName,\r
1673 &gXhciComponentName2\r
1674 );\r
1675}\r
1676\r
1677\r
1678/**\r
1679 Test to see if this driver supports ControllerHandle. Any\r
1680 ControllerHandle that has Usb2HcProtocol installed will\r
1681 be supported.\r
1682\r
1683 @param This Protocol instance pointer.\r
1684 @param Controller Handle of device to test.\r
1685 @param RemainingDevicePath Not used.\r
1686\r
1687 @return EFI_SUCCESS This driver supports this device.\r
1688 @return EFI_UNSUPPORTED This driver does not support this device.\r
1689\r
1690**/\r
1691EFI_STATUS\r
1692EFIAPI\r
1693XhcDriverBindingSupported (\r
1694 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1695 IN EFI_HANDLE Controller,\r
1696 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
1697 )\r
1698{\r
1699 EFI_STATUS Status;\r
1700 EFI_PCI_IO_PROTOCOL *PciIo;\r
1701 USB_CLASSC UsbClassCReg;\r
1702\r
1703 //\r
1704 // Test whether there is PCI IO Protocol attached on the controller handle.\r
1705 //\r
1706 Status = gBS->OpenProtocol (\r
1707 Controller,\r
1708 &gEfiPciIoProtocolGuid,\r
1709 (VOID **) &PciIo,\r
1710 This->DriverBindingHandle,\r
1711 Controller,\r
1712 EFI_OPEN_PROTOCOL_BY_DRIVER\r
1713 );\r
1714\r
1715 if (EFI_ERROR (Status)) {\r
1716 return EFI_UNSUPPORTED;\r
1717 }\r
1718\r
1719 Status = PciIo->Pci.Read (\r
1720 PciIo,\r
1721 EfiPciIoWidthUint8,\r
1722 PCI_CLASSCODE_OFFSET,\r
1723 sizeof (USB_CLASSC) / sizeof (UINT8),\r
1724 &UsbClassCReg\r
1725 );\r
1726\r
1727 if (EFI_ERROR (Status)) {\r
1728 Status = EFI_UNSUPPORTED;\r
1729 goto ON_EXIT;\r
1730 }\r
1731\r
1732 //\r
1733 // Test whether the controller belongs to Xhci type\r
1734 //\r
1735 if ((UsbClassCReg.BaseCode != PCI_CLASS_SERIAL) ||\r
1736 (UsbClassCReg.SubClassCode != PCI_CLASS_SERIAL_USB) ||\r
1737 (UsbClassCReg.ProgInterface != PCI_IF_XHCI)) {\r
1738 Status = EFI_UNSUPPORTED;\r
1739 }\r
1740\r
1741ON_EXIT:\r
1742 gBS->CloseProtocol (\r
1743 Controller,\r
1744 &gEfiPciIoProtocolGuid,\r
1745 This->DriverBindingHandle,\r
1746 Controller\r
1747 );\r
1748\r
1749 return Status;\r
1750}\r
1751\r
1752/**\r
1753 Create and initialize a USB_XHCI_INSTANCE structure.\r
1754\r
1755 @param PciIo The PciIo on this device.\r
1756 @param DevicePath The device path of host controller.\r
1757 @param OriginalPciAttributes Original PCI attributes.\r
1758\r
1759 @return The allocated and initialized USB_XHCI_INSTANCE structure if created,\r
1760 otherwise NULL.\r
1761\r
1762**/\r
1763USB_XHCI_INSTANCE*\r
1764XhcCreateUsbHc (\r
1765 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1766 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
1767 IN UINT64 OriginalPciAttributes\r
1768 )\r
1769{\r
1770 USB_XHCI_INSTANCE *Xhc;\r
1771 EFI_STATUS Status;\r
1772 UINT32 PageSize;\r
1773 UINT16 ExtCapReg;\r
1774\r
1775 Xhc = AllocateZeroPool (sizeof (USB_XHCI_INSTANCE));\r
1776\r
1777 if (Xhc == NULL) {\r
1778 return NULL;\r
1779 }\r
1780\r
1781 //\r
1782 // Initialize private data structure\r
1783 //\r
1784 Xhc->Signature = XHCI_INSTANCE_SIG;\r
1785 Xhc->PciIo = PciIo;\r
1786 Xhc->DevicePath = DevicePath;\r
1787 Xhc->OriginalPciAttributes = OriginalPciAttributes;\r
1788 CopyMem (&Xhc->Usb2Hc, &gXhciUsb2HcTemplate, sizeof (EFI_USB2_HC_PROTOCOL));\r
1789\r
1790 InitializeListHead (&Xhc->AsyncIntTransfers);\r
1791\r
1792 //\r
1793 // Be caution that the Offset passed to XhcReadCapReg() should be Dword align\r
1794 //\r
1795 Xhc->CapLength = XhcReadCapReg8 (Xhc, XHC_CAPLENGTH_OFFSET);\r
1796 Xhc->HcSParams1.Dword = XhcReadCapReg (Xhc, XHC_HCSPARAMS1_OFFSET);\r
1797 Xhc->HcSParams2.Dword = XhcReadCapReg (Xhc, XHC_HCSPARAMS2_OFFSET);\r
1798 Xhc->HcCParams.Dword = XhcReadCapReg (Xhc, XHC_HCCPARAMS_OFFSET);\r
1799 Xhc->DBOff = XhcReadCapReg (Xhc, XHC_DBOFF_OFFSET);\r
1800 Xhc->RTSOff = XhcReadCapReg (Xhc, XHC_RTSOFF_OFFSET);\r
1801\r
1802 //\r
1803 // This PageSize field defines the page size supported by the xHC implementation.\r
1804 // This xHC supports a page size of 2^(n+12) if bit n is Set. For example,\r
1805 // if bit 0 is Set, the xHC supports 4k byte page sizes.\r
1806 //\r
1807 PageSize = XhcReadOpReg(Xhc, XHC_PAGESIZE_OFFSET) & XHC_PAGESIZE_MASK;\r
1808 Xhc->PageSize = 1 << (HighBitSet32(PageSize) + 12);\r
1809\r
1810 ExtCapReg = (UINT16) (Xhc->HcCParams.Data.ExtCapReg);\r
1811 Xhc->ExtCapRegBase = ExtCapReg << 2;\r
1812 Xhc->UsbLegSupOffset = XhcGetCapabilityAddr (Xhc, XHC_CAP_USB_LEGACY);\r
1813 Xhc->DebugCapSupOffset = XhcGetCapabilityAddr (Xhc, XHC_CAP_USB_DEBUG);\r
1814\r
1815 DEBUG ((EFI_D_INFO, "XhcCreateUsb3Hc: Capability length 0x%x\n", Xhc->CapLength));\r
1816 DEBUG ((EFI_D_INFO, "XhcCreateUsb3Hc: HcSParams1 0x%x\n", Xhc->HcSParams1));\r
1817 DEBUG ((EFI_D_INFO, "XhcCreateUsb3Hc: HcSParams2 0x%x\n", Xhc->HcSParams2));\r
1818 DEBUG ((EFI_D_INFO, "XhcCreateUsb3Hc: HcCParams 0x%x\n", Xhc->HcCParams));\r
1819 DEBUG ((EFI_D_INFO, "XhcCreateUsb3Hc: DBOff 0x%x\n", Xhc->DBOff));\r
1820 DEBUG ((EFI_D_INFO, "XhcCreateUsb3Hc: RTSOff 0x%x\n", Xhc->RTSOff));\r
1821 DEBUG ((EFI_D_INFO, "XhcCreateUsb3Hc: UsbLegSupOffset 0x%x\n", Xhc->UsbLegSupOffset));\r
1822 DEBUG ((EFI_D_INFO, "XhcCreateUsb3Hc: DebugCapSupOffset 0x%x\n", Xhc->DebugCapSupOffset));\r
1823\r
1824 //\r
1825 // Create AsyncRequest Polling Timer\r
1826 //\r
1827 Status = gBS->CreateEvent (\r
1828 EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
1829 TPL_CALLBACK,\r
1830 XhcMonitorAsyncRequests,\r
1831 Xhc,\r
1832 &Xhc->PollTimer\r
1833 );\r
1834\r
1835 if (EFI_ERROR (Status)) {\r
1836 goto ON_ERROR;\r
1837 }\r
1838\r
1839 return Xhc;\r
1840\r
1841ON_ERROR:\r
1842 FreePool (Xhc);\r
1843 return NULL;\r
1844}\r
1845\r
1846/**\r
1847 One notified function to stop the Host Controller when gBS->ExitBootServices() called.\r
1848\r
1849 @param Event Pointer to this event\r
e3644786 1850 @param Context Event handler private data\r
4b738c76
HT
1851\r
1852**/\r
1853VOID\r
1854EFIAPI\r
1855XhcExitBootService (\r
1856 EFI_EVENT Event,\r
1857 VOID *Context\r
1858 )\r
1859\r
1860{\r
1861 USB_XHCI_INSTANCE *Xhc;\r
1862 EFI_PCI_IO_PROTOCOL *PciIo;\r
1863\r
1864 Xhc = (USB_XHCI_INSTANCE*) Context;\r
1865 PciIo = Xhc->PciIo;\r
1866\r
1867 //\r
1868 // Stop AsyncRequest Polling timer then stop the XHCI driver\r
1869 // and uninstall the XHCI protocl.\r
1870 //\r
1871 gBS->SetTimer (Xhc->PollTimer, TimerCancel, 0);\r
1872 XhcHaltHC (Xhc, XHC_GENERIC_TIMEOUT);\r
1873\r
1874 if (Xhc->PollTimer != NULL) {\r
1875 gBS->CloseEvent (Xhc->PollTimer);\r
1876 }\r
1877\r
1878 XhcClearBiosOwnership (Xhc);\r
1879\r
1880 //\r
1881 // Restore original PCI attributes\r
1882 //\r
1883 PciIo->Attributes (\r
1884 PciIo,\r
1885 EfiPciIoAttributeOperationSet,\r
1886 Xhc->OriginalPciAttributes,\r
1887 NULL\r
1888 );\r
1889}\r
1890\r
1891/**\r
1892 Starting the Usb XHCI Driver.\r
1893\r
1894 @param This Protocol instance pointer.\r
1895 @param Controller Handle of device to test.\r
1896 @param RemainingDevicePath Not used.\r
1897\r
1898 @return EFI_SUCCESS supports this device.\r
1899 @return EFI_UNSUPPORTED do not support this device.\r
1900 @return EFI_DEVICE_ERROR cannot be started due to device Error.\r
1901 @return EFI_OUT_OF_RESOURCES cannot allocate resources.\r
1902\r
1903**/\r
1904EFI_STATUS\r
1905EFIAPI\r
1906XhcDriverBindingStart (\r
1907 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
1908 IN EFI_HANDLE Controller,\r
1909 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
1910 )\r
1911{\r
1912 EFI_STATUS Status;\r
1913 EFI_PCI_IO_PROTOCOL *PciIo;\r
1914 UINT64 Supports;\r
1915 UINT64 OriginalPciAttributes;\r
1916 BOOLEAN PciAttributesSaved;\r
1917 USB_XHCI_INSTANCE *Xhc;\r
1918 EFI_DEVICE_PATH_PROTOCOL *HcDevicePath;\r
1919\r
1920 //\r
1921 // Open the PciIo Protocol, then enable the USB host controller\r
1922 //\r
1923 Status = gBS->OpenProtocol (\r
1924 Controller,\r
1925 &gEfiPciIoProtocolGuid,\r
1926 (VOID **) &PciIo,\r
1927 This->DriverBindingHandle,\r
1928 Controller,\r
1929 EFI_OPEN_PROTOCOL_BY_DRIVER\r
1930 );\r
1931\r
1932 if (EFI_ERROR (Status)) {\r
1933 return Status;\r
1934 }\r
1935\r
1936 //\r
1937 // Open Device Path Protocol for on USB host controller\r
1938 //\r
1939 HcDevicePath = NULL;\r
1940 Status = gBS->OpenProtocol (\r
1941 Controller,\r
1942 &gEfiDevicePathProtocolGuid,\r
1943 (VOID **) &HcDevicePath,\r
1944 This->DriverBindingHandle,\r
1945 Controller,\r
1946 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1947 );\r
1948\r
1949 PciAttributesSaved = FALSE;\r
1950 //\r
1951 // Save original PCI attributes\r
1952 //\r
1953 Status = PciIo->Attributes (\r
1954 PciIo,\r
1955 EfiPciIoAttributeOperationGet,\r
1956 0,\r
1957 &OriginalPciAttributes\r
1958 );\r
1959\r
1960 if (EFI_ERROR (Status)) {\r
1961 goto CLOSE_PCIIO;\r
1962 }\r
1963 PciAttributesSaved = TRUE;\r
1964\r
1965 Status = PciIo->Attributes (\r
1966 PciIo,\r
1967 EfiPciIoAttributeOperationSupported,\r
1968 0,\r
1969 &Supports\r
1970 );\r
1971 if (!EFI_ERROR (Status)) {\r
1972 Supports &= EFI_PCI_DEVICE_ENABLE;\r
1973 Status = PciIo->Attributes (\r
1974 PciIo,\r
1975 EfiPciIoAttributeOperationEnable,\r
1976 Supports,\r
1977 NULL\r
1978 );\r
1979 }\r
1980\r
1981 if (EFI_ERROR (Status)) {\r
1982 DEBUG ((EFI_D_ERROR, "XhcDriverBindingStart: failed to enable controller\n"));\r
1983 goto CLOSE_PCIIO;\r
1984 }\r
1985\r
1986 //\r
1987 // Create then install USB2_HC_PROTOCOL\r
1988 //\r
1989 Xhc = XhcCreateUsbHc (PciIo, HcDevicePath, OriginalPciAttributes);\r
1990\r
1991 if (Xhc == NULL) {\r
1992 DEBUG ((EFI_D_ERROR, "XhcDriverBindingStart: failed to create USB2_HC\n"));\r
1993 return EFI_OUT_OF_RESOURCES;\r
1994 }\r
1995\r
1996 XhcSetBiosOwnership (Xhc);\r
1997\r
1998 XhcResetHC (Xhc, XHC_RESET_TIMEOUT);\r
1999 ASSERT (XhcIsHalt (Xhc));\r
2000\r
2001 //\r
2002 // After Chip Hardware Reset wait until the Controller Not Ready (CNR) flag\r
2003 // in the USBSTS is '0' before writing any xHC Operational or Runtime registers.\r
2004 //\r
2005 ASSERT (!(XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_CNR)));\r
2006\r
2007 //\r
2008 // Initialize the schedule\r
2009 //\r
2010 XhcInitSched (Xhc);\r
2011\r
2012 //\r
2013 // Start the Host Controller\r
2014 //\r
2015 XhcRunHC(Xhc, XHC_GENERIC_TIMEOUT);\r
2016\r
2017 //\r
2018 // Start the asynchronous interrupt monitor\r
2019 //\r
2020 Status = gBS->SetTimer (Xhc->PollTimer, TimerPeriodic, XHC_ASYNC_TIMER_INTERVAL);\r
2021 if (EFI_ERROR (Status)) {\r
2022 DEBUG ((EFI_D_ERROR, "XhcDriverBindingStart: failed to start async interrupt monitor\n"));\r
2023 XhcHaltHC (Xhc, XHC_GENERIC_TIMEOUT);\r
2024 goto FREE_POOL;\r
2025 }\r
2026\r
2027 //\r
2028 // Create event to stop the HC when exit boot service.\r
2029 //\r
2030 Status = gBS->CreateEventEx (\r
2031 EVT_NOTIFY_SIGNAL,\r
2032 TPL_NOTIFY,\r
2033 XhcExitBootService,\r
2034 Xhc,\r
2035 &gEfiEventExitBootServicesGuid,\r
2036 &Xhc->ExitBootServiceEvent\r
2037 );\r
2038 if (EFI_ERROR (Status)) {\r
2039 goto FREE_POOL;\r
2040 }\r
2041\r
2042 //\r
2043 // Install the component name protocol, don't fail the start\r
2044 // because of something for display.\r
2045 //\r
2046 AddUnicodeString2 (\r
2047 "eng",\r
2048 gXhciComponentName.SupportedLanguages,\r
2049 &Xhc->ControllerNameTable,\r
2050 L"eXtensible Host Controller (USB 3.0)",\r
2051 TRUE\r
2052 );\r
2053 AddUnicodeString2 (\r
2054 "en",\r
2055 gXhciComponentName2.SupportedLanguages,\r
2056 &Xhc->ControllerNameTable,\r
2057 L"eXtensible Host Controller (USB 3.0)",\r
2058 FALSE\r
2059 );\r
2060\r
2061 Status = gBS->InstallProtocolInterface (\r
2062 &Controller,\r
2063 &gEfiUsb2HcProtocolGuid,\r
2064 EFI_NATIVE_INTERFACE,\r
2065 &Xhc->Usb2Hc\r
2066 );\r
2067 if (EFI_ERROR (Status)) {\r
2068 DEBUG ((EFI_D_ERROR, "XhcDriverBindingStart: failed to install USB2_HC Protocol\n"));\r
2069 goto FREE_POOL;\r
2070 }\r
2071\r
2072 DEBUG ((EFI_D_INFO, "XhcDriverBindingStart: XHCI started for controller @ %x\n", Controller));\r
2073 return EFI_SUCCESS;\r
2074\r
2075FREE_POOL:\r
2076 gBS->CloseEvent (Xhc->PollTimer);\r
2077 XhcFreeSched (Xhc);\r
2078 FreePool (Xhc);\r
2079\r
2080CLOSE_PCIIO:\r
2081 if (PciAttributesSaved) {\r
2082 //\r
2083 // Restore original PCI attributes\r
2084 //\r
2085 PciIo->Attributes (\r
2086 PciIo,\r
2087 EfiPciIoAttributeOperationSet,\r
2088 OriginalPciAttributes,\r
2089 NULL\r
2090 );\r
2091 }\r
2092\r
2093 gBS->CloseProtocol (\r
2094 Controller,\r
2095 &gEfiPciIoProtocolGuid,\r
2096 This->DriverBindingHandle,\r
2097 Controller\r
2098 );\r
2099\r
2100 return Status;\r
2101}\r
2102\r
2103\r
2104/**\r
2105 Stop this driver on ControllerHandle. Support stoping any child handles\r
2106 created by this driver.\r
2107\r
2108 @param This Protocol instance pointer.\r
2109 @param Controller Handle of device to stop driver on.\r
2110 @param NumberOfChildren Number of Children in the ChildHandleBuffer.\r
2111 @param ChildHandleBuffer List of handles for the children we need to stop.\r
2112\r
2113 @return EFI_SUCCESS Success.\r
2114 @return EFI_DEVICE_ERROR Fail.\r
2115\r
2116**/\r
2117EFI_STATUS\r
2118EFIAPI\r
2119XhcDriverBindingStop (\r
2120 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
2121 IN EFI_HANDLE Controller,\r
2122 IN UINTN NumberOfChildren,\r
2123 IN EFI_HANDLE *ChildHandleBuffer\r
2124 )\r
2125{\r
2126 EFI_STATUS Status;\r
2127 EFI_USB2_HC_PROTOCOL *Usb2Hc;\r
2128 EFI_PCI_IO_PROTOCOL *PciIo;\r
2129 USB_XHCI_INSTANCE *Xhc;\r
2130 UINT8 Index;\r
2131\r
2132 //\r
2133 // Test whether the Controller handler passed in is a valid\r
2134 // Usb controller handle that should be supported, if not,\r
2135 // return the error status directly\r
2136 //\r
2137 Status = gBS->OpenProtocol (\r
2138 Controller,\r
2139 &gEfiUsb2HcProtocolGuid,\r
2140 (VOID **) &Usb2Hc,\r
2141 This->DriverBindingHandle,\r
2142 Controller,\r
2143 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
2144 );\r
2145\r
2146 if (EFI_ERROR (Status)) {\r
2147 return Status;\r
2148 }\r
2149\r
2150 Status = gBS->UninstallProtocolInterface (\r
2151 Controller,\r
2152 &gEfiUsb2HcProtocolGuid,\r
2153 Usb2Hc\r
2154 );\r
2155\r
2156 if (EFI_ERROR (Status)) {\r
2157 return Status;\r
2158 }\r
2159\r
2160 Xhc = XHC_FROM_THIS (Usb2Hc);\r
2161 PciIo = Xhc->PciIo;\r
2162\r
2163 //\r
2164 // Stop AsyncRequest Polling timer then stop the XHCI driver\r
2165 // and uninstall the XHCI protocl.\r
2166 //\r
2167 gBS->SetTimer (Xhc->PollTimer, TimerCancel, 0);\r
2168\r
2169 //\r
2170 // Disable the device slots occupied by these devices on its downstream ports.\r
2171 // Entry 0 is reserved.\r
2172 //\r
2173 for (Index = 0; Index < 255; Index++) {\r
2174 if (!Xhc->UsbDevContext[Index + 1].Enabled ||\r
2175 (Xhc->UsbDevContext[Index + 1].SlotId == 0)) {\r
2176 continue;\r
2177 }\r
2178 if (Xhc->HcCParams.Data.Csz == 0) {\r
2179 XhcDisableSlotCmd (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);\r
2180 } else {\r
2181 XhcDisableSlotCmd64 (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);\r
2182 }\r
2183 }\r
2184\r
2185 if (Xhc->PollTimer != NULL) {\r
2186 gBS->CloseEvent (Xhc->PollTimer);\r
2187 }\r
2188\r
2189 if (Xhc->ExitBootServiceEvent != NULL) {\r
2190 gBS->CloseEvent (Xhc->ExitBootServiceEvent);\r
2191 }\r
2192\r
2193 XhcHaltHC (Xhc, XHC_GENERIC_TIMEOUT);\r
2194 XhcClearBiosOwnership (Xhc);\r
2195 XhciDelAllAsyncIntTransfers (Xhc);\r
2196 XhcFreeSched (Xhc);\r
2197\r
2198 if (Xhc->ControllerNameTable) {\r
2199 FreeUnicodeStringTable (Xhc->ControllerNameTable);\r
2200 }\r
2201\r
2202 //\r
2203 // Restore original PCI attributes\r
2204 //\r
2205 PciIo->Attributes (\r
2206 PciIo,\r
2207 EfiPciIoAttributeOperationSet,\r
2208 Xhc->OriginalPciAttributes,\r
2209 NULL\r
2210 );\r
2211\r
2212 gBS->CloseProtocol (\r
2213 Controller,\r
2214 &gEfiPciIoProtocolGuid,\r
2215 This->DriverBindingHandle,\r
2216 Controller\r
2217 );\r
2218\r
2219 FreePool (Xhc);\r
2220\r
2221 return EFI_SUCCESS;\r
2222}\r
2223\r