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