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