diff options
Diffstat (limited to 'Core/EM/usb/amiusbhc.c')
-rw-r--r-- | Core/EM/usb/amiusbhc.c | 3330 |
1 files changed, 3330 insertions, 0 deletions
diff --git a/Core/EM/usb/amiusbhc.c b/Core/EM/usb/amiusbhc.c new file mode 100644 index 0000000..7f90434 --- /dev/null +++ b/Core/EM/usb/amiusbhc.c @@ -0,0 +1,3330 @@ +//**************************************************************************** +//**************************************************************************** +//** ** +//** (C)Copyright 1985-2016, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Norcross, GA 30093 ** +//** ** +//** Phone (770)-246-8600 ** +//** ** +//**************************************************************************** +//**************************************************************************** + +//**************************************************************************** +// $Header: /Alaska/Projects/Intel/Haswell/LynxPoint_SharkBay-DT_Crb_1AQQW/core/em/usb/amiusbhc.c 1 3/01/17 2:28a Chienhsieh $ +// +// $Revision: 1 $ +// +// $Date: 3/01/17 2:28a $ +// +//**************************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/Projects/Intel/Haswell/LynxPoint_SharkBay-DT_Crb_1AQQW/core/em/usb/amiusbhc.c $ +// +// 1 3/01/17 2:28a Chienhsieh +// [TAG] EIP320994 +// [Description] Fixed Reconnect XHCI controller fail in shell with USB, +// 4.6.5.1_USB_08.10.36 (XHCI Mode: Enabled) +// +// 99 10/28/16 3:59a Wilsonlee +// [TAG] EIP300142 +// [Category] Improvement +// [Description] Remove USB Int1C module part because we use the other +// method to service xhci. +// [Files] usbport.c, amidef.h, amiusbhc.c, UsbLegacy.cif +// +// 98 10/16/16 10:18p Wilsonlee +// [TAG] EIP288158 +// [Category] Improvement +// [Description] Check if gUsbData is integrity. +// [Files] amiusb.cif, usbsb.c, AmiUsbLib.cif, AmiUsbLib.sdl, +// AmiUsbSmmGlobalDataValidationLib.c, +// AmiUsbSmmGlobalDataValidationLib.cif, +// AmiUsbSmmGlobalDataValidationLib.mak, Crc32.c, amiusb.c, amiusb.h, +// ehci.c, elib.c, ohci.c, syskbc.c, uhci.c, usb.c, usbCCID.c, usbdef.h, +// usbhid.c, usbhub.c, usbkbd.c, usbmass.c, usbms.c, usbrt.mak, xhci.c, +// amiusbhc.c, efiusbccid.c, efiusbmass.c, uhcd.c, usbmisc.c, +// AmiUsbController.h, AmiUsbLibInclude.cif, +// AmiUsbSmmGlobalDataValidationLib.h +// +// 97 7/28/16 4:55a Wilsonlee +// [TAG] EIP264662 +// [Category] Improvement +// [Description] Don't install usb hw smi after reconnecting usb +// controllers. +// [Files] uhcd.c, usb.c, ohci.c, amiusb.c, amiusbhc.c +// +// 96 7/07/16 1:12a Wilsonlee +// [TAG] EIP277810 +// [Category] Improvement +// [Description] Validate the memory buffer is entirely outside of SMM. +// [Files] usbsb.c, amiusb.c, ehci.c, ohci.c, uhci.c, usbCCID.c, +// usbdef.h, usbmass.c, xhci.c, amiusbhc.c, efiusbccid.c, efiusbmass.c, +// uhcd.c, uhcd.h, usbmisc.c +// +// 95 3/31/16 5:49a Wilsonlee +// [TAG] EIP259282 +// [Category] Improvement +// [Description] Update AmiUsbHcGetRootHubPortStatus function to support +// super speed devices. +// [Files] amiusbhc.c +// +// 94 3/02/16 9:42p Wilsonlee +// [TAG] EIP254309 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] GK-FORCE K83 USB KB function abnormal. +// [RootCause] This device has an interrupt out endpoint and doesn't +// support "Set Report" request. +// [Solution] Use the interrupt out endpoint instead of sending "Set +// Report" request. +// [Files] AmiUsbController.h, xhci.c, usbmass.c, usbkbd.h, usbkbd.c, +// usbhub.c, usbhid.c, usbdef.h, usbCCID.c, usb.c, uhci.c, ohci.c, ehci.c, +// amiusb.h, efiusbms,c, amiusbhc.c +// +// 93 1/19/16 3:19a Wilsonlee +// [TAG] EIP251667 +// [Category] Improvement +// [Description] Implement EFI_USB2_HC_PROTOCOL.SetState() function. +// [Files] amiusbhc.c, uhcd.h +// +// 92 1/19/16 2:47a Wilsonlee +// [TAG] EIP251519 +// [Category] Improvement +// [Description] Return current state of the USB host controller on +// EFI_USB2_HC_PROTOCOL.GetState(). +// [Files] amiusbhc.c +// +// 91 1/19/16 2:12a Wilsonlee +// [TAG] EIP252487 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Static code analysis issues found in Usb module. +// [RootCause] Wrong function called due to copy-paste error. +// [Solution] Replace AmiUsbHcClearRootHubPortFeature with +// AmiUsbHcSetRootHubPortFeature. +// [Files] amiusbhc.c +// +// 90 12/03/15 1:31a Wilsonlee +// [TAG] EIP247363 +// [Category] Improvement +// [Description] MajorRevision is 3 and MinorRevision is 1 for xhci 1.1 +// controllers. +// [Files] amiusbhc.c +// +// 89 7/24/15 5:03a Wilsonlee +// [TAG] EIP230092 +// [Category] Bug Fix +// [Severity] Critical +// [Symptom] Usb devices don't work in VL801 / VL805 under BIOS. +// [RootCause] Bit[0..5] are reserved in Device Context Base Address +// Array Element 0. +// [Solution] Allcate a PAGESIZE boundary for Scratchpad Buffer Array +// Base Address. +// [Files] amiusbhc.c +// +// 88 5/13/15 2:46a Wilsonlee +// [TAG] EIP216587 +// [Category] Improvement +// [Description] Add 64-bit addressing buffer support for usb transfers. +// [Files] amiusbhc.c, efiusbmass.c +// +// 87 4/10/15 3:05a Wilsonlee +// [TAG] EIP207413 +// [Category] Improvement +// [Description] Install UsbApiTable and UsbMassApitTable in +// AmiUsbSmmProtocol. +// [Files] amiusbhc.c, AmiUsbController.h, usbdef.h, usbCCID.c, uhci.c, +// ehci.c, amiusbrtCCID.h, amiusb.h, amiusb.c, uhcd.c +// +// 86 2/09/15 4:16a Wilsonlee +// [TAG] EIP202592 +// [Category] Improvement +// [Description] Don't reset xhci controller if it's Debug Capability is +// enabled. +// [Files] xhci.c, xhci.h, amiusbhc.c +// +// 85 1/22/15 10:20p Wilsonlee +// [TAG] EIP201434 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Number of connected devices isn't correct if we plug out +// keyboards or mice behind hub in xhci. +// [RootCause] The PortConnectChange bit is cleared when we check port +// status for interrupt endpoint transaction error. +// [Solution] Don't clear change bits if we check port status for +// interrupt endpoint transaction error. +// [Files] xhci.c, usbhub.c, usbdef.h, usb.c, uhci.c, ohci.c, ehci.c, +// amiusbhc.c +// +// 84 12/24/14 6:12a Wilsonlee +// [TAG] EIP196753 +// [Category] Improvement +// [Description] Check Max Scratchpad Buffers (Max Scratchpad Bufs Hi) +// register and allocate Scratchpad buffers. +// [Files] amiusbhc.c, xhci.h +// +// 83 6/29/14 10:40p Wilsonlee +// [TAG] EIP175328 +// [Category] Bug Fix +// [Severity] Important +// [Symptom] Bluetooth module asserts in AmiUsb_07. +// [RootCause] For ActivatePolling function, we use new parameter, +// PollingLength, in AmiUsb_07, but it's undefined in +// AmiUsb2HcAsyncInterruptTransfer. +// [Solution] Initialize PollingLength in +// AmiUsb2HcAsyncInterruptTransfer. +// [Files] amiusbhc.c +// +// 82 4/30/14 5:27a Wilsonlee +// [TAG] EIP164842 +// [Category] Improvement +// [Description] Check if the devices have put into to our queue before +// we put them. +// [Files] UsbInt13.c, amiusb.c, ehci.c, ohci.c, usb.c, usbdef.h, +// usbmass.c, xhci.c, amiusbhc.c, efiusbmass.c, uhcd.c, usbbus.c, usbsb.c +// +// 81 12/30/13 3:17a Ryanchou +// Corrent max packet size check for full speed device in +// AmiUsb2HcSyncInterruptTransfer(). +// +// 80 7/26/13 2:41a Ryanchou +// [TAG] EIP122142 +// [Category] Improvement +// [Description] Improve periodic schedule mechanism +// [Files] ehci.c, ehci.h, ohci.c, ohci.h, uhci.c, uhci.h, usbdef.h, +// amiusbhc.c +// +// 79 3/25/13 9:36p Wilsonlee +// [TAG] EIP118926 +// [Category] Improvement +// [Description] Add the token "EFI_USB_HC_INTERRUPT_OUT_SUPPORT" to +// control whether support EFI_USB2_HC_PROTOCOL.AsyncInterruptTransfer and +// EFI_USB2_HC_PROTOCOL.SyncInterruptTransfer() on OUT endpoints. +// [Files] amiusbhc.c, usbsrc.sdl +// +// 78 3/19/13 4:00a Ryanchou +// [TAG] EIP118177 +// [Category] Improvement +// [Description] Dynamically allocate HCStrucTable at runtime. +// [Files] usb.sdl, usbport.c, usbsb.c, amiusb.c, ehci.c, ohci.c, +// syskbc.c, sysnokbc.c, uhci.c, usb.c, usbCCID.c, usbdef.h, usbhid.c, +// usbhub.c, usbmass.c, usbrt.mak, usb.sd, amiusbhc.c, efiusbccid.c, +// efiusbhid.c, efiusbmass.c, efiusbms.c, uhcd.c, uhcd.h, uhcd.mak, +// usbmisc.c, usbsrc.sdl +// +// 77 1/11/13 4:19a Ryanchou +// [TAG] EIP102491 +// [Category] Improvement +// [Description] Synchronized with Aptio V USB module +// [Files] usbport.c, usbsb.c, ehci.c, ehci.h, ohci.c, ohci.h, uhci.h, +// usb.c, usbdef.h, usbhid.c, usbhub.c, usbkbd.c, usbkbd.h, usbmass.c. +// usbms.c, usbpoint.c, xhci.h, usb.sd, amiusbhc.c, componentname.c, +// efiusbkc.c, efiusbmass.c, uhcd.c, uhcd.h, usbbus.c, usbbus.h, usbmisc.c +// +// 76 11/10/12 6:41a Ryanchou +// [TAG] EIP99431 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] Cannot use the UsbIo's UsbAsyncInterruptTransfer for +// keyboard input +// [RootCause] Stopping EFI USB keyboard driver does not stop the +// endpoint polling, then application calls UsbAsyncInterruptTransfer, +// error will be returned. +// [Solution] Stops endpoint polling and release resource when +// disconnecting the device driver. And improve the +// UsbSyncInterruptTransfer. +// [Files] amiusb.c, amiusb.h, ehci.c, ohci.c, uhci.c, usb.c, +// usbCCID.c, usbdef.h, usbhub.c, usbkbd.c, usbmass.c, usbms.c, +// usbpoint.c, amiusbhc.c, efiusbhid.c, usbbus.c, usbbus.h +// +// 75 9/28/12 3:00a Wilsonlee +// [TAG] EIP101226 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] Chief River fails to boot when Above 4G Decoding is +// enabled. +// [RootCause] We read 32 bits width memory base address even if it is +// 64 bits wide. +// [Solution] Read 64 bits width memory base address if it is 64 bits +// wide. +// [Files] amiusbhc.c +// +// 74 8/29/12 8:34a Ryanchou +// [TAG] EIP77262 +// [Category] New Feature +// [Description] Remove SMM dependency of USB. +// [Files] usb.sdl, usbport.c, amiusb.c, amiusb.dxs, amiusb.h, ehci.c, +// elib.c, ohci.c, uhci.c, usb.c, usbdef.h, usbrt.mak, xhci.c, amiusbhc.c, +// efiusbccid.c, efiusbhid.c, efiusbkb.c, efiusbmass.c, uhcd.c, uhcd.dxs, +// uhcd.h, usbmisc.c, AmiUsbController.h +// +// 73 8/29/12 6:25a Ryanchou +// [TAG] EIP93932 +// [Category] Improvement +// [Description] Fix the SCT test failure in AsyncInterruptTransfer +// item. +// [Files] amiusbhc.c +// +// 72 7/25/12 4:51a Wilsonlee +// [TAG] EIP91840 +// [Category] Improvement +// [Description] Initialize the variable Params.ApiData.CoreProc.retVal +// and Params.bRetValue. +// [Files] amiusbhc.c +// +// 71 5/04/12 6:41a Ryanchou +// [TAG] EIP82875 +// [Category] Improvement +// [Description] Support start/stop individual USB host to avoid +// reconnect issues. +// [Files] usbport.c, usbsb.c, amiusb.c, amiusb.h, ehci.c, ohci.c, +// uhci.c, uhci.h, usb.c, usbdef.h, xhci.c, amiusbhc.c, uhcd.c, uhcd.h, +// usbbus.c, usbmisc.c +// +// 70 5/03/12 5:53a Roberthsu +// [TAG] EIP84455 +// [Category] Improvement +// [Description] Implement usb hid device gencric. +// [Files] amiusb.c,amiusbhc.c,efiusbhid.c,efiusbkb.c,ehci.c,ohci.c,uhc +// d.c,uhci.c,usbdef.h,usbhid.c,usbhub.c,usbkbd.c,usbkbd.h,usbms.c,usbsb.c +// ,usbsrc.sdl +// +// 69 4/10/12 10:14p Wilsonlee +// [TAG] EIP84790 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] USB IO PROTOCOL under XHCI issue +// [RootCause] The DevMiscInfo is NULL. +// [Solution] Fill the DevMiscInfo for the xhci controller. +// [Files] ehci.c, xhci.c, amiusbhc.c +// +// 68 2/16/12 8:55p Wilsonlee +// [TAG] EIP81612 +// [Category] Spec Update +// [Severity] Minor +// [Description] Add EFI_USB_SPEED_SUPER in EFI_USB2_HC_PROTOCOL +// according to UEFI 2.3.1 spec +// [Files] usb.c, usbbus.c, amiusbhc.c +// +// 67 1/13/12 4:26a Ryanchou +// [TAG] EIP47348 +// [Category] New Feature +// [Description] Support for USB Port Reset function. +// [Files] amiusb.c, amiusb.h, amiusbhc.c, uhci.c, usb.c, usbbus.c, +// usbbus.h, usbmass.c +// +// 66 12/14/11 2:07a Ryanchou +// [TAG] EIP76397 +// [Category] Bug Fix +// [Severity] Important +// [Symptom] ASSERT occurred when executing "reconnect -r" under shell +// [RootCause] The EIP63188 changes locate all USB controllers at one +// time, the "reconnect -r" will connect ConIn and ConOut first, so USB +// driver only locate a controller. +// [Solution] Rollback the EIP63188 changes to avoid this issue. +// [Files] amiusbhc.c, efiusbhid.c, efiusbkb.c, uhcd.c, uhcd.h, +// usbbus.c usbhid.c +// +// 65 9/28/11 10:47a Ryanchou +// [TAG] EIP66064 +// [Category] Bug Fix +// [Severity] Minor +// [Symptom] System hangs when waiting for finger swipe +// [RootCause] USB driver save the URP pointer to EBDA in function +// UsbSmiCore and UsbSmiHc, the pointer will be destroyed if someone also +// invoke the two functions. +// [Solution] Save the URP pointer before generate SW SMI and restore it +// after return from SMI. +// [Files] amiusb.c, amiusbhc.c, usbport.c +// +// 64 7/15/11 6:23a Ryanchou +// [TAG] EIP38434 +// [Category] New Feature +// [Description] Added USB HID report protocol support. +// [Files] amiusb.c, AmiUsbController.h, amiusbhc.c, efiusbkb.c, +// efiusbkb.h, efiusbpoint.c, ehci.c, ohci.c, uhcd.c uhcd.cif, uhci.c, +// usb.c, usbdef.h, usbhid.c, usbkbd.c, usbkbd.h, usbms.c, usbpoint.c, +// usbrt.cif, usbsb.c, usbsetup.c, usbsrc.sdl, xhci.c +// +// 62 4/06/11 3:00a Ryanchou +// [TAG] EIP57691 +// [Category] Improvement +// [Description] The MP version of FL1009 doesn't need the EIP46210 +// workaround, remove the EIP46210 change. +// [Files] amiusbhc.c +// +// 61 2/18/11 12:24a Ryanchou +// [TAG] EIP51495 +// [Category] Improvement +// [Description] Clear 'HC OS Owned Semaphore' bit during XHCI legacy +// initialization. +// [Files] amiusbhc.c, ehci.c +// +// 60 12/28/10 4:00a Ryanchou +// [TAG] EIP48009 +// [Category] Improvement +// [Description] Use 32 or 64 byte Context data structures dynamically. +// [Files] amiusbhc.c, usbsrc.sdl, xhci.c, xhci.h +// +// 59 12/02/10 2:19p Olegi +// [TAG] EIP48695 +// [Category] Bug Fix +// [Severity] Important +// [Symptom] SCT Error for USB HC SyncInterruptTransfer API +// [RootCause] Checking for endpoint being IN was missing. +// [Solution] - Added checking for BIT7 of the interrupt endpoint +// address, if not set return EFI_INVALID_PARAMETER. +// - Corrected EFI USB mouse driver that issues the SyncInterruptTransfer +// with the wrong endpoint address. +// [Files] amiusbhc.c +// efiusbms.c +// +// 58 10/30/10 2:32a Ryanchou +// EIP38221: Added the code that properly initializes +// DEV_INFO.bIntEndpoint field; interrupt endpoint polling is using this +// endpoint number. +// +// 57 10/22/10 9:07a Ryanchou +// EIP46210: Added FL1009 USB 3.0 connection linkup workaround. +// +// 56 10/22/10 8:58a Ryanchou +// EIP46693: Clear xHCI BIOS owned semaphore bit and SMI enable bit in +// PreInitXhci. +// +// 55 10/21/10 10:16a Ryanchou +// +// 54 9/16/10 12:47p Olegi +// Changed the parameters validation code in +// AmiUsb2HcSyncInterruptTransfer function: +// - MaxPacketLength does not have to be 8, it is 4 for a mouse +// - Endpoint does not have to be in (BIT7) +// +// 53 9/07/10 6:03a Tonylo +// EIP43742 - Wrong 64bit-Addressing Capability bit acquired for +// reference. +// +// 52 8/31/10 9:01a Tonylo +// EIP41544 - Add EntronTech XHCI support. +// +// Category: New Feature +// +// Description: Add EntronTech XHCI support. +// +// Files: amiusbhc.c +// usbport.c +// uhcd.h +// +// +// 51 8/17/10 4:26p Olegi +// Klockwork issues fixes. EIP37978 +// +// 50 6/07/10 5:00p Olegi +// Corrected the transfer routines output values. EIP34492. +// +// 49 5/19/10 4:04p Olegi +// Remove the assertion on not-successful return from SMI handler. Errors +// are legitimate, they are handled on the callers' level. +// +// 48 4/02/10 8:59a Olegi +// +// 47 2/27/10 12:00p Olegi +// +// 46 2/26/10 4:08p Olegi +// +// 45 2/08/10 9:56a Olegi +// EIP33381: Implement multiple bulk endpoint in UsbIoProtocol. +// +// 44 1/27/10 5:26p Olegi +// +// 43 1/19/10 11:59a Olegi +// +// 42 12/22/09 8:47a Olegi +// +// 41 11/25/09 8:06a Olegi +// +// 40 11/09/09 5:40p Olegi +// +// 39 10/30/09 5:48p Olegi +// +// 38 10/09/09 5:57p Olegi +// +// 37 8/11/09 9:30a Olegi +// Update for a bugfix #24507. +// +// 36 8/05/09 6:01p Olegi +// Bugfix in the controller version reporting. EIP#24507. +// +// 34 12/16/08 10:50a Olegi +// Correction in the return values: 0 changed to NULL. EIP#17767. +// +// 32 10/03/08 3:31p Olegi +// gUsbData->dLastCommandStatusExtended is initialized before every +// transfer. +// +// 31 9/26/08 5:06p Olegi +// Added one more stall check condition. +// +// 30 9/02/08 10:33a Olegi +// Modifications in GetRootHubStatus and ControlTransfer to return proper +// error codes. +// +// 29 8/08/08 2:39p Olegi +// Bugfix in AmiUsbHcGetRootHubPortStatus - port number passed there is +// 0-based. +// +// 28 5/16/08 12:02p Olegi +// Compliance with AMI coding standard. +// +// 23 12/22/06 4:05p Olegi +// Timeout implementation. +// +// 18 10/26/06 3:57p Olegi +// EFI_USB2_HC_PROTOCOL implementatin. +// +// 12 3/20/06 3:37p Olegi +// Version 8.5 - x64 compatible. +// +// 8 6/15/05 1:58p Andriyn +// Comments were changed +//**************************************************************************** +//<AMI_FHDR_START> +// +// Name: AmuUsbHc.c +// +// Description: USB_HC_PROTOCOL implementation +// +//<AMI_FHDR_END> +//**************************************************************************** + +#include "Efi.h" +#include "amidef.h" +#include "usbdef.h" +#include "uhcd.h" + +#include "tree.h" +#include "uhci.h" +#include "pci.h" +#include "protocol\cpu.h" +#include "protocol\legacy8259.h" + +#define INTERRUPTQUEUESIZE 10 + +extern EFI_GUID gEfiUsb2HcProtocolGuid; +extern USB_GLOBAL_DATA *gUsbData; +extern EFI_USB_PROTOCOL *gAmiUsbController; + +static UINT8 SpeedMap[] = { 0x10, 0x01, 0, 0 }; + +EFI_LEGACY_8259_PROTOCOL *gPic; +UINT32 gVector = 0; + +UINT8 *gUsbBusTempBuffer = NULL; +UINTN gTempBufferPages = 0; + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: GetThis +// +// Description: +// Function returns a pointer to HcProtocol2 record of a given protocol +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +static HC_DXE_RECORD* GetThis(EFI_USB2_HC_PROTOCOL* Protocol) +{ + return (HC_DXE_RECORD*)( + (char*)Protocol - (UINTN)&((HC_DXE_RECORD*)0)->hcprotocol2 ); +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: GetThis1 +// +// Description: +// Function returns a pointer to HcProtocol record of a given protocol +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +static HC_DXE_RECORD* GetThis1 (EFI_USB_HC_PROTOCOL* Protocol) +{ + return (HC_DXE_RECORD*)( + (char*)Protocol - (UINTN)&((HC_DXE_RECORD*)0)->hcprotocol ); +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: GetTransferStatus +// +// Description: +// Function converts the bitmap of gUsbData->dLastCommandStatusExtended into +// a valid USB error. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +static UINT32 GetTransferStatus() +{ + static struct { int BitDst, BitSrc; } ErrorMap[] = { + EFI_USB_ERR_STALL, USB_TRSFR_STALLED, + EFI_USB_ERR_STALL, USB_BULK_STALLED, + EFI_USB_ERR_STALL, USB_CONTROL_STALLED, + EFI_USB_ERR_BUFFER, USB_TRSFR_BUFFER_ERROR, + EFI_USB_ERR_BABBLE, USB_TRNSFR_BABBLE, + EFI_USB_ERR_NAK, USB_TRNSFR_NAK, + EFI_USB_ERR_CRC, USB_TRNSFR_CRCERROR, + EFI_USB_ERR_TIMEOUT, USB_TRNSFR_TIMEOUT, //(EIP84790) + EFI_USB_ERR_BITSTUFF, USB_TRNSFR_BITSTUFF, + EFI_USB_ERR_SYSTEM, 0 + }; + UINT32 Err = 0; + UINT32 Status = gUsbData->dLastCommandStatusExtended; + UINT8 i; + + for (i = 0; i<COUNTOF(ErrorMap); ++i){ + if( Status & ErrorMap[i].BitSrc ) { + Err |= ErrorMap[i].BitDst; + } + } + + if( Status == 0 ) { + return EFI_USB_NOERROR; + } else { + return Err; + } +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: UsbSmiCore +// +// Description: +// Bridge between DXE code and function in USB Core proc table which is inside +// our SMI code. +// +// Input: +// Func - function number opUSBCORE_XXX which corresponds to index in Core Proc table. +// Rest of the parameters coresponds the callee interface +// +// Output: +// Whatever callee returns +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +enum { + opUSBCORE_GetDescriptor, + opUSBCORE_ReConfigDevice, + opUSBCORE_ReConfigDevice2, + opUSBCORE_AllocDevInfo, + opUSBCORE_PrepareForLegacyOS, + opUSBCORE_ResetAndReconfigDev, + opUSBCORE_DevDriverDisconnect, + opUSBCORE_PeriodicEvent, + opUSBCORE_Last, +}; + + +int CoreprocStackSize[] = { + 6*sizeof(VOID*), // opUSBSMI_GetDescriptor + 2*sizeof(VOID*), // opUSBCORE_ReConfigDevice + 4*sizeof(VOID*), // opUSBCORE_ReConfigDevice2 + 1*sizeof(VOID*), // opUSBCORE_AllocDevInfo + 1*sizeof(VOID*), // opUSBCORE_PrepareForLegacyOS + 2*sizeof(VOID*), // opUSBCORE_ResetAndReconfigDev + 2*sizeof(VOID*), // opUSBCORE_DevDriverDisconnect + 0, // opUSBCORE_PeriodicEvent +}; + +UINTN UsbSmiCore( UINT8 Func, ... ) +{ + URP_STRUC Params; + VA_LIST ArgList; + + ASSERT(Func < COUNTOF(CoreprocStackSize)); +// ASSERT(CoreprocStackSize[Func] > 0); + + VA_START(ArgList, Func); + + Params.bFuncNumber = USB_API_CORE_PROC; + Params.bSubFunc = Func; + Params.bRetValue = USB_ERROR; //(EIP91840+) + Params.ApiData.CoreProc.paramBuffer = &VA_ARG(ArgList, int); + Params.ApiData.CoreProc.paramSize = CoreprocStackSize[Func]; + Params.ApiData.CoreProc.retVal = 0; //(EIP91840+) + USB_DEBUG(DEBUG_USBHC_LEVEL8, + "call CORE SMI proc(%d); params: %x\n", Func, Params.ApiData.CoreProc.paramBuffer); + + InvokeUsbApi(&Params); + + VA_END(ArgList); + +// ASSERT(Params.bRetValue == USB_SUCCESS); + + return Params.ApiData.CoreProc.retVal; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: UsbSmiGetDescriptor +// +// Description: +// SW SMI to execute GetDescriptor transfer +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8* +UsbSmiGetDescriptor ( + HC_STRUC* HostController, + DEV_INFO* Device, + UINT8* Buffer, + UINT16 Length, + UINT8 DescType, + UINT8 DescIndex +) +{ + EFI_STATUS Status; + UINT8 *DataBuffer = Buffer; + UINTN ReturnValue; + + if (Shr64((UINTN)Buffer, 32)) { + if (gUsbBusTempBuffer == NULL || Length > (gTempBufferPages << 12)) { + if (gUsbBusTempBuffer) { + gBS->FreePages((EFI_PHYSICAL_ADDRESS)gUsbBusTempBuffer, gTempBufferPages); + gUsbBusTempBuffer = NULL; + gTempBufferPages = 0; + } + gTempBufferPages = EFI_SIZE_TO_PAGES(Length); + gUsbBusTempBuffer = (UINT8*)0xFFFFFFFF; + Status = gBS->AllocatePages(AllocateMaxAddress, EfiBootServicesData, + gTempBufferPages, (EFI_PHYSICAL_ADDRESS*)&gUsbBusTempBuffer); + if (!EFI_ERROR(Status)) { + gBS->SetMem (gUsbBusTempBuffer, gTempBufferPages << 12, 0); + } else { + gUsbBusTempBuffer = NULL; + gTempBufferPages = 0; + } + } + + if (gUsbBusTempBuffer) { + DataBuffer = gUsbBusTempBuffer; + } + } + ReturnValue = UsbSmiCore(opUSBCORE_GetDescriptor, + HostController, Device, DataBuffer, Length, DescType, DescIndex); + + if (ReturnValue == 0) { + return NULL; + } + + if (DataBuffer != Buffer) { + gBS->CopyMem (Buffer, DataBuffer, Length); + } + + return Buffer; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: UsbSmiReConfigDevice +// +// Description: +// Perform the device specific configuration +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +UsbSmiReConfigDevice( + HC_STRUC* HostController, + DEV_INFO* Device +) +{ + return (UINT8)UsbSmiCore(opUSBCORE_ReConfigDevice, HostController, Device); +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: UsbAllocDevInfo +// +// Description: +// Allocate the empty buffer for USB device +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +DEV_INFO* +UsbAllocDevInfo() +{ + return (DEV_INFO*)UsbSmiCore(opUSBCORE_AllocDevInfo, 1); +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: UsbPrepareForLegacyOS +// +// Description: +// Callback on LEGACY_BOOT event +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID UsbPrepareForLegacyOS() +{ + UsbSmiCore(opUSBCORE_PrepareForLegacyOS, 1); +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: UsbResetAndReconfigDev +// +// Description: +// +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +UsbResetAndReconfigDev( + HC_STRUC* HostController, + DEV_INFO* Device +) +{ + return (UINT8)UsbSmiCore(opUSBCORE_ResetAndReconfigDev, HostController, Device); +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: UsbDevDriverDisconnect +// +// Description: +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +UsbDevDriverDisconnect( + HC_STRUC* HostController, + DEV_INFO* Device +) +{ + return (UINT8)UsbSmiCore(opUSBCORE_DevDriverDisconnect, HostController, Device); +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: UsbSmiHc +// +// Description: +// Bridge between DXE code and SMI function in USB HC driver. +// +// Input: +// Func - function number opHC_XXX which corresponds to index in HCD_HEADER +// HcType - type of USB HC controller; selects an HC driver to call +// Rest of the parameters coresponds the callee interface +// +// Output: +// Whatever callee returns +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +int HcprocStackSize[] = { + sizeof(VOID*) * 1, // opHC_Start + sizeof(VOID*) * 1, // opHC_Stop + sizeof(VOID*) * 1, // opHC_EnumeratePorts + sizeof(VOID*) * 1, // opHC_DisableInterrupts + sizeof(VOID*) * 1, // opHC_EnableInterrupts + sizeof(VOID*) * 1, // opHC_ProcessInterrupt + sizeof(VOID*) * 3, // opHC_GetRootHubStatus + sizeof(VOID*) * 2, // opHC_DisableRootHub + sizeof(VOID*) * 2, // opHC_EnableRootHub + sizeof(VOID*) * 7, // opHC_ControlTransfer + sizeof(VOID*) * 5, // opHC_BulkTransfer + sizeof(VOID*) * 6, // opHC_InterruptTransfer + sizeof(VOID*) * 2, // opHC_DeactivatePolling + sizeof(VOID*) * 2, // opHC_ActivatePolling + sizeof(VOID*) * 1, // opHC_DisableKeyRepeat + sizeof(VOID*) * 1, // opHC_EnableKeyRepeat + sizeof(VOID*) * 3, // opHC_EnableEndpoints + sizeof(VOID*) * 4, // opHC_InitDeviceData + sizeof(VOID*) * 2, // opHC_DeinitDeviceData + sizeof(VOID*) * 2, // opHC_ResetRootHub + sizeof(VOID*) * 3, // opHC_ClearEndpointState + sizeof(VOID*) * 1, // opHC_GlobalSuspend +}; + +UINTN +UsbSmiHc( + UINT8 Func, + UINT8 HcType, + ... +) +{ + URP_STRUC Params; + VA_LIST ArgList; + + ASSERT(Func < sizeof(HcprocStackSize)/sizeof(int)); + ASSERT( HcprocStackSize[Func] > 0); + + VA_START(ArgList, HcType); + + Params.bFuncNumber = USB_API_HC_PROC; + Params.bSubFunc = Func; + Params.bRetValue = USB_ERROR; //(EIP91840+) + Params.ApiData.HcProc.paramBuffer = &VA_ARG(ArgList, int); + Params.ApiData.HcProc.paramSize = HcprocStackSize[Func]; + Params.ApiData.HcProc.bHCType = HcType; + Params.ApiData.HcProc.retVal = 0; //(EIP91840+) + USB_DEBUG(DEBUG_USBHC_LEVEL8, + "call HC SMI driver(type:%d;func:%d); params at %x\n", + HcType, Func, Params.ApiData.HcProc.paramBuffer); + + InvokeUsbApi(&Params); + + VA_END(ArgList); +// ASSERT(Params.bRetValue == USB_SUCCESS); + + return Params.ApiData.HcProc.retVal; +} + +VOID +UsbSmiPeriodicEvent(VOID) +{ +// UsbSmiCore(opUSBCORE_PeriodicEvent); +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: UsbSmiGetRootHubStatus, UsbSmiEnableRootHub, UsbSmiDisableRootHub +// +// Description: +// Wrappers for calling USB HC driver functions in USBSMI service +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 UsbSmiGetRootHubStatus(HC_STRUC* HcStruc, UINT8 PortNum, BOOLEAN ClearChangeBits) +{ + return (UINT8)UsbSmiHc( + opHC_GetRootHubStatus, HcStruc->bHCType, HcStruc, PortNum, ClearChangeBits); +} + +UINT8 UsbSmiEnableRootHub(HC_STRUC* HcStruc, UINT8 PortNum) +{ + return (UINT8)UsbSmiHc( + opHC_EnableRootHub, HcStruc->bHCType, HcStruc, PortNum); +} + +UINT8 UsbSmiDisableRootHub(HC_STRUC* HcStruc, UINT8 PortNum) +{ + return (UINT8)UsbSmiHc( + opHC_DisableRootHub, HcStruc->bHCType, HcStruc, PortNum); +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: UsbSmiControlTransfer, UsbSmiBulkTransfer, UsbSmiInterruptTransfer +// +// Description: +// Wrappers for calling USB HC driver USB transfer functions +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + + +UINT16 +UsbSmiControlTransfer ( + HC_STRUC *HcStruc, + DEV_INFO *DevInfo, + UINT16 Request, + UINT16 Index, + UINT16 Value, + UINT8 *Buffer, + UINT16 Length) +{ + EFI_STATUS Status; + UINT8 *DataBuffer = Buffer; + UINTN ReturnValue; + + if (Shr64((UINTN)Buffer, 32)) { + if (gUsbBusTempBuffer == NULL || Length > (gTempBufferPages << 12)) { + if (gUsbBusTempBuffer) { + gBS->FreePages((EFI_PHYSICAL_ADDRESS)gUsbBusTempBuffer, gTempBufferPages); + gUsbBusTempBuffer = NULL; + gTempBufferPages = 0; + } + gTempBufferPages = EFI_SIZE_TO_PAGES(Length); + gUsbBusTempBuffer = (UINT8*)0xFFFFFFFF; + Status = gBS->AllocatePages(AllocateMaxAddress, EfiBootServicesData, + gTempBufferPages, (EFI_PHYSICAL_ADDRESS*)&gUsbBusTempBuffer); + if (!EFI_ERROR(Status)) { + gBS->SetMem (gUsbBusTempBuffer, gTempBufferPages << 12, 0); + } else { + gUsbBusTempBuffer = NULL; + gTempBufferPages = 0; + } + } + if (gUsbBusTempBuffer) { + DataBuffer = gUsbBusTempBuffer; + } + } + + if (DataBuffer != Buffer) { + if (!(Request & USB_REQ_TYPE_INPUT)) { + gBS->CopyMem(DataBuffer, Buffer, Length); + } + } + + ReturnValue = UsbSmiHc(opHC_ControlTransfer, + HcStruc->bHCType, HcStruc, DevInfo, + Request, Index, Value, DataBuffer, Length); + + if (DataBuffer != Buffer) { + if (Request & USB_REQ_TYPE_INPUT) { + gBS->CopyMem(Buffer, DataBuffer, Length); + } + } + + return (UINT16)ReturnValue; +} + +UINT32 +UsbSmiBulkTransfer( + HC_STRUC *HcStruc, + DEV_INFO *DevInfo, + UINT8 XferDir, + UINT8 *Buffer, + UINT32 Length +) +{ + EFI_STATUS Status; + UINT8 *DataBuffer = Buffer; + UINTN ReturnValue; + + if (Shr64((UINTN)Buffer, 32)) { + if (gUsbBusTempBuffer == NULL || Length > (gTempBufferPages << 12)) { + if (gUsbBusTempBuffer) { + gBS->FreePages((EFI_PHYSICAL_ADDRESS)gUsbBusTempBuffer, gTempBufferPages); + gUsbBusTempBuffer = NULL; + gTempBufferPages = 0; + } + gTempBufferPages = EFI_SIZE_TO_PAGES(Length); + gUsbBusTempBuffer = (UINT8*)0xFFFFFFFF; + Status = gBS->AllocatePages(AllocateMaxAddress, EfiBootServicesData, + gTempBufferPages, (EFI_PHYSICAL_ADDRESS*)&gUsbBusTempBuffer); + if (!EFI_ERROR(Status)) { + gBS->SetMem (gUsbBusTempBuffer, gTempBufferPages << 12, 0); + } else { + gUsbBusTempBuffer = NULL; + gTempBufferPages = 0; + } + } + if (gUsbBusTempBuffer) { + DataBuffer = gUsbBusTempBuffer; + } + } + + if (DataBuffer != Buffer) { + if (!(XferDir & BIT7)) { + gBS->CopyMem(DataBuffer, Buffer, Length); + } + } + + ReturnValue = UsbSmiHc(opHC_BulkTransfer, + HcStruc->bHCType, HcStruc, DevInfo, XferDir, DataBuffer, Length); + + if (DataBuffer != Buffer) { + if (XferDir & BIT7) { + gBS->CopyMem(Buffer, DataBuffer, Length); + } + } + + return (UINT32)ReturnValue; +} + +UINT16 +UsbSmiInterruptTransfer ( + HC_STRUC* HcStruc, + DEV_INFO* DevInfo, + UINT8 EndpointAddress, + UINT16 MaxPktSize, + UINT8 *Buffer, + UINT16 Length +) +{ + EFI_STATUS Status; + UINT8 *DataBuffer = Buffer; + UINTN ReturnValue; + + if (Shr64((UINTN)Buffer, 32)) { + if (gUsbBusTempBuffer == NULL || Length > (gTempBufferPages << 12)) { + if (gUsbBusTempBuffer) { + gBS->FreePages((EFI_PHYSICAL_ADDRESS)gUsbBusTempBuffer, gTempBufferPages); + gUsbBusTempBuffer = NULL; + gTempBufferPages = 0; + } + gTempBufferPages = EFI_SIZE_TO_PAGES(Length); + gUsbBusTempBuffer = (UINT8*)0xFFFFFFFF; + Status = gBS->AllocatePages(AllocateMaxAddress, EfiBootServicesData, + gTempBufferPages, (EFI_PHYSICAL_ADDRESS*)&gUsbBusTempBuffer); + if (!EFI_ERROR(Status)) { + gBS->SetMem (gUsbBusTempBuffer, gTempBufferPages << 12, 0); + } else { + gUsbBusTempBuffer = NULL; + gTempBufferPages = 0; + } + } + if (gUsbBusTempBuffer) { + DataBuffer = gUsbBusTempBuffer; + } + } + + if (DataBuffer != Buffer) { + if (EndpointAddress & BIT7) { + gBS->CopyMem(DataBuffer, Buffer, Length); + } + } + + ReturnValue = UsbSmiHc(opHC_InterruptTransfer, + HcStruc->bHCType, HcStruc, DevInfo, EndpointAddress, MaxPktSize, Length); + + if (DataBuffer != Buffer) { + if (EndpointAddress & BIT7) { + gBS->CopyMem(Buffer, DataBuffer, Length); + } + } + + return (UINT8)ReturnValue; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: UsbSmiActivatePolling, UsbSmiDeactivatePolling +// +// Description: +// Wrappers for calling USB HC driver USB polling functions +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 UsbSmiDeactivatePolling (HC_STRUC* HostController, DEV_INFO* DevInfo ) +{ + return (UINT8)UsbSmiHc( opHC_DeactivatePolling, + HostController->bHCType, HostController, DevInfo ); +} + +UINT8 UsbSmiActivatePolling (HC_STRUC* HostController, DEV_INFO* DevInfo ) +{ + return (UINT8)UsbSmiHc( opHC_ActivatePolling, + HostController->bHCType, HostController, DevInfo ); +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: ConvertBitmaps +// +// Description: +// Converts one bit-strng to another using a convertion table +// +// Input: +// Val - intial 32 bit wide bit-string +// BitT- array of bitmaptable_t recodrds +// Cnt - number of records in array BitT +// +// Output: +// 32-bit wide bit-string - result of conversion applied to Val +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +struct BITMAPTABLE_T {unsigned int src; unsigned int dst;}; + +UINT32 +ConvertBitmaps( + UINT32 Val, + struct BITMAPTABLE_T* BitT, + UINT32 Cnt +) +{ + UINT32 Res = 0; + UINT32 i; + for( i=0; (BitT->src !=0)&& ( i < Cnt); ++i, BitT++ ){ + if( BitT->src & Val ) + Res |= BitT->dst; + } + return Res; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: SearchDevinfoByAdr +// +// Description: +// Enumerates DEV_INFO structures in aDevInfoTable array of USB data to find +// one that matches the specified USB address and connects to a specified USB +// host controller. +// +// Input: +// DEV_INFO Start Pointer to the device info structure from +// where the search begins (if 0 start from first entry) +// DevAddr Device address +// HcStruc Pointer to the HCStruc structure +// +// Output: +// Pointer to DEV_INFO structure, NULL if device is not found +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +DEV_INFO* +SearchDevinfoByAdr( + DEV_INFO* Start, + UINT8 DevAddr, + HC_STRUC* HcStruc +) +{ + DEV_INFO* DevInfo; + DEV_INFO* Dev = gUsbData->aDevInfoTable + COUNTOF(gUsbData->aDevInfoTable); + + for ( DevInfo = Start!=NULL?Start:&gUsbData->aDevInfoTable[1]; + DevInfo != Dev; ++DevInfo ){ + if ((DevInfo->Flag & (DEV_INFO_VALID_STRUC | DEV_INFO_DEV_DUMMY)) == + DEV_INFO_VALID_STRUC) { + if(( gUsbData->HcTable[DevInfo->bHCNumber - 1] == HcStruc) && + ( DevInfo->bDeviceAddress == DevAddr )){ + return DevInfo; + } + } + } + return NULL; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: DevAddr2Info +// +// Description: +// Returns a DEV_INFO that corresponds to a device that is connected to a +// specified host controller and has a specified address +// +// Input: +// Addr Device address +// Hc Pointer to the HCStruc structure +// +// Output: +// Pointer to DEV_INFO structure, NULL if device is not found +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +DEV_INFO* +DevAddr2Info( + UINT8 Addr, + HC_STRUC* Hc +) +{ + DEV_INFO* Dev = SearchDevinfoByAdr(NULL, Addr, Hc); + USB_DEBUG(DEBUG_USBHC_LEVEL8, + "\tDevAddr2Info %x -> %x(hc:%x;hub:%x;port:%x;if:%x)\n", + Addr, Dev, Dev->bHCNumber, Dev->bHubDeviceNumber, + Dev->bHubPortNumber, Dev->bInterfaceNum ); + return Dev; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: FindOldTransfer +// +// Description: +// Searches a DEV_INFO that was used as a temporary structure for the USB transfer. +// +// Input: +// Device address +// EndPoint Interrupt Endpoint number that was assigned to temporary structure +// HCStruc Pointer to the HCStruc structure +// +// Output: +// Pointer to DeviceInfo Structure NULL if device is not found +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +DEV_INFO* +FindOldTransfer( + UINT8 DevAddr, + UINT8 EndPoint, + HC_STRUC* HcStruc +) +{ + DEV_INFO *Dev; + DEV_INFO *LastDev = gUsbData->aDevInfoTable + + COUNTOF(gUsbData->aDevInfoTable); + + for ( Dev = &gUsbData->aDevInfoTable[1]; Dev != LastDev; ++Dev ){ + if( ((Dev->Flag & (DEV_INFO_VALID_STRUC|DEV_INFO_DEV_PRESENT) )== + (DEV_INFO_VALID_STRUC|DEV_INFO_DEV_PRESENT)) && + (Dev->bHCNumber == HcStruc->bHCNumber ) && + (Dev->bDeviceAddress == DevAddr ) && + (Dev->IntInEndpoint == EndPoint )) + { + return Dev; + } + } + return NULL; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: AllocDevInfo +// +// Description: +// Allocates temporary DEV_INFO structure in USB data area for use in USB transfer. +// +// Output: +// Pointer to a DEV_INFO structure +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +DEV_INFO* +AllocDevInfo() +{ + DEV_INFO* Dev = UsbAllocDevInfo(); + ASSERT(Dev); + if(Dev){ + Dev->bDeviceType = BIOS_DEV_TYPE_USBBUS_SHADOW; + Dev->Flag |= DEV_INFO_DEV_DUMMY; + } + return Dev; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: FreeDevInfo +// +// Description: +// Marks DEV_INFO structure that it is free for use in consequent operations. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID +FreeDevInfo( + DEV_INFO* Dev +) +{ + ASSERT(Dev); + if (Dev) { + Dev->Flag &= ~(DEV_INFO_VALID_STRUC | DEV_INFO_DEV_PRESENT | DEV_INFO_DEV_DUMMY); + } +} + +UINT8 +TranslateInterval( + UINT8 Speed, + UINTN Interval +) +{ + UINT8 BitCount = 0; + + if (Speed == EFI_USB_SPEED_LOW || + Speed == EFI_USB_SPEED_FULL) { + return (UINT8)Interval; + } + + for (BitCount = 0; Interval != 0; BitCount++) { + Interval >>= 1; + } + return (BitCount + 2); +} + +///////////////////////////////////////////////////////////////////////////// +// USB Host Controller API functions +///////////////////////////////////////////////////////////////////////////// + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: AmiUsbHcReset +// +// Description: +// Provides software reset for the USB host controller. +// +// Input: +// This A pointer to the EFI_USB_HC_PROTOCOL instance. Type +// EFI_USB_HC_PROTOCOL is defined in Section 14.1. +// Attributes A bit mask of the reset operation to perform. +// +// Output: +// EFI_SUCCESS The reset operation succeeded. +// EFI_INVALID_PARAMETER Attributes is not valid. +// EFI_UNSUPPORTED The type of reset specified by Attributes is +// not currently supported by the host controller +// hardware. +// EFI_DEVICE_ERROR An error was encountered while attempting to +// perform the reset operation. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS EFIAPI +AmiUsbHcReset( + IN EFI_USB_HC_PROTOCOL *This, + IN UINT16 attributes +) +{ + PROGRESS_CODE(DXE_USB_RESET); + + if (!(attributes & (EFI_USB_HC_RESET_GLOBAL | EFI_USB_HC_RESET_HOST_CONTROLLER))) + return EFI_INVALID_PARAMETER; + + USB_DEBUG(DEBUG_USBHC_LEVEL, "AmiUsbHcReset:"); + + return EFI_UNSUPPORTED; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: AmiUsbHcGetState +// +// Description: +// Protocol USB HC function that returns Host Controller state. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS +AmiUsbHcGetState( + IN EFI_USB_HC_PROTOCOL *This, + OUT EFI_USB_HC_STATE *State +) +{ + return AmiUsb2HcGetState(&GetThis1(This)->hcprotocol2, State); +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: AmiUsbHcSetState +// +// Description: +// Protocol USB HC function that sets Host Controller state. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS +AmiUsbHcSetState( + IN EFI_USB_HC_PROTOCOL *This, + IN EFI_USB_HC_STATE State +) +{ + USB_DEBUG(DEBUG_USBHC_LEVEL, "USB HC:\t\tsetState, %d\n", State); + return AmiUsb2HcSetState(&GetThis1(This)->hcprotocol2, State); +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: AmiUsbHcTransfer +// +// Description: +// Protocol USB HC function that performs USB transfer. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS EFIAPI +AmiUsbHcControlTransfer( + IN EFI_USB_HC_PROTOCOL *HcProtocol, + IN UINT8 DeviceAddress, + IN BOOLEAN IsSlowDevice, + IN UINT8 MaximumPacketLength, + IN EFI_USB_DEVICE_REQUEST *Request, + IN EFI_USB_DATA_DIRECTION TransferDirection, + IN OUT VOID *Data, + IN OUT UINTN *DataLength, + IN UINTN Timeout, + OUT UINT32 *TransferResult +) +{ + return AmiUsb2HcControlTransfer(&GetThis1(HcProtocol)->hcprotocol2, + DeviceAddress, + IsSlowDevice?EFI_USB_SPEED_LOW:EFI_USB_SPEED_FULL, + MaximumPacketLength, Request, TransferDirection, Data, + DataLength, Timeout, NULL, TransferResult); +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: AmiUsbHcBulkTransfer +// +// Description: +// Protocol USB HC function that performs USB bulk transfer. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS EFIAPI AmiUsbHcBulkTransfer( + IN EFI_USB_HC_PROTOCOL *HcProtocol, + IN UINT8 DeviceAddress, + IN UINT8 EndpointAddress, + IN UINT8 MaximumPacketLength, + IN OUT VOID *Data, + IN OUT UINTN *DataLength, + IN OUT UINT8 *DataToggle, + IN UINTN Timeout, + OUT UINT32 *TransferResult +) +{ + // + // Check for valid maximum packet length is 8, 16, 32 or 64 + // + if ( MaximumPacketLength != 8 && + MaximumPacketLength != 16 && + MaximumPacketLength != 32 && + MaximumPacketLength != 64 ) return EFI_INVALID_PARAMETER; + + return AmiUsb2HcBulkTransfer(&GetThis1(HcProtocol)->hcprotocol2, + DeviceAddress, EndpointAddress, EFI_USB_SPEED_FULL, + MaximumPacketLength, 1, &Data, DataLength, + DataToggle, Timeout, NULL, TransferResult); +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: AmiUsbHcAsyncInterruptTransfer +// +// Description: +// Protocol USB HC function that performs USB async interrupt transfer. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS EFIAPI +AmiUsbHcAsyncInterruptTransfer( + IN EFI_USB_HC_PROTOCOL *HcProtocol, + IN UINT8 DeviceAddress, + IN UINT8 EndpointAddress, + IN BOOLEAN IsSlowDevice, + IN UINT8 MaxPacket, + IN BOOLEAN IsNewTransfer, + IN OUT UINT8 *DataToggle, + IN UINTN PollingInterval , + IN UINTN DataLength, + IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallbackFunction , + IN VOID *Context) +{ + return AmiUsb2HcAsyncInterruptTransfer( + &GetThis1(HcProtocol)->hcprotocol2, + DeviceAddress, EndpointAddress, + IsSlowDevice?EFI_USB_SPEED_LOW:EFI_USB_SPEED_FULL, + MaxPacket, IsNewTransfer, DataToggle, + PollingInterval, DataLength, NULL, CallbackFunction, Context); +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: AmiUsbHcSyncInterruptTransfer +// +// Description: +// Protocol USB HC function that performs USB sync interrupt transfer. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS +EFIAPI +AmiUsbHcSyncInterruptTransfer( + IN EFI_USB_HC_PROTOCOL *HcProtocol, + IN UINT8 DeviceAddress, + IN UINT8 EndpointAddress, + IN BOOLEAN IsSlowDevice, + IN UINT8 MaximumPacketLength, + IN OUT VOID *Data, + IN OUT UINTN *DataLength, + IN OUT UINT8 *DataToggle, + IN UINTN Timeout, + OUT UINT32 *TransferResult +) +{ + return AmiUsb2HcSyncInterruptTransfer( + &GetThis1(HcProtocol)->hcprotocol2, + DeviceAddress, EndpointAddress, + IsSlowDevice?EFI_USB_SPEED_LOW:EFI_USB_SPEED_FULL, + MaximumPacketLength, + Data, DataLength, DataToggle, Timeout, NULL, TransferResult ); +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: AmiUsbHcIsochronousTransfer +// +// Description: +// Protocol USB HC function that performs USB sync isochronous transfer. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS EFIAPI +AmiUsbHcIsochronousTransfer( + IN EFI_USB_HC_PROTOCOL *This, + IN UINT8 DeviceAddress, + IN UINT8 EndpointAddress, + IN UINT8 MaximumPacketLength, + IN OUT VOID *Data, + IN OUT UINTN DataLength, + OUT UINT32 *TransferResult +) +{ + return EFI_UNSUPPORTED; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: AmiUsbHcAsyncIsochronousTransfer +// +// Description: +// Protocol USB HC function that performs USB async isochronous transfer. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS EFIAPI +AmiUsbHcAsyncIsochronousTransfer( + IN EFI_USB_HC_PROTOCOL *This, + IN UINT8 DeviceAddress, + IN UINT8 EndpointAddress, + IN UINT8 MaximumPacketLength, + IN OUT VOID *Data, + IN UINTN DataLength, + IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallback, + IN VOID *Context + ) +{ + return EFI_UNSUPPORTED; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: AmiUsbHcGetRootHubPortNumber +// +// Description: +// Protocol USB HC function that returns the number of ports of a root hub +// on a given controller. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS EFIAPI +AmiUsbHcGetRootHubPortNumber ( + IN EFI_USB_HC_PROTOCOL *HcProtocol, + OUT UINT8 *PortNumber +) +{ + HC_DXE_RECORD *This = GetThis1(HcProtocol); + + USB_DEBUG(DEBUG_USBHC_LEVEL, + "USB HC:\t\tget_roothub_port_number\n"); + + if (PortNumber == NULL) return EFI_INVALID_PARAMETER; + + *PortNumber = This->hc_data->bNumPorts; + + return EFI_SUCCESS; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: AmiUsbHcGetRootHubPortStatus +// +// Description: +// Protocol USB HC function that returns the root port status +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS EFIAPI +AmiUsbHcGetRootHubPortStatus ( + EFI_USB_HC_PROTOCOL *HcProtocol, + UINT8 PortNumber, + EFI_USB_PORT_STATUS *PortStatus +) +{ + HC_DXE_RECORD *This = GetThis1( HcProtocol ); + + static struct BITMAPTABLE_T MapTable[] = { + {USB_PORT_STAT_DEV_CONNECTED,USB_PORT_STAT_CONNECTION}, + {USB_PORT_STAT_DEV_LOWSPEED,USB_PORT_STAT_LOW_SPEED}, + {USB_PORT_STAT_DEV_SUPERSPEED, USB_PORT_STAT_SUPER_SPEED}, + {USB_PORT_STAT_DEV_SUPERSPEED_PLUS, USB_PORT_STAT_SUPER_SPEED}, + {USB_PORT_STAT_DEV_ENABLED, USB_PORT_STAT_ENABLE}, + {USB_PORT_STAT_DEV_OWNER, USB_PORT_STAT_OWNER} + }; + static struct BITMAPTABLE_T MapTable2[] = { + {USB_PORT_STAT_DEV_CONNECT_CHANGED,USB_PORT_STAT_C_CONNECTION}, + }; + + UINT8 Status1; + + USB_DEBUG(DEBUG_USBHC_LEVEL, "USB HC:\t\tget_roothub_port_status\n" ); + + if (PortStatus == NULL || PortNumber >= This->hc_data->bNumPorts) + return EFI_INVALID_PARAMETER; + + Status1 = UsbSmiGetRootHubStatus(This->hc_data,(UINT8)PortNumber + 1, TRUE); + + PortStatus->PortStatus = (UINT16)ConvertBitmaps( + Status1, MapTable, COUNTOF(MapTable)); + PortStatus->PortChangeStatus = (UINT16)ConvertBitmaps( + Status1, MapTable2, COUNTOF(MapTable2)) ; + + if (((Status1 & USB_PORT_STAT_DEV_CONNECTED) != 0) && + (Status1 & (USB_PORT_STAT_DEV_LOWSPEED | USB_PORT_STAT_DEV_FULLSPEED + | USB_PORT_STAT_DEV_SUPERSPEED | USB_PORT_STAT_DEV_SUPERSPEED_PLUS))==0) { + PortStatus->PortStatus |= USB_PORT_STAT_HIGH_SPEED; + } + + USB_DEBUG(DEBUG_USBHC_LEVEL, "\t\tStatus=%x, PortStatus=%x, PortChangeStatus=%x\n", + Status1, PortStatus->PortStatus, PortStatus->PortChangeStatus ); + + return EFI_SUCCESS; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: AmiUsbHcSetRootHubPortFeature +// +// Description: +// Protocol USB HC function set root hub port feature +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS EFIAPI +AmiUsbHcSetRootHubPortFeature( + IN EFI_USB_HC_PROTOCOL *HcProtocol, + IN UINT8 PortNumber, + IN EFI_USB_PORT_FEATURE PortFeature +) +{ + HC_DXE_RECORD *This = GetThis1(HcProtocol); + + USB_DEBUG(DEBUG_USBHC_LEVEL, "USB HC:\t\tset_roothub_port_feature\n" ); + + if ( PortNumber >= This->hc_data->bNumPorts) + return EFI_INVALID_PARAMETER; + + switch( PortFeature ){ + case EfiUsbPortEnable: + UsbSmiEnableRootHub(This->hc_data, PortNumber + 1); + break; + + default: + return EFI_INVALID_PARAMETER; + } + + return EFI_SUCCESS; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: AmiUsbHcClearRootHubPortFeature +// +// Description: +// Protocol USB HC function clear root hub port feature +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS EFIAPI +AmiUsbHcClearRootHubPortFeature( + IN EFI_USB_HC_PROTOCOL *HcProtocol, + IN UINT8 PortNumber, + IN EFI_USB_PORT_FEATURE PortFeature +) +{ + HC_DXE_RECORD *This = GetThis1(HcProtocol); + + USB_DEBUG(DEBUG_USBHC_LEVEL, "USB HC:\t\tclear_roothub_port_feature\n"); + + if (PortNumber >= This->hc_data->bNumPorts) return EFI_INVALID_PARAMETER; + + switch (PortFeature ) { + case EfiUsbPortEnable: + UsbSmiDisableRootHub(This->hc_data, PortNumber + 1); + break; + + default: + return EFI_INVALID_PARAMETER; + } + return EFI_SUCCESS; +} + + +///////////////////////////////////////////////////////////////////////////// +// USB2 Host Controller API functions +///////////////////////////////////////////////////////////////////////////// + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: AmiUsb2HcGetCapability +// +// Description: +// This is USB2HC API to get the host controller capability. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS +AmiUsb2HcGetCapability( + IN EFI_USB2_HC_PROTOCOL *This, + OUT UINT8 *MaxSpeed, + OUT UINT8 *PortNumber, + OUT UINT8 *Is64BitCapable +) +{ + HC_DXE_RECORD *Rec = GetThis(This); + + if (MaxSpeed == NULL || PortNumber == NULL || Is64BitCapable == NULL) + return EFI_INVALID_PARAMETER; + *Is64BitCapable = FALSE; // Driver currently does not support >4GB allocations + // even if controller does + //(EIP81612)> + //*MaxSpeed = (Rec->hc_data->bHCType==USB_HC_EHCI)? + // EFI_USB_SPEED_HIGH : EFI_USB_SPEED_FULL; + switch (Rec->hc_data->bHCType) { + case USB_HC_OHCI: + case USB_HC_UHCI: + *MaxSpeed = EFI_USB_SPEED_FULL; + break; + case USB_HC_EHCI: + *MaxSpeed = EFI_USB_SPEED_HIGH; + break; + case USB_HC_XHCI: + *MaxSpeed = EFI_USB_SPEED_SUPER; + break; + } + //<(EIP81612) + + *PortNumber = Rec->hc_data->bNumPorts; + + return EFI_SUCCESS; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: AmiUsb2HcReset +// +// Description: +// This is USB2HC API to perform host controller reset. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS +AmiUsb2HcReset( + IN EFI_USB2_HC_PROTOCOL *This, + IN UINT16 Attributes +) +{ + PROGRESS_CODE(DXE_USB_RESET); + + if (Attributes == 0 || (Attributes & ~(EFI_USB_HC_RESET_GLOBAL + | EFI_USB_HC_RESET_HOST_CONTROLLER | EFI_USB_HC_RESET_GLOBAL_WITH_DEBUG + | EFI_USB_HC_RESET_HOST_WITH_DEBUG))==0 ) + { + return EFI_INVALID_PARAMETER; + } + + return EFI_UNSUPPORTED; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: AmiUsb2HcGetState +// +// Description: +// This is USB2HC API to get the host controller state. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS +AmiUsb2HcGetState( + IN EFI_USB2_HC_PROTOCOL *This, + OUT EFI_USB_HC_STATE *State +) +{ + HC_DXE_RECORD *Rec = GetThis(This); + + if (State == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Rec->hc_data->dHCFlag & HC_STATE_RUNNING) { + *State = EfiUsbHcStateOperational; + return EFI_SUCCESS; + } + + if (Rec->hc_data->dHCFlag & HC_STATE_SUSPEND) { + *State = EfiUsbHcStateSuspend; + return EFI_SUCCESS; + } + + *State = EfiUsbHcStateHalt; + + return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: AmiUsb2HcSetState +// +// Description: +// This is USB2HC API to set the host controller state. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS +AmiUsb2HcSetState( + IN EFI_USB2_HC_PROTOCOL *This, + IN EFI_USB_HC_STATE State +) +{ + HC_DXE_RECORD *Rec = GetThis(This); + EFI_USB_HC_STATE CurrentState; + EFI_STATUS Status = EFI_SUCCESS; + UINT8 UsbStatus = USB_SUCCESS; + + Status = AmiUsb2HcGetState(This, &CurrentState); + + if (EFI_ERROR(Status)) { + return EFI_DEVICE_ERROR; + } + + if (CurrentState == State) { + return Status; + } + + switch (State) { + case EfiUsbHcStateHalt: + UsbStatus = (UINT8)UsbSmiHc(opHC_Stop, Rec->hc_data->bHCType, Rec->hc_data); + break; + case EfiUsbHcStateOperational: + UsbStatus = (UINT8)UsbSmiHc(opHC_Start, Rec->hc_data->bHCType, Rec->hc_data); + break; + case EfiUsbHcStateSuspend: + UsbStatus = (UINT8)UsbSmiHc(opHC_GlobalSuspend, Rec->hc_data->bHCType, Rec->hc_data); + break; + default: + Status = EFI_INVALID_PARAMETER; + break; + } + + if (UsbStatus != USB_SUCCESS) { + Status = EFI_DEVICE_ERROR; + } + + return Status; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: AsyncInterruptOnTimer +// +// Description: +// This function checks if queue has a new transfer. If yes, calls a +// callback with data from transfer. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID EFIAPI +AsyncInterruptOnTimer ( + EFI_EVENT Event, + VOID *Ctx +) +{ + USBHC_INTERRUPT_DEVNINFO_T *Idi = (USBHC_INTERRUPT_DEVNINFO_T*)Ctx; + UINT8 Lock; + VOID *Data; + + // + // Check re-entrance + // + ATOMIC({Lock = Idi->Lock; Idi->Lock = 1;}); + if(Lock) { + return; //control is already inside + } + + while((UINTN)QueueSize(&Idi->QCompleted) >= Idi->DataLength ){ + ATOMIC(Data = QueueRemoveMsg( &Idi->QCompleted, (int)Idi->DataLength )); + //TRACE((-1,"USBHC: AsyncInterruptOnTimer: calling callback...\n")); + Idi->CallbackFunction( + Data, Idi->DataLength, Idi->Context, EFI_USB_NOERROR); + } + + Idi->Lock = 0; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: AmiUsb2HcBulkTransfer +// +// Description: +// This function performs USB2 HC Bulk Transfer +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS EFIAPI +AmiUsb2HcBulkTransfer( + IN EFI_USB2_HC_PROTOCOL *HcProtocol, + IN UINT8 DeviceAddress, + IN UINT8 EndpointAddress, + IN UINT8 DeviceSpeed, + IN UINTN MaximumPacketLength, + IN UINT8 DataBuffersNumber, + IN OUT VOID *Data[EFI_USB_MAX_BULK_BUFFER_NUM], + IN OUT UINTN *DataLength, + IN OUT UINT8 *DataToggle, + IN UINTN Timeout, + IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator, + OUT UINT32 *TransferResult +) +{ + UINT32 SmiRes; + HC_DXE_RECORD *This = GetThis( HcProtocol ); + DEV_INFO* DevInfo; + DEV_INFO* DevSrc = DevAddr2Info( DeviceAddress, This->hc_data ); + UINT8 XferDir = 0; + UINT16 CurrentTimeout; + UINT8 ToggleBit = (EndpointAddress & 0xF) - 1; + + // + // Check Params + // + //(EIP81612)> + if( DevSrc == NULL || Data == NULL || Data[0] == NULL || + (*DataToggle != 0 && *DataToggle != 1) || + (DeviceSpeed != EFI_USB_SPEED_SUPER && DeviceSpeed != EFI_USB_SPEED_HIGH + && DeviceSpeed != EFI_USB_SPEED_FULL) || + *DataLength == 0 || TransferResult == NULL || + MaximumPacketLength == 0 ) { + return EFI_INVALID_PARAMETER; + } + + // + // Check for valid maximum packet length + // + if ( DeviceSpeed == EFI_USB_SPEED_SUPER && MaximumPacketLength > 1024 ) { + return EFI_INVALID_PARAMETER; + } + //<(EIP81612) + if ( DeviceSpeed == EFI_USB_SPEED_HIGH && MaximumPacketLength > 512 ) { + return EFI_INVALID_PARAMETER; + } + if ( DeviceSpeed == EFI_USB_SPEED_FULL && MaximumPacketLength > 64 ) { + return EFI_INVALID_PARAMETER; + } + + // + // Alloc DEV_INFO + // + DevInfo = AllocDevInfo(); + + if(DevInfo == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Fill DEV_INFO + // + DevInfo->bDeviceAddress = DeviceAddress; + DevInfo->bHCNumber = This->hc_data->bHCNumber; + DevInfo->bEndpointSpeed = SpeedMap[DeviceSpeed]; + DevInfo->bHubDeviceNumber = DevSrc->bHubDeviceNumber; + DevInfo->bHubPortNumber = DevSrc->bHubPortNumber; + DevInfo->DevMiscInfo = DevSrc->DevMiscInfo; //(EIP84790+) + + if( EndpointAddress & 0x80 ){ + XferDir = 0x80; + DevInfo->bBulkInEndpoint = EndpointAddress & 0xF; + DevInfo->wBulkInMaxPkt = (UINT16)MaximumPacketLength; + DevInfo->wDataInSync = (UINT16)(*DataToggle) << ToggleBit; + } else { + XferDir = 0x0; + DevInfo->bBulkOutEndpoint = EndpointAddress & 0xF; + DevInfo->wBulkOutMaxPkt = (UINT16)MaximumPacketLength; + DevInfo->wDataOutSync = (UINT16)(*DataToggle) << ToggleBit; + } + + // + // Call SMI routine and retrieve last status + // if any error + // + CRITICAL_CODE( EFI_TPL_NOTIFY, + { + CurrentTimeout = gUsbData->wTimeOutValue; + gUsbData->wTimeOutValue = (UINT16)Timeout; + gUsbData->dLastCommandStatusExtended = 0; + SmiRes = UsbSmiBulkTransfer( + This->hc_data, DevInfo, + XferDir, + (UINT8*)Data[0], + (UINT32)*DataLength ); + *TransferResult = GetTransferStatus(); + gUsbData->wTimeOutValue = CurrentTimeout; + }); + + // + // Update the data length + // + *DataLength = (UINTN)SmiRes; + + // + // Update Toggle bit + // + if( XferDir ){ + *DataToggle = (UINT8)(DevInfo->wDataInSync >> ToggleBit) & 0x1; + } else { + *DataToggle = (UINT8)(DevInfo->wDataOutSync >> ToggleBit) & 0x1; + } + FreeDevInfo(DevInfo); + + if( (*TransferResult) & EFI_USB_ERR_TIMEOUT ) { + return EFI_TIMEOUT; + } + return (*TransferResult)? EFI_DEVICE_ERROR:EFI_SUCCESS; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: AmiUsb2HcAsyncInterruptTransfer +// +// Description: +// This function performs USB2 HC Async Interrupt Transfer +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS EFIAPI +AmiUsb2HcAsyncInterruptTransfer( + IN EFI_USB2_HC_PROTOCOL *HcProtocol, + IN UINT8 DeviceAddress, + IN UINT8 EndpointAddress, + IN UINT8 DeviceSpeed, + IN UINTN MaxPacket, + IN BOOLEAN IsNewTransfer, + IN OUT UINT8 *DataToggle, + IN UINTN PollingInterval, + IN UINTN DataLength, + IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator, + IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallbackFunction , + IN VOID *Context) +{ + HC_DXE_RECORD *This = GetThis( HcProtocol ); + DEV_INFO* DevInfo; + USBHC_INTERRUPT_DEVNINFO_T* AsyncTransfer = 0; + UINT8 SmiStatus = USB_SUCCESS; + UINT8 ToggleBit = (EndpointAddress & 0xF) - 1; + + if (DeviceSpeed != EFI_USB_SPEED_SUPER && + DeviceSpeed != EFI_USB_SPEED_HIGH && + DeviceSpeed != EFI_USB_SPEED_FULL && + DeviceSpeed != EFI_USB_SPEED_LOW){ + return EFI_INVALID_PARAMETER; + } + +#if !EFI_USB_HC_INTERRUPT_OUT_SUPPORT + if (!(EndpointAddress & BIT7)) { + return EFI_INVALID_PARAMETER; + } +#endif + //<(EIP81612) + if (IsNewTransfer){ + DEV_INFO* DevInfoSrc = DevAddr2Info( DeviceAddress, This->hc_data ); + DevInfo = FindOldTransfer( DeviceAddress, EndpointAddress, This->hc_data ); + + if (DataLength == 0) { + return EFI_INVALID_PARAMETER; + } + + if (*DataToggle != 0 && *DataToggle != 1) { + return EFI_INVALID_PARAMETER; + } + + if (PollingInterval < 1 || PollingInterval > 255) { + return EFI_INVALID_PARAMETER; + } + + if( DevInfoSrc == NULL || CallbackFunction == NULL) { + return EFI_INVALID_PARAMETER; + } + if( DevInfo != NULL ){ + USB_DEBUG(DEBUG_LEVEL_3,"Stacked AsyncInterrupt request are not supported\n"); + return EFI_INVALID_PARAMETER; + } + DevInfo = AllocDevInfo(); + *DevInfo = *DevInfoSrc; + DevInfo->IntInEndpoint = EndpointAddress; + DevInfo->bEndpointSpeed = SpeedMap[DeviceSpeed]; + DevInfo->IntInMaxPkt = (UINT16)MaxPacket; //(EIP84790+) + DevInfo->bPollInterval = TranslateInterval(DeviceSpeed, PollingInterval); + DevInfo->PollingLength = (UINT16)DataLength; + + //create new transfer + gBS->AllocatePool (EfiBootServicesData, + sizeof(USBHC_INTERRUPT_DEVNINFO_T) + DataLength*INTERRUPTQUEUESIZE, + &AsyncTransfer ); + EfiZeroMem(AsyncTransfer, sizeof(USBHC_INTERRUPT_DEVNINFO_T)+ + DataLength*INTERRUPTQUEUESIZE); + DevInfo->pExtra = (UINT8*)AsyncTransfer; + AsyncTransfer->QCompleted.data = (VOID *volatile *)AsyncTransfer->Data; + AsyncTransfer->QCompleted.maxsize = (int)DataLength * INTERRUPTQUEUESIZE; + AsyncTransfer->DataLength = DataLength; + AsyncTransfer->EndpointAddress = EndpointAddress; + + DevInfo->Flag |= DEV_INFO_DEV_DUMMY; + VERIFY_EFI_ERROR( + gBS->CreateEvent ( EFI_EVENT_TIMER | EFI_EVENT_NOTIFY_SIGNAL, + EFI_TPL_CALLBACK, AsyncInterruptOnTimer, + AsyncTransfer,&AsyncTransfer->Event)); + + PollingInterval = PollingInterval < 32 ? 32 : PollingInterval; + VERIFY_EFI_ERROR( + gBS->SetTimer ( AsyncTransfer->Event, TimerPeriodic, + PollingInterval * MILLISECOND)); + AsyncTransfer->CallbackFunction = CallbackFunction; + AsyncTransfer->Context = Context; + if(EndpointAddress & 0x80) { + DevInfo->wDataInSync = (UINT16)(*DataToggle) << ToggleBit; + } else { + DevInfo->wDataOutSync = (UINT16)(*DataToggle) << ToggleBit; + } + + // + // Activate transfer + // + SmiStatus = UsbSmiActivatePolling(This->hc_data, DevInfo); + ASSERT(SmiStatus==USB_SUCCESS); + } else { + // + // Find old transfer + // + DevInfo = FindOldTransfer( + DeviceAddress, + EndpointAddress, + This->hc_data ); + if( DevInfo == NULL || DevInfo->pExtra == NULL ){ + USB_DEBUG(DEBUG_LEVEL_3,"Canceling bad AsyncInterrupt request\n"); + return EFI_INVALID_PARAMETER; + } + AsyncTransfer = (USBHC_INTERRUPT_DEVNINFO_T*)DevInfo->pExtra; + DevInfo->pExtra = 0; + // + // Deactivate transfer + // + SmiStatus = UsbSmiDeactivatePolling (This->hc_data, DevInfo); + if (DataToggle){ + if(EndpointAddress & 0x80) { + *DataToggle = (UINT8)(DevInfo->wDataInSync >> ToggleBit) & 0x1; + } else { + *DataToggle = (UINT8)(DevInfo->wDataOutSync >> ToggleBit) & 0x1; + } + } + VERIFY_EFI_ERROR(gBS->SetTimer(AsyncTransfer->Event, TimerCancel, 0)); + VERIFY_EFI_ERROR(gBS->CloseEvent (AsyncTransfer->Event)); + gBS->FreePool(AsyncTransfer); + FreeDevInfo(DevInfo); + } + + return SmiStatus == USB_SUCCESS? EFI_SUCCESS : EFI_DEVICE_ERROR; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: AmiUsb2HcSyncInterruptTransfer +// +// Description: +// This function performs USB2 HC Sync Interrupt Transfer +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS EFIAPI +AmiUsb2HcSyncInterruptTransfer( + IN EFI_USB2_HC_PROTOCOL *HcProtocol, + IN UINT8 DeviceAddress, + IN UINT8 EndpointAddress, + IN UINT8 DeviceSpeed, + IN UINTN MaximumPacketLength, + IN OUT VOID *Data, + IN OUT UINTN *DataLength, + IN OUT UINT8 *DataToggle, + IN UINTN Timeout, + IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator, + OUT UINT32 *TransferResult ) +{ + UINT16 SmiRes; + HC_DXE_RECORD *This = GetThis( HcProtocol ); + DEV_INFO *DevInfo; + DEV_INFO* DevSrc = DevAddr2Info( DeviceAddress, This->hc_data ); + UINT16 CurrentTimeout; + UINT8 ToggleBit = (EndpointAddress & 0xF) - 1; + UINT16 *wDataSync; + + if (DeviceSpeed != EFI_USB_SPEED_SUPER && + DeviceSpeed != EFI_USB_SPEED_HIGH && + DeviceSpeed != EFI_USB_SPEED_FULL && + DeviceSpeed != EFI_USB_SPEED_LOW) { + return EFI_INVALID_PARAMETER; + } + +#if !EFI_USB_HC_INTERRUPT_OUT_SUPPORT + if (!(EndpointAddress & BIT7)) { + return EFI_INVALID_PARAMETER; + } +#endif + + if (Data == NULL || DataLength == NULL || + *DataLength == 0 || TransferResult == NULL) { + return EFI_INVALID_PARAMETER; + } + + if ( DeviceSpeed == EFI_USB_SPEED_LOW && MaximumPacketLength > 8) { + return EFI_INVALID_PARAMETER; + } + + if (DeviceSpeed == EFI_USB_SPEED_FULL && MaximumPacketLength > 64) { + return EFI_INVALID_PARAMETER; + } + + if (DeviceSpeed == EFI_USB_SPEED_HIGH && MaximumPacketLength > 3072 ) { + return EFI_INVALID_PARAMETER; + } + + if (*DataToggle != 0 && *DataToggle != 1) return EFI_INVALID_PARAMETER; + + if(DevSrc == NULL) { + return EFI_INVALID_PARAMETER; + } + + DevInfo = AllocDevInfo(); + DevInfo->bDeviceAddress = DeviceAddress; + DevInfo->bHCNumber = This->hc_data->bHCNumber; + DevInfo->bEndpointSpeed = SpeedMap[DeviceSpeed]; + DevInfo->bPollInterval = TranslateInterval(DeviceSpeed, 1); + DevInfo->bHubDeviceNumber = DevSrc->bHubDeviceNumber; + DevInfo->bHubPortNumber = DevSrc->bHubPortNumber; + DevInfo->DevMiscInfo = DevSrc->DevMiscInfo; //(EIP84790+) + + wDataSync = EndpointAddress & 0x80 ? &DevInfo->wDataInSync : + &DevInfo->wDataOutSync; + + *wDataSync = (UINT16)(*DataToggle) << ToggleBit; + + CRITICAL_CODE( EFI_TPL_NOTIFY, + { + CurrentTimeout = gUsbData->wTimeOutValue; + gUsbData->wTimeOutValue = (UINT16)Timeout; + gUsbData->dLastCommandStatusExtended = 0; + SmiRes = UsbSmiInterruptTransfer( + This->hc_data, + DevInfo, + EndpointAddress, + (UINT16)MaximumPacketLength, + (UINT8*)Data, + (UINT16)*DataLength); + *TransferResult = GetTransferStatus(); + gUsbData->wTimeOutValue = CurrentTimeout; + }); + + *DataLength = (UINTN)SmiRes; + *DataToggle = (UINT8)(*wDataSync >> ToggleBit) & 0x1; + + FreeDevInfo(DevInfo); + // + // Return with error or success + // + if ( (*TransferResult) & EFI_USB_ERR_TIMEOUT ) return EFI_TIMEOUT; + return (*TransferResult)? EFI_DEVICE_ERROR:EFI_SUCCESS; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: AmiUsb2HcIsochronousTransfer +// +// Description: +// This function performs USB2 HC Isochronous Transfer +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS +EFIAPI +AmiUsb2HcIsochronousTransfer( + IN EFI_USB2_HC_PROTOCOL *This, + IN UINT8 DeviceAddress, + IN UINT8 EndPointAddress, + IN UINT8 DeviceSpeed, + IN UINTN MaximumPacketLength, + IN UINT8 DataBuffersNumber, + IN OUT VOID *Data[EFI_USB_MAX_ISO_BUFFER_NUM], + IN UINTN DataLength, + IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator, + OUT UINT32 *TransferResult +) +{ + //(EIP81612)> + if ( Data == NULL || Data[0] == NULL || DataLength == 0 || + (DeviceSpeed != EFI_USB_SPEED_SUPER && DeviceSpeed != EFI_USB_SPEED_HIGH + && DeviceSpeed != EFI_USB_SPEED_FULL) || + MaximumPacketLength > 1023 ) { + return EFI_INVALID_PARAMETER; + } + //<(EIP81612) + return EFI_UNSUPPORTED; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: AmiUsb2HcAsyncIsochronousTransfer +// +// Description: +// This function performs USB2 HC Async Isochronous Transfer +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS +EFIAPI +AmiUsb2HcAsyncIsochronousTransfer( + IN EFI_USB2_HC_PROTOCOL *This, + IN UINT8 DeviceAddress, + IN UINT8 EndPointAddress, + IN UINT8 DeviceSpeed, + IN UINTN MaximumPacketLength, + IN UINT8 DataBuffersNumber, + IN OUT VOID *Data[EFI_USB_MAX_ISO_BUFFER_NUM], + IN UINTN DataLength, + IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator, + IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack, + IN VOID *Context OPTIONAL +) +{ + //(EIP81612)> + if( Data == NULL || Data[0] == NULL || DataLength == 0 || + (DeviceSpeed != EFI_USB_SPEED_SUPER && DeviceSpeed != EFI_USB_SPEED_HIGH + && DeviceSpeed != EFI_USB_SPEED_FULL) || + MaximumPacketLength > 1023 ) { + return EFI_INVALID_PARAMETER; + } + //<EIP81612) + return EFI_UNSUPPORTED; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: AmiUsb2HcTransfer +// +// Description: +// This function performs USB2 HC Control Transfer +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS EFIAPI +AmiUsb2HcControlTransfer( + IN EFI_USB2_HC_PROTOCOL *HcProtocol, + IN UINT8 DeviceAddress, + IN UINT8 DeviceSpeed, + IN UINTN MaximumPacketLength, + IN EFI_USB_DEVICE_REQUEST *Request, + IN EFI_USB_DATA_DIRECTION TransferDirection, + IN OUT VOID *Data , + IN OUT UINTN *DataLength, + IN UINTN Timeout, + IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator, + OUT UINT32 *TransferResult +) +{ + UINT16 SmiRes; + HC_DXE_RECORD *This = GetThis( HcProtocol ); + DEV_INFO *DevInfo; + DEV_INFO *DevSrc = DevAddr2Info( DeviceAddress, This->hc_data ); + UINT16 CurrentTimeout; + EFI_STATUS Status; + + //(EIP81612)> + if ( (DeviceSpeed != EFI_USB_SPEED_SUPER && DeviceSpeed != EFI_USB_SPEED_HIGH + && DeviceSpeed != EFI_USB_SPEED_FULL && DeviceSpeed != EFI_USB_SPEED_LOW) + || DevSrc == NULL) { + return EFI_INVALID_PARAMETER; + } + //<(EIP81612) + if ( TransferDirection < EfiUsbDataIn || TransferDirection > EfiUsbNoData ) { + return EFI_INVALID_PARAMETER; + } + + if ( TransferDirection == EfiUsbNoData && (Data != NULL || *DataLength != 0) ) { + return EFI_INVALID_PARAMETER; + } + + if ( TransferDirection != EfiUsbNoData && (Data == NULL || *DataLength == 0) ) { + return EFI_INVALID_PARAMETER; + } + + if( Request == NULL || TransferResult == NULL ) { + return EFI_INVALID_PARAMETER; + } + + if ( DeviceSpeed == EFI_USB_SPEED_LOW && MaximumPacketLength != 8 ) { + return EFI_INVALID_PARAMETER; + } + + if ((DeviceSpeed == EFI_USB_SPEED_HIGH || DeviceSpeed == EFI_USB_SPEED_FULL) && + ( MaximumPacketLength != 8 && + MaximumPacketLength != 16 && + MaximumPacketLength != 32 && + MaximumPacketLength != 64 ) + ) { + return EFI_INVALID_PARAMETER; + } + //(EIP81612+)> + if ( DeviceSpeed == EFI_USB_SPEED_SUPER && MaximumPacketLength != 512 ) { + return EFI_INVALID_PARAMETER; + } + //<(EIP81612+) + + DevInfo = AllocDevInfo(); + DevInfo->bDeviceAddress = DeviceAddress; + DevInfo->bHCNumber = This->hc_data->bHCNumber; + DevInfo->bEndpointSpeed = SpeedMap[DeviceSpeed]; + DevInfo->wEndp0MaxPacket = (UINT16)MaximumPacketLength; + DevInfo->bHubDeviceNumber = DevSrc->bHubDeviceNumber; + DevInfo->bHubDeviceNumber = DevSrc->bHubDeviceNumber; + DevInfo->bHubPortNumber = DevSrc->bHubPortNumber; + DevInfo->DevMiscInfo = DevSrc->DevMiscInfo; //(EIP84790+) + + CRITICAL_CODE( EFI_TPL_NOTIFY, + { + CurrentTimeout = gUsbData->wTimeOutValue; + gUsbData->wTimeOutValue = (UINT16)Timeout; + gUsbData->dLastCommandStatusExtended = 0; + SmiRes = UsbSmiControlTransfer(This->hc_data, DevInfo, + (UINT16)((( TransferDirection == EfiUsbDataIn?1:0) << 7) | + (((UINT16)Request->RequestType)) | + (((UINT16)Request->Request)<<8)), + (UINT16)Request->Index, (UINT16)Request->Value, + (UINT8*)Data, (UINT16)Request->Length); + *TransferResult = GetTransferStatus(); + gUsbData->wTimeOutValue = CurrentTimeout; + }); + + Status = EFI_SUCCESS; +/* + if (TransferDirection == EfiUsbDataIn + && *DataLength != 0 + && SmiRes == 0) + { + // + // Some data is expected, no data is returned + // + Status = EFI_DEVICE_ERROR; + } +*/ + if( (*TransferResult) & EFI_USB_ERR_TIMEOUT ) Status = EFI_TIMEOUT; + if( (*TransferResult) & ~EFI_USB_ERR_TIMEOUT ) Status = EFI_DEVICE_ERROR; + + *DataLength = (UINTN)SmiRes; + + FreeDevInfo(DevInfo); + + return Status; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: AmiUsb2HcGetRootHubPortStatus +// +// Description: +// This function returns HC root port status. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS EFIAPI +AmiUsb2HcGetRootHubPortStatus ( + EFI_USB2_HC_PROTOCOL *HcProtocol, + UINT8 PortNumber, + EFI_USB_PORT_STATUS *PortStatus +) +{ + HC_DXE_RECORD *This = GetThis( HcProtocol ); + return AmiUsbHcGetRootHubPortStatus( + &This->hcprotocol, PortNumber, PortStatus); +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: AmiUsb2HcSetRootHubPortFeature +// +// Description: +// This function set root hub port features. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS EFIAPI +AmiUsb2HcSetRootHubPortFeature( + IN EFI_USB2_HC_PROTOCOL *HcProtocol, + IN UINT8 PortNumber, + IN EFI_USB_PORT_FEATURE PortFeature +) +{ + HC_DXE_RECORD *This = GetThis( HcProtocol ); + return AmiUsbHcSetRootHubPortFeature( + &This->hcprotocol, PortNumber, PortFeature); +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: AmiUsb2HcClearRootHubPortFeature +// +// Description: +// This function clears root hub port feature. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS EFIAPI +AmiUsb2HcClearRootHubPortFeature( + IN EFI_USB2_HC_PROTOCOL *HcProtocol, + IN UINT8 PortNumber, + IN EFI_USB_PORT_FEATURE PortFeature +) +{ + HC_DXE_RECORD *This = GetThis( HcProtocol ); + return AmiUsbHcClearRootHubPortFeature( + &This->hcprotocol, PortNumber, PortFeature); +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: FindHcStruc +// +// Description: +// Search gUsbData for information about HC linked to an EFI handle +// +// Input: +// Controller - Host Controller handle +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +HC_STRUC* FindHcStruc( + EFI_HANDLE Controller +) +{ + unsigned i; + for (i = 0; i < gUsbData->HcTableCount; i++) { + if (gUsbData->HcTable[i] == NULL) { + continue; + } + if (!(gUsbData->HcTable[i]->dHCFlag & HC_STATE_USED)) { + continue; + } + if (gUsbData->HcTable[i]->Controller == Controller ) + return gUsbData->HcTable[i]; + } + return NULL; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: UsbHcSupported +// +// Description: +// This function is a part of Driver Binding Protocol interface. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS UsbHcSupported ( + EFI_DRIVER_BINDING_PROTOCOL *This, + EFI_HANDLE Controller, + EFI_DEVICE_PATH_PROTOCOL *Dp +) +{ + EFI_STATUS Status; + VOID* Ptr; + + Status = gBS->OpenProtocol ( + Controller, + &gEfiPciIoProtocolGuid, + &Ptr, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER ); + if (EFI_ERROR (Status)) { + return Status; + } + + gBS->CloseProtocol ( + Controller, &gEfiPciIoProtocolGuid, + This->DriverBindingHandle, Controller); + + if (FindHcStruc(Controller) == NULL) { + return EFI_UNSUPPORTED; + } else + return EFI_SUCCESS; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: UsbHcStop +// +// Description: +// This function is a part of Driver Binding Protocol interface. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS EFIAPI +UsbHcStop ( + EFI_DRIVER_BINDING_PROTOCOL *This, + EFI_HANDLE Controller, + UINTN NumberOfChildren, + EFI_HANDLE *Children ) +{ + return EFI_SUCCESS; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: InstallHcProtocols +// +// Description: +// Start the AMI USB driver; Sets USB_FLAG_DRIVER_STARTED +// +// Input: +// This - Protocol instance pointer. +// ControllerHandle - Handle of device to test +// RemainingDevicePath - Not used +// +// Output: +// EFI_SUCCESS - USB HC devices were initialized. +// EFI_UNSUPPORTED - pThis device is not supported by USB driver. +// EFI_DEVICE_ERROR - pThis driver cannot be started due to device error +// EFI_OUT_OF_RESOURCES +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS +InstallHcProtocols( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN HC_STRUC *HcData +) +{ + HC_DXE_RECORD *Rec; + USB3_HOST_CONTROLLER *Usb3Hc; + + // + // Create HcDxeRecord + // + VERIFY_EFI_ERROR( + gBS->AllocatePool ( + EfiBootServicesData, + sizeof(HC_DXE_RECORD), + &Rec )); + Rec->hc_data = HcData; + Rec->pciIo = PciIo; + Rec->AsyncTransfers.pHead = NULL; + Rec->AsyncTransfers.pTail = NULL; + Rec->AsyncTransfers.Size = 0; + + Rec->hcprotocol.Reset = AmiUsbHcReset; + Rec->hcprotocol.GetState = AmiUsbHcGetState; + Rec->hcprotocol.SetState = AmiUsbHcSetState; + Rec->hcprotocol.ControlTransfer = AmiUsbHcControlTransfer; + Rec->hcprotocol.BulkTransfer = AmiUsbHcBulkTransfer; + Rec->hcprotocol.AsyncInterruptTransfer = AmiUsbHcAsyncInterruptTransfer; + Rec->hcprotocol.SyncInterruptTransfer = AmiUsbHcSyncInterruptTransfer; + Rec->hcprotocol.IsochronousTransfer = AmiUsbHcIsochronousTransfer; + Rec->hcprotocol.AsyncIsochronousTransfer = AmiUsbHcAsyncIsochronousTransfer; + Rec->hcprotocol.GetRootHubPortNumber = AmiUsbHcGetRootHubPortNumber; + Rec->hcprotocol.GetRootHubPortStatus = AmiUsbHcGetRootHubPortStatus; + Rec->hcprotocol.SetRootHubPortFeature = AmiUsbHcSetRootHubPortFeature; + Rec->hcprotocol.ClearRootHubPortFeature = AmiUsbHcClearRootHubPortFeature; + + // + // Fill USB Revision fields based on type of HC + // + // USB_HC_UHCI USB_HC_OHCI -> 1.1 + // USB_HC_EHCI -> 2.0 + // USB_HC_XHCI 0.96, 1.0 -> 3.0 + // USB_HC_XHCI 1.1 -> 3.1 + + switch (HcData->bHCType) { + case USB_HC_UHCI: + case USB_HC_OHCI: + Rec->hcprotocol.MajorRevision = 1; + Rec->hcprotocol.MinorRevision = 1; + break; + case USB_HC_EHCI: + Rec->hcprotocol.MajorRevision = 2; + Rec->hcprotocol.MinorRevision = 0; + break; + case USB_HC_XHCI: + Rec->hcprotocol.MajorRevision = 3; + Usb3Hc = (USB3_HOST_CONTROLLER*)HcData->usbbus_data; + if (Usb3Hc->HciVersion <= 0x0100) { + Rec->hcprotocol.MinorRevision = 0; + } else { + Rec->hcprotocol.MinorRevision = 1; + } + break; + default: + break; + } + + Rec->hcprotocol2.GetCapability = AmiUsb2HcGetCapability; + Rec->hcprotocol2.Reset = AmiUsb2HcReset; + Rec->hcprotocol2.GetState = AmiUsb2HcGetState; + Rec->hcprotocol2.SetState = AmiUsb2HcSetState; + Rec->hcprotocol2.ControlTransfer = AmiUsb2HcControlTransfer; + Rec->hcprotocol2.BulkTransfer = AmiUsb2HcBulkTransfer; + Rec->hcprotocol2.AsyncInterruptTransfer = AmiUsb2HcAsyncInterruptTransfer; + Rec->hcprotocol2.SyncInterruptTransfer = AmiUsb2HcSyncInterruptTransfer; + Rec->hcprotocol2.IsochronousTransfer = AmiUsb2HcIsochronousTransfer; + Rec->hcprotocol2.AsyncIsochronousTransfer = AmiUsb2HcAsyncIsochronousTransfer; + Rec->hcprotocol2.GetRootHubPortStatus = AmiUsb2HcGetRootHubPortStatus; + Rec->hcprotocol2.SetRootHubPortFeature = AmiUsb2HcSetRootHubPortFeature; + Rec->hcprotocol2.ClearRootHubPortFeature = AmiUsb2HcClearRootHubPortFeature; + Rec->hcprotocol2.MajorRevision = Rec->hcprotocol.MajorRevision; + Rec->hcprotocol2.MinorRevision = Rec->hcprotocol.MinorRevision; + + + // + // Instal USB_HC_PROTOCOL + // + VERIFY_EFI_ERROR( + gBS->InstallProtocolInterface( &Controller, + &gEfiUsbHcProtocolGuid, EFI_NATIVE_INTERFACE, &Rec->hcprotocol )); + VERIFY_EFI_ERROR( + gBS->InstallProtocolInterface( &Controller, + &gEfiUsb2HcProtocolGuid, EFI_NATIVE_INTERFACE, &Rec->hcprotocol2 )); + + return EFI_SUCCESS; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: XhciAllocateScratchpadBuffers +// +// Description: +// This function allocates XHCI scratchpad buffers. Data initialization will +// be done later, in SMI XhciStart function. +// +// Notes: +// Usb3Hc->DcbaaPtr points to the beginning of memory block first 2048 Bytes +// of which is used for DCBAA. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS +XhciAllocateScratchpadBuffers ( + IN USB3_HOST_CONTROLLER *Usb3Hc +) +{ + UINT16 NumBufs = ((Usb3Hc->CapRegs->HcsParams2.MaxScratchPadBufsHi) << 5) + + Usb3Hc->CapRegs->HcsParams2.MaxScratchPadBufsLo; + UINT16 Count; + VOID *Buffer; + + if (NumBufs == 0) { + return EFI_SUCCESS; + } + + if (Usb3Hc->ScratchBufEntry == NULL) { + // Allcate a PAGESIZE boundary for Scratchpad Buffer Array Base Address + // because bit[0..5] are reserved in Device Context Base Address Array Element 0. + Usb3Hc->ScratchBufEntry = AllocateHcMemory(Usb3Hc->PciIo, + EFI_SIZE_TO_PAGES((sizeof(UINT64) * NumBufs)), 0x1000); + + if (Usb3Hc->ScratchBufEntry == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + gBS->SetMem(Usb3Hc->ScratchBufEntry, (sizeof(UINT64) * NumBufs), 0); + + for (Count = 0; Count < NumBufs; Count++) { + + // Allocate scratchpad buffer: PAGESIZE block located on + // a PAGESIZE boundary. Section 4.20. + Buffer = AllocateHcMemory(Usb3Hc->PciIo, + Usb3Hc->PageSize4K, Usb3Hc->PageSize4K << 12); + ASSERT(Buffer != NULL); // See if allocation is successful + + if (Buffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // Update *ScratchBufArrayBase + Usb3Hc->ScratchBufEntry[Count] = (UINTN)Buffer; + } + } + + // Update scratchpad pointer only if # of scratch buffers >0 + if (NumBufs > 0) { + *(UINTN*)Usb3Hc->DcbaaPtr = (UINTN)Usb3Hc->ScratchBufEntry; + } + + return EFI_SUCCESS; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: XhciInitMemory +// +// Description: +// This function allocates XHCI memory buffers. Data initialization will be +// done later, in SMI XhciStart function. These are the memory blocks: +// +// 1. DCBAAP + ScrPadBuf pointers + InpCtx + ERST <-- 8KB +// 2. CommandRing <-- 1KB +// 3. EventRing <-- 1KB +// 4. XferRings <-- 1KB*MaxSlots, 1KB = 32EP per slot times 32 (padded size of TRB_RING) +// 4. N*sizeof(XHCI_DEVICE_CONTEXT) for device context segment <-- N KB or 2*N KB, +// N is SlotNumber from CONFIG register +// +// 5. TransferRings <-- MaxSlots*32*1KB +// +// Notes: +// Scratchpad buffers are optional, they are allocated and initialized separately. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS +XhciInitMemory ( + IN USB3_HOST_CONTROLLER *Usb3Hc +) +{ + EFI_STATUS Status; + UINTN MemSize; + UINTN DeviceContextSize; + UINTN XfrRingsSize; + UINTN XfrTrbsSize; + + XfrRingsSize = Usb3Hc->MaxSlots * 32 * 32; // 32 endpoints per device, 32 padded size of TRB_RING + XfrTrbsSize = RING_SIZE*Usb3Hc->MaxSlots*32; + DeviceContextSize = (XHCI_DEVICE_CONTEXT_ENTRIES * Usb3Hc->ContextSize) * Usb3Hc->MaxSlots; + + MemSize = 0x2800 + XfrRingsSize + XfrTrbsSize + DeviceContextSize; + if (Usb3Hc->DcbaaPtr == NULL) { + Usb3Hc->DcbaaPtr = (XHCI_DCBAA*)AllocateHcMemory(Usb3Hc->PciIo, + EFI_SIZE_TO_PAGES(MemSize), 0x1000); + } + gBS->SetMem(Usb3Hc->DcbaaPtr, MemSize, 0); // Clear buffer + + USB_DEBUG(3, "XHCI: Memory allocation - total %x Bytes:\n 0x2800+XfrRings(%x)+XfrTrbs(%x)+DevCtx(%x)\n", + MemSize, XfrRingsSize, XfrTrbsSize, DeviceContextSize); + + // Assign DCBAA (Device Context Base Address); program the + // DCBAA Pointer (DCBAAP) register (5.4.6) with a 64-bit address + // pointing to where the Device Context Base Address Array is located. + // + // DCBAA: size 2048 Bytes, within PAGESIZE, 64 Bytes aligned. + // + // These requirements can be met by allocating 1 page using + // pBS->AllocatePages; the address will be 4K aligned and will + // not span PAGESIZE boundary. + + Status = XhciAllocateScratchpadBuffers(Usb3Hc); + ASSERT_EFI_ERROR(Status); + + // Assign Input Context; the size of Input Context is either + // 0x420 or 0x840 depending on HCPARAMS.Csz + if (Usb3Hc->InputContext == NULL) { + Usb3Hc->InputContext = (VOID*)((UINTN)Usb3Hc->DcbaaPtr + 0x940); + } + + // Initialize Transfer Rings pointer and store it in Usb3Hc; actual + // xfer ring initialization happens later, when the EP is being enabled + if (Usb3Hc->XfrRings == NULL) { + Usb3Hc->XfrRings = (TRB_RING*)((UINTN)Usb3Hc->DcbaaPtr + 0x2800); + } + + // 1024 = 32 bytes is padded sizeof(TRB_RING) times 32 EP per device + if (Usb3Hc->XfrTrbs == NULL) { + Usb3Hc->XfrTrbs = (UINTN)Usb3Hc->XfrRings + XfrRingsSize; + } + + // Assign device context memory: Usb3Hc->MaxSlots devices, + // 1024 (2048 if HCPARAMS.Csz is set) Bytes each + if (Usb3Hc->DeviceContext == NULL) { + Usb3Hc->DeviceContext = (VOID*)((UINTN)Usb3Hc->XfrTrbs + XfrTrbsSize); + } + + return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: XhciExtCapParser +// +// Description: +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS +XhciExtCapParser( + IN USB3_HOST_CONTROLLER *Usb3Hc +) +{ + XHCI_EXT_CAP *CurPtr; + + if (Usb3Hc->CapRegs->HccParams1.Xecp == 0) return EFI_SUCCESS; + + // Starts from first capability + CurPtr = (XHCI_EXT_CAP *)((UINTN)Usb3Hc->CapRegs + (Usb3Hc->CapRegs->HccParams1.Xecp << 2)); + + // Traverse all capability structures + for(;;) { + switch (CurPtr->CapId) { + case XHCI_EXT_CAP_USB_LEGACY: + Usb3Hc->ExtLegCap = (XHCI_EXT_LEG_CAP *)CurPtr; + // Clear HC BIOS Owned Semaphore bit + Usb3Hc->ExtLegCap->LegSup.HcBiosOwned = 0; + // Clear HC OS Owned Semaphore bit + Usb3Hc->ExtLegCap->LegSup.HcOsOwned = 0; + // Clear SMI enable bit + Usb3Hc->ExtLegCap->LegCtlSts.UsbSmiEnable = 0; + Usb3Hc->ExtLegCap->LegCtlSts.UsbOwnershipChangeSmiEnable = 0; + USB_DEBUG(3, "XHCI: USB Legacy Ext Cap Ptr %x\n", Usb3Hc->ExtLegCap); + break; + + case XHCI_EXT_CAP_SUPPORTED_PROTOCOL: + if (((XHCI_EXT_PROTOCOL*)CurPtr)->MajorRev == 0x02) { + Usb3Hc->Usb2Protocol = (XHCI_EXT_PROTOCOL*)CurPtr; + USB_DEBUG(3, "XHCI: USB2 Support Protocol %x, PortOffset %x PortCount %x\n", + Usb3Hc->Usb2Protocol, Usb3Hc->Usb2Protocol->PortOffset, Usb3Hc->Usb2Protocol->PortCount); + } else if (((XHCI_EXT_PROTOCOL*)CurPtr)->MajorRev == 0x03) { + Usb3Hc->Usb3Protocol = (XHCI_EXT_PROTOCOL*)CurPtr; + USB_DEBUG(3, "XHCI: USB3 Support Protocol %x, PortOffset %x PortCount %x\n", + Usb3Hc->Usb3Protocol, Usb3Hc->Usb3Protocol->PortOffset, Usb3Hc->Usb3Protocol->PortCount); + } + break; + + case XHCI_EXT_CAP_POWERMANAGEMENT: + case XHCI_EXT_CAP_IO_VIRTUALIZATION: + break; + case XHCI_EXT_CAP_USB_DEBUG_PORT: + Usb3Hc->DbCapRegs = (XHCI_DB_CAP_REGS*)CurPtr; + USB_DEBUG(3, "XHCI: USB Debug Capability Ptr %x\n", Usb3Hc->DbCapRegs); + break; + } + if(CurPtr->NextCapPtr == 0) break; + // Point to next capability + CurPtr=(XHCI_EXT_CAP *)((UINTN)CurPtr+ (((UINTN)CurPtr->NextCapPtr) << 2)); + } + + return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: PreInitXhci +// +// Description: +// This function initializes XHCI data structures, allocates HC memory and +// updates the relevant fields in HcStruc. At this point the controller's +// resources are assigned and accessible. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS +PreInitXhci( + EFI_HANDLE Handle, + HC_STRUC *HcStruc +) +{ +#if XHCI_SUPPORT + UINT8 MaxSlots; + EFI_STATUS Status; + USB3_HOST_CONTROLLER *Usb3Hc = NULL; + + if (HcStruc->usbbus_data == NULL) { + Status = gBS->AllocatePool(EfiRuntimeServicesData, + sizeof(USB3_HOST_CONTROLLER), &Usb3Hc); + if (EFI_ERROR(Status)) { + return Status; + } + + gBS->SetMem(Usb3Hc, sizeof(USB3_HOST_CONTROLLER), 0); + } else { + Usb3Hc = HcStruc->usbbus_data; + } + + Usb3Hc->Controller = Handle; + Status = gBS->HandleProtocol(Handle, &gEfiPciIoProtocolGuid, &Usb3Hc->PciIo); + ASSERT_EFI_ERROR(Status); + + // Get Capability Registers offset off the BAR + //(EIP101226)> + Status = Usb3Hc->PciIo->Pci.Read(Usb3Hc->PciIo, + EfiPciIoWidthUint32, PCI_BAR0, 1, &Usb3Hc->CapRegs); + ASSERT_EFI_ERROR(Status); + if (EFI_ERROR(Status)) { + return Status; + } + if (((UINT8)(UINTN)Usb3Hc->CapRegs & (BIT1 |BIT2)) == BIT2) { + Status = Usb3Hc->PciIo->Pci.Read(Usb3Hc->PciIo, + EfiPciIoWidthUint32, PCI_BAR0, sizeof(VOID*)/sizeof(UINT32), &Usb3Hc->CapRegs); + } + + //<(EIP101226) + //clear all attributes before use + (UINT8)(UINTN)Usb3Hc->CapRegs &= ~(0x7F); // Clear attributes + + Usb3Hc->PciIo->Pci.Read(Usb3Hc->PciIo, + EfiPciIoWidthUint16, PCI_VID, 1, &Usb3Hc->Vid); + + Usb3Hc->PciIo->Pci.Read(Usb3Hc->PciIo, + EfiPciIoWidthUint16, PCI_DID, 1, &Usb3Hc->Did); + + Usb3Hc->Access64 = Usb3Hc->CapRegs->HccParams1.Ac64; + + Usb3Hc->HciVersion = Usb3Hc->CapRegs->HciVersion; + Usb3Hc->MaxPorts = Usb3Hc->CapRegs->HcsParams1.MaxPorts; + + Usb3Hc->OpRegs = (XHCI_HC_OP_REGS*)((UINTN)Usb3Hc->CapRegs + Usb3Hc->CapRegs->CapLength); + Usb3Hc->PageSize4K = Usb3Hc->OpRegs->PageSize; + Usb3Hc->ContextSize = 0x20 << Usb3Hc->CapRegs->HccParams1.Csz; + + USB_DEBUG(3, "XHCI: Cap %x, OpRegs: %x Ver %x,\n MaxPorts 0x%x, PageSize %x*4K\n", + Usb3Hc->CapRegs, Usb3Hc->OpRegs, Usb3Hc->HciVersion, Usb3Hc->MaxPorts, Usb3Hc->PageSize4K); + + ASSERT(Usb3Hc->PageSize4K < 0x8000); // Maximum possible page size is 128MB + + Status = Usb3Hc->PciIo->Pci.Read( + Usb3Hc->PciIo, EfiPciIoWidthUint8, XHCI_PCI_SBRN, 1, &Usb3Hc->SBRN); + ASSERT_EFI_ERROR(Status); + USB_DEBUG(3, "XHCI: Serial Bus Release Number is %x\n", Usb3Hc->SBRN); + + // OEM might change the default number of MaxSlots + Status = Usb3OemGetMaxDeviceSlots(&MaxSlots); + + if (EFI_ERROR(Status)) { + // Use default number of slots + MaxSlots = Usb3Hc->CapRegs->HcsParams1.MaxSlots; + } + else { + // Validate the porting function output + ASSERT(MaxSlots > 0 && MaxSlots <= Usb3Hc->CapRegs->HcsParams1.MaxSlots); + } + Usb3Hc->MaxSlots = MaxSlots; + + // Get maximum number of interrupters + Usb3Hc->MaxIntrs = Usb3Hc->CapRegs->HcsParams1.MaxIntrs; + + Usb3Hc->DbOffset = Usb3Hc->CapRegs->DbOff; + + USB_DEBUG(3, "XHCI: MaxSlots %x, MaxIntrs %x, Doorbell Offset %x\n", Usb3Hc->MaxSlots, Usb3Hc->MaxIntrs, Usb3Hc->DbOffset); + + // Parse all capability structures + XhciExtCapParser(Usb3Hc); + + if (gUsbData->UsbXhciSupport == 0) { + gBS->FreePool(Usb3Hc); + return EFI_UNSUPPORTED; + } + + // Allocate and initialize memory blocks + Status = XhciInitMemory(Usb3Hc); + ASSERT_EFI_ERROR(Status); + if (EFI_ERROR(Status)) { + gBS->FreePool(Usb3Hc); + return Status; + } + + HcStruc->usbbus_data = (VOID*)Usb3Hc; + +#endif + + return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// Name: PostStopXhci +// +// Description: +// This function frees the HC memory and clears XHCI data structures. +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +EFI_STATUS +PostStopXhci( + EFI_HANDLE Handle, + HC_STRUC *HcStruc +) +{ +#if XHCI_SUPPORT +/* + USB3_HOST_CONTROLLER *Usb3Hc = (USB3_HOST_CONTROLLER*)HcStruc->usbbus_data; + UINT16 NumBufs = ((Usb3Hc->CapRegs->HcsParams2.MaxScratchPadBufsHi) << 5) + + Usb3Hc->CapRegs->HcsParams2.MaxScratchPadBufsLo; + UINT16 Count; + UINTN MemSize; + UINTN DeviceContextSize; + UINTN XfrRingsSize; + UINTN XfrTrbsSize; + + for (Count = 0; Count < NumBufs; Count++) { + gBS->FreePages((EFI_PHYSICAL_ADDRESS)(Usb3Hc->ScratchBufEntry[Count]), Usb3Hc->PageSize4K); + } + + XfrRingsSize = Usb3Hc->MaxSlots * 32 * 32; // 32 endpoints per device, 32 padded size of TRB_RING + XfrTrbsSize = RING_SIZE * Usb3Hc->MaxSlots * 32; + DeviceContextSize = (XHCI_DEVICE_CONTEXT_ENTRIES * Usb3Hc->ContextSize) * Usb3Hc->MaxSlots; + + MemSize = 0x2800 + XfrRingsSize + XfrTrbsSize + DeviceContextSize; + + gBS->FreePages((EFI_PHYSICAL_ADDRESS)Usb3Hc->DcbaaPtr, EFI_SIZE_TO_PAGES(MemSize)); + if (Usb3Hc->ScratchBufEntry) { + gBS->FreePages((EFI_PHYSICAL_ADDRESS)Usb3Hc->ScratchBufEntry, EFI_SIZE_TO_PAGES((sizeof(UINT64) * NumBufs))); + } + gBS->FreePool(Usb3Hc); +*/ +#endif + return EFI_SUCCESS; +} + +//**************************************************************************** +//**************************************************************************** +//** ** +//** (C)Copyright 1985-2016, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Norcross, GA 30093 ** +//** ** +//** Phone (770)-246-8600 ** +//** ** +//**************************************************************************** +//**************************************************************************** |