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