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