//**************************************************************************** //**************************************************************************** //** ** //** (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 //**************************************************************************** // // // Name: AmuUsbHc.c // // Description: USB_HC_PROTOCOL implementation // // //**************************************************************************** #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; // //--------------------------------------------------------------------------- // // Name: GetThis // // Description: // Function returns a pointer to HcProtocol2 record of a given protocol // //--------------------------------------------------------------------------- // static HC_DXE_RECORD* GetThis(EFI_USB2_HC_PROTOCOL* Protocol) { return (HC_DXE_RECORD*)( (char*)Protocol - (UINTN)&((HC_DXE_RECORD*)0)->hcprotocol2 ); } // //--------------------------------------------------------------------------- // // Name: GetThis1 // // Description: // Function returns a pointer to HcProtocol record of a given protocol // //--------------------------------------------------------------------------- // static HC_DXE_RECORD* GetThis1 (EFI_USB_HC_PROTOCOL* Protocol) { return (HC_DXE_RECORD*)( (char*)Protocol - (UINTN)&((HC_DXE_RECORD*)0)->hcprotocol ); } // //--------------------------------------------------------------------------- // // Name: GetTransferStatus // // Description: // Function converts the bitmap of gUsbData->dLastCommandStatusExtended into // a valid USB error. // //--------------------------------------------------------------------------- // 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 //--------------------------------------------------------------------------- // // 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 // //--------------------------------------------------------------------------- // 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; } // //--------------------------------------------------------------------------- // // Name: UsbSmiGetDescriptor // // Description: // SW SMI to execute GetDescriptor transfer // //--------------------------------------------------------------------------- // 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; } // //--------------------------------------------------------------------------- // // Name: UsbSmiReConfigDevice // // Description: // Perform the device specific configuration // //--------------------------------------------------------------------------- // UINT8 UsbSmiReConfigDevice( HC_STRUC* HostController, DEV_INFO* Device ) { return (UINT8)UsbSmiCore(opUSBCORE_ReConfigDevice, HostController, Device); } // //--------------------------------------------------------------------------- // // Name: UsbAllocDevInfo // // Description: // Allocate the empty buffer for USB device // //--------------------------------------------------------------------------- // DEV_INFO* UsbAllocDevInfo() { return (DEV_INFO*)UsbSmiCore(opUSBCORE_AllocDevInfo, 1); } // //--------------------------------------------------------------------------- // // Name: UsbPrepareForLegacyOS // // Description: // Callback on LEGACY_BOOT event // //--------------------------------------------------------------------------- // VOID UsbPrepareForLegacyOS() { UsbSmiCore(opUSBCORE_PrepareForLegacyOS, 1); } // //--------------------------------------------------------------------------- // // Name: UsbResetAndReconfigDev // // Description: // // //--------------------------------------------------------------------------- // UINT8 UsbResetAndReconfigDev( HC_STRUC* HostController, DEV_INFO* Device ) { return (UINT8)UsbSmiCore(opUSBCORE_ResetAndReconfigDev, HostController, Device); } // //--------------------------------------------------------------------------- // // Name: UsbDevDriverDisconnect // // Description: // //--------------------------------------------------------------------------- // UINT8 UsbDevDriverDisconnect( HC_STRUC* HostController, DEV_INFO* Device ) { return (UINT8)UsbSmiCore(opUSBCORE_DevDriverDisconnect, HostController, Device); } // //--------------------------------------------------------------------------- // // 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 // //--------------------------------------------------------------------------- // 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); } // //--------------------------------------------------------------------------- // // Name: UsbSmiGetRootHubStatus, UsbSmiEnableRootHub, UsbSmiDisableRootHub // // Description: // Wrappers for calling USB HC driver functions in USBSMI service // //--------------------------------------------------------------------------- // 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); } // //--------------------------------------------------------------------------- // // Name: UsbSmiControlTransfer, UsbSmiBulkTransfer, UsbSmiInterruptTransfer // // Description: // Wrappers for calling USB HC driver USB transfer functions // //--------------------------------------------------------------------------- // 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; } // //--------------------------------------------------------------------------- // // Name: UsbSmiActivatePolling, UsbSmiDeactivatePolling // // Description: // Wrappers for calling USB HC driver USB polling functions // //--------------------------------------------------------------------------- // 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 ); } // //--------------------------------------------------------------------------- // // 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 // //--------------------------------------------------------------------------- // 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; } // //--------------------------------------------------------------------------- // // 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 // //--------------------------------------------------------------------------- // 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; } // //--------------------------------------------------------------------------- // // 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 // //--------------------------------------------------------------------------- // 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; } // //--------------------------------------------------------------------------- // // 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 // //--------------------------------------------------------------------------- // 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; } // //--------------------------------------------------------------------------- // // Name: AllocDevInfo // // Description: // Allocates temporary DEV_INFO structure in USB data area for use in USB transfer. // // Output: // Pointer to a DEV_INFO structure // //--------------------------------------------------------------------------- // 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; } // //--------------------------------------------------------------------------- // // Name: FreeDevInfo // // Description: // Marks DEV_INFO structure that it is free for use in consequent operations. // //--------------------------------------------------------------------------- // 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 ///////////////////////////////////////////////////////////////////////////// // //--------------------------------------------------------------------------- // // 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. // //--------------------------------------------------------------------------- // 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; } // //--------------------------------------------------------------------------- // // Name: AmiUsbHcGetState // // Description: // Protocol USB HC function that returns Host Controller state. // //--------------------------------------------------------------------------- // EFI_STATUS AmiUsbHcGetState( IN EFI_USB_HC_PROTOCOL *This, OUT EFI_USB_HC_STATE *State ) { return AmiUsb2HcGetState(&GetThis1(This)->hcprotocol2, State); } // //--------------------------------------------------------------------------- // // Name: AmiUsbHcSetState // // Description: // Protocol USB HC function that sets Host Controller state. // //--------------------------------------------------------------------------- // 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); } // //--------------------------------------------------------------------------- // // Name: AmiUsbHcTransfer // // Description: // Protocol USB HC function that performs USB transfer. // //--------------------------------------------------------------------------- // 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); } // //--------------------------------------------------------------------------- // // Name: AmiUsbHcBulkTransfer // // Description: // Protocol USB HC function that performs USB bulk transfer. // //--------------------------------------------------------------------------- // 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); } // //--------------------------------------------------------------------------- // // Name: AmiUsbHcAsyncInterruptTransfer // // Description: // Protocol USB HC function that performs USB async interrupt transfer. // //--------------------------------------------------------------------------- // 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); } // //--------------------------------------------------------------------------- // // Name: AmiUsbHcSyncInterruptTransfer // // Description: // Protocol USB HC function that performs USB sync interrupt transfer. // //--------------------------------------------------------------------------- // 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 ); } // //--------------------------------------------------------------------------- // // Name: AmiUsbHcIsochronousTransfer // // Description: // Protocol USB HC function that performs USB sync isochronous transfer. // //--------------------------------------------------------------------------- // 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; } // //--------------------------------------------------------------------------- // // Name: AmiUsbHcAsyncIsochronousTransfer // // Description: // Protocol USB HC function that performs USB async isochronous transfer. // //--------------------------------------------------------------------------- // 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; } // //--------------------------------------------------------------------------- // // Name: AmiUsbHcGetRootHubPortNumber // // Description: // Protocol USB HC function that returns the number of ports of a root hub // on a given controller. // //--------------------------------------------------------------------------- // 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; } // //--------------------------------------------------------------------------- // // Name: AmiUsbHcGetRootHubPortStatus // // Description: // Protocol USB HC function that returns the root port status // //--------------------------------------------------------------------------- // 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; } // //--------------------------------------------------------------------------- // // Name: AmiUsbHcSetRootHubPortFeature // // Description: // Protocol USB HC function set root hub port feature // //--------------------------------------------------------------------------- // 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; } // //--------------------------------------------------------------------------- // // Name: AmiUsbHcClearRootHubPortFeature // // Description: // Protocol USB HC function clear root hub port feature // //--------------------------------------------------------------------------- // 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 ///////////////////////////////////////////////////////////////////////////// // //--------------------------------------------------------------------------- // // Name: AmiUsb2HcGetCapability // // Description: // This is USB2HC API to get the host controller capability. // //--------------------------------------------------------------------------- // 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; } // //--------------------------------------------------------------------------- // // Name: AmiUsb2HcReset // // Description: // This is USB2HC API to perform host controller reset. // //--------------------------------------------------------------------------- // 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; } // //--------------------------------------------------------------------------- // // Name: AmiUsb2HcGetState // // Description: // This is USB2HC API to get the host controller state. // //--------------------------------------------------------------------------- // 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; } // //--------------------------------------------------------------------------- // // Name: AmiUsb2HcSetState // // Description: // This is USB2HC API to set the host controller state. // //--------------------------------------------------------------------------- // 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; } // //--------------------------------------------------------------------------- // // Name: AsyncInterruptOnTimer // // Description: // This function checks if queue has a new transfer. If yes, calls a // callback with data from transfer. // //--------------------------------------------------------------------------- // 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; } // //--------------------------------------------------------------------------- // // Name: AmiUsb2HcBulkTransfer // // Description: // This function performs USB2 HC Bulk Transfer // //--------------------------------------------------------------------------- // 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; } // //--------------------------------------------------------------------------- // // Name: AmiUsb2HcAsyncInterruptTransfer // // Description: // This function performs USB2 HC Async Interrupt Transfer // //--------------------------------------------------------------------------- // 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; } // //--------------------------------------------------------------------------- // // Name: AmiUsb2HcSyncInterruptTransfer // // Description: // This function performs USB2 HC Sync Interrupt Transfer // //--------------------------------------------------------------------------- // 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; } // //--------------------------------------------------------------------------- // // Name: AmiUsb2HcIsochronousTransfer // // Description: // This function performs USB2 HC Isochronous Transfer // //--------------------------------------------------------------------------- // 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; } // //--------------------------------------------------------------------------- // // Name: AmiUsb2HcAsyncIsochronousTransfer // // Description: // This function performs USB2 HC Async Isochronous Transfer // //--------------------------------------------------------------------------- // 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; } // //--------------------------------------------------------------------------- // // Name: AmiUsb2HcTransfer // // Description: // This function performs USB2 HC Control Transfer // //--------------------------------------------------------------------------- // 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; } // //--------------------------------------------------------------------------- // // Name: AmiUsb2HcGetRootHubPortStatus // // Description: // This function returns HC root port status. // //--------------------------------------------------------------------------- // 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); } // //--------------------------------------------------------------------------- // // Name: AmiUsb2HcSetRootHubPortFeature // // Description: // This function set root hub port features. // //--------------------------------------------------------------------------- // 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); } // //--------------------------------------------------------------------------- // // Name: AmiUsb2HcClearRootHubPortFeature // // Description: // This function clears root hub port feature. // //--------------------------------------------------------------------------- // 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); } // //--------------------------------------------------------------------------- // // Name: FindHcStruc // // Description: // Search gUsbData for information about HC linked to an EFI handle // // Input: // Controller - Host Controller handle // //--------------------------------------------------------------------------- // 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; } // //--------------------------------------------------------------------------- // // Name: UsbHcSupported // // Description: // This function is a part of Driver Binding Protocol interface. // //--------------------------------------------------------------------------- // 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; } // //--------------------------------------------------------------------------- // // Name: UsbHcStop // // Description: // This function is a part of Driver Binding Protocol interface. // //--------------------------------------------------------------------------- // EFI_STATUS EFIAPI UsbHcStop ( EFI_DRIVER_BINDING_PROTOCOL *This, EFI_HANDLE Controller, UINTN NumberOfChildren, EFI_HANDLE *Children ) { return EFI_SUCCESS; } // //--------------------------------------------------------------------------- // // 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 // //--------------------------------------------------------------------------- // 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; } // //--------------------------------------------------------------------------- // // 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. // //--------------------------------------------------------------------------- // 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; } // //--------------------------------------------------------------------------- // // 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. // //--------------------------------------------------------------------------- // 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; } // //--------------------------------------------------------------------------- // // Name: XhciExtCapParser // // Description: // //--------------------------------------------------------------------------- // 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; } // //--------------------------------------------------------------------------- // // 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. // //--------------------------------------------------------------------------- // 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; } // //--------------------------------------------------------------------------- // // Name: PostStopXhci // // Description: // This function frees the HC memory and clears XHCI data structures. // //--------------------------------------------------------------------------- // 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 ** //** ** //**************************************************************************** //****************************************************************************