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