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