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