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