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