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