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