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