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