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