//**************************************************************************** //**************************************************************************** //** ** //** (C)Copyright 1985-2016, American Megatrends, Inc. ** //** ** //** All Rights Reserved. ** //** ** //** 5555 Oakbrook Pkwy, Norcross, GA 30093 ** //** ** //** Phone (770)-246-8600 ** //** ** //**************************************************************************** //**************************************************************************** //**************************************************************************** // $Header: /Alaska/SOURCE/Modules/USB/ALASKA/RT/uhci.c 114 10/16/16 10:12p Wilsonlee $ // // $Revision: 114 $ // // $Date: 10/16/16 10:12p $ //**************************************************************************** //**************************************************************************** // Revision History // ---------------- // $Log: /Alaska/SOURCE/Modules/USB/ALASKA/RT/uhci.c $ // // 114 10/16/16 10:12p 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 // // 113 7/22/16 3:50a 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 // // 112 7/07/16 1:09a 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 // // 111 3/14/16 10:21p Wilsonlee // [TAG] EIP257506 // [Category] Improvement // [Description] Add USB_KEYREPEAT_INTERVAL token to change the key // repeat interval. // [Files] usb.sdl, xhci.h, usbkbd.h, uhci.c, ohci.c, ehci.c // // 110 3/02/16 9:41p 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 // // 109 12/03/15 1:48a Wilsonlee // [TAG] EIP247625 // [Category] Bug Fix // [Severity] Normal // [Symptom] USB hot-plug function is failed in external uhci // controllers. // [RootCause] We don't install UhciRootHubQhCallBack for external uhci // controllers. // [Solution] Handle the hot-plug function in the periodic timer smi // handler if the uhci controller is external. // [Files] uhci.c // // 108 4/10/15 3:11a 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 // // 107 3/08/15 10:49p Wilsonlee // [TAG] EIP207774 // [Category] Improvement // [Description] Set USB_FLAG_DRIVER_STARTED flag when HC is running and // clear it if we don't start any HC. // [Files] uhci.c, usb.c, ehci.c, ohci.c, xhci.c, amiusb.h // // 106 1/22/15 10:19p 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 // // 105 6/26/14 1:15a Wilsonlee // [TAG] EIP173387 // [Category] Improvement // [Description] Remove TODO comments. // [Files] usbsetup.c, xhci.c, usbmass.c, usbCCID.c, usb.c, uhci.c, // syskbc.c, usbport.c, usbbus.c, uhcd.c, UsbBotPeim.c, PeiXhci.c, // PeiEhci.c // // 104 5/01/14 3:57a Ryanchou // [TAG] EIP162589 // [Category] Improvement // [Description] Do not register external controller as key repeat // controller. // [Files] ehci.c, ohci.c, uhci.c // // 103 4/30/14 8:56a Ryanchou // [TAG] EIP160289 // [Category] Improvement // [Description] Handle zero length of short packet. // [Files] uhci.c // // 102 4/30/14 6:13a Ryanchou // [TAG] EIP151374 // [Category] Improvement // [Description] Calculates maximum data length to be reported in the // HID device. // [Files] ehci.c, ohci.c, uhci.c, usbCCID.c, usbdef.h, usbhid.c, // usbhub.c, xhci.c // // 101 2/26/14 1:55a Wilsonlee // [TAG] EIP149854 // [Category] Improvement // [Description] Add data length parameter to polling callback function. // [Files] usbkbd.c, uhci.c, usb.c, usbhub.c, usbCCID.c, usbms.c, // usbhid.c, usbpoint.c, usbkbd.h, ehci.c, ohci.c, xhci.c, usbdef.h // // 100 9/24/13 5:39a Ryanchou // [TAG] EIP132985 // [Category] Improvement // [Description] Clear the SMI enable bit if UHCI is not controlled by // BIOS. // [Files] uhci.c // // 99 8/16/13 2:15a Ryanchou // // 98 7/26/13 2:40a 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 // // 97 7/22/13 10:31p Wilsonlee // [TAG] EIP125357 // [Category] Improvement // [Description] Check if the port releases to a select host controller. // [Files] uhci.c, usb.c, usbhub.c, ehci.c, ohci.c, xhci.c, usbdef.h // // 96 6/02/13 11:42p Wilsonlee // [TAG] EIP123235 // [Category] Improvement // [Description] Stop the usb host controller at ExitBootService if it // is an extend card or it doesn't support HW SMI. // [Files] xhci.c, ehci.c, uhci.c, ohci.c, amiusb.c, usbdef.h, usbsb.c, // uhcd.c // // 95 4/16/13 6:45a Ryanchou // [TAG] EIP118912 // [Category] Improvement // [Description] Add VIA VT6212 EHCI controller support. // [Files] ehci.c, uhci.c, usbdef.h, uhcd.c // // 94 3/19/13 3:58a 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 // // 93 3/18/13 4:49a Ryanchou // [TAG] EIP98377 // [Category] Improvement // [Description] Optimize USB controller timing. // [Files] usb.sdl, usbport.c, ehci.c, elib.c, ohci.c, uhci.c, // usbdef.h, usbhub.c, xhci.c, uhcd.c // // 92 2/24/13 9:00p Wilsonlee // [TAG] EIP113541 // [Category] Bug Fix // [Severity] Critical // [Symptom] System hangs at checkpoint 0xA2 when Win8 resume from S4. // [RootCause] The "HCHalted" bit and "Port Change Detect" bit are set // when the system S4 resume to Win8 OS. // [Solution] We need to clear the interrupt status even if the // "HCHalted" bit is set. // [Files] ehci.c, ohci.c, uhci.c // // 91 12/06/12 12:39a Wilsonlee // [TAG] EIP103186 // [Category] Improvement // [Description] Handle the error case "MEMIO was disabled" in USB // driver. // [Files] uhci.c, ohci.c, ehci.c, xhci.c // // 90 11/22/12 9:21p Wilsonlee // [TAG] EIP106887 // [Category] New Feature // [Description] Support usb S5 wake up function for UHCI. // [Files] usb.c, uhci.c, uhci.h // // 89 11/10/12 6:48a Ryanchou // // 88 11/10/12 6:39a 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 // // 87 9/28/12 2:37a Wilsonlee // [TAG] EIP93154 // [Category] Improvement // [Description] Change the unit of the FixedDelay from 15 us to 1 us. // [Files] amiusb.h, xhci.c, ehci.c, ohci.c, uhci.c, usb.c, usbCCID.c, // usbmass.c, usbhub.c, elib.c // // 86 8/29/12 8:17a 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 // // 85 5/04/12 6:39a 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 // // 84 5/03/12 6:23a 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 // // 83 11/08/11 1:56a Ryanchou // [TAG] EIP63188 // [Category] Improvement // [Description] External USB controller support. // [Files] amidef.h, amiusb.c, ehci.c, ohci.c, uhcd.c, uhcd.h, uhci.c, // usbdef.h, usbmisc.c, usbsb.c, xhci.c // // 82 9/26/11 11:43p Roberthsu // [TAG] EIP67230 // [Category] Bug Fix // [Severity] Normal // [Symptom] Ntrig touch panel can not use on CedarTrail // [RootCause] Because ntrig report data over than 512 byte.Control // transfer check if over 512 than set length is 512. // [Solution] Remove check transfer length. // [Files] ohci.c,uhci.c,usbhid.c // // 81 8/08/11 6:59a Ryanchou // [TAG] EIP54018 // [Category] New Feature // [Description] Added USB S5 wake up support. // [Files] amiusb.c, ehci.c, ohci.c, uhci.c, usb.c, usb.sdl, usbdef.h, // usbsb.c xhci.c // // 80 8/08/11 5:15a Ryanchou // [TAG] EIP60561 // [Category] New Feature // [Description] Add USB timing policy protocol for timing override. // [Files] ehci.c, guids.c, ohci.c, uhcd.c, uhci.c usb.c, usbdef.h, // usbhub.c, usbmass.c, UsbPolicy.h, usbport.c usbsrc.sdl // // 79 7/15/11 6:11a Ryanchou // [TAG] EIP38434 // [Category] New Feature // [Description] Added USB HID report protocol support. // [Files] amiusb.c, AmiUsbController.h, amiusbhc.c, efiusbkb.c, // efiusbkb.h, ehci.c, ohci.c, uhcd.c uhcd.cif, uhci.c, usb.c, usbdef.h, // usbkbd.c, usbkbd.h, usbms.c, usbrt.cif, usbsb.c, usbsetup.c, // usbsrc.sdl, xhci.c // // 78 7/13/11 4:09a Ryanchou // [TAG] EIP59332 // [Category] Improvement // [Description] Modified the Stop function for UHCD and USBBUS to // properly stop devices and uninstall the protocols. // [Files] uhcd.c, uhcd.h, uhci.c, usbbus.c, UsbInt13.c, usbmisc.c // // 77 7/12/11 8:09a Ryanchou // [TAG] EIP56918 // [Category] New Feature // [Description] Added CCID device support. // [Files] amiusb.c, amiusb.h, amiusbrtCCID.h, ehci.c, ohci.c, uhci.c, // usb.c, UsbCCID.c, usbdef.h, usbrt.cif, usbsetup.c, efiusbccid.c, // framework.cif, uhcd.c, uhcd.cif, uhcd.h, usbsrc.sdl, AmiusbCCID.h, // AmiUsbController.h, AmiUSBProtocols.cif // // 76 7/01/11 3:19a Ryanchou // [TAG] EIP61385 // [Category] Bug Fix // [Severity] Important // [Symptom] USB devices can't detected. // [RootCause] This is the side effect of EIP59663, the port status // doesn't reflect connect status and connect status change. // [Solution] Add 100 us delay. // [Files] ehci.c, uhci.c // // 75 6/22/11 1:44a Ryanchou // [TAG] EIP59738 // [Category] Improvement // [Description] Support Block size other than 512 bytes USB HDD in UEFI // mode. // [Files] efiusbmass.c, uhci.c, usb.c, usbdef.h, usbmass.c // // 74 5/03/11 10:09a Ryanchou // [TAG] EIP54283 // [Category] Improvement // [Description] Follow XHCI spec ver 1.0 section 4.6.8 to recovery // endpoint halt. // [Files] ehci.c, ohci.c, uhci.c, usbdef.h, usbmass.c, xhci.c // // 73 4/06/11 1:33a Ryanchou // [TAG] EIP54782 // [Category] Improvement // [Description] Change polling data size of HID devices to max packet // size of interrupt endpoint. // [Files] ehci.c, ohci.c, uhci.c, usb.c, usbdef.h, xhci.c // // 72 3/29/11 10:51p Ryanchou // [TAG] EIP55401 // [Category] Improvement // [Description] Improve the USB 3.0 device compatibility. // [Files] ehci.c, ehci.h, ohci.c, uhci.c, usb.c, usbdef.h, usbhub.c, // xhci.c // // 71 3/29/11 10:08a Ryanchou // [TAG] EIP53518 // [Category] Improvement // [Description] Added chipset xHCI chip support. // [Files] amiusb.c, amiusb.h, ehci.c, ohci.c, uhcd.c, uhci.c, usb.c, // usb.sdl, usbdef.h, usbport, usbsb.c, xhci.c // // 70 11/11/10 11:35p Ryanchou // [TAG] EIP45578 // [Category] Bug Fix // [Severity] Minor // [Symptom] USB 3.0 device can't be detected. // [RootCause] Address Device Command fails. // [Solution] Reset the device and attempt the Address Device Command // again. // [Files] ehci.c, ohci.c, uhci.c, usb.c, usbdef.h, usbhub.c, xhci.c // // 69 9/24/10 5:38p Olegi // EIP38221: Added the code that properly initializes // DEV_INFO.bIntEndpoint field; interrupt endpoint polling is using this // endpoint number. // // 68 9/07/10 4:11a Tonylo // Remove user tags for coding standard. // // 67 8/18/10 4:22p Olegi // Klockwork related fixes; EIP37978 // // 66 4/30/10 3:36p Fredericko // Fixed EIP : 38028: USB AutoKeyRepeat is not working properly // // 65 3/10/10 6:35p Olegi // // 64 3/10/10 10:51a Olegi // Function headers corrected. // // 63 3/06/10 1:11p Olegi // // 62 2/26/10 4:23p Olegi // // 61 2/08/10 10:11a Olegi // EIP33381: Implement multiple bulk endpoint in UsbIoProtocol. // // 60 2/08/10 9:40a Olegi // EIP34448: Changes in UHCIWaitForTransferComplete and transfer routines. // // 59 1/26/10 4:35p Olegi // // 55 12/23/09 11:59a Olegi // // 54 12/22/09 8:57a Olegi // // 53 12/10/09 10:06a Olegi // Added timeout in UHCI_WaitForBulkTransferComplete, EIP32048. // // 52 11/13/09 12:37p Olegi // // 51 10/30/09 5:47p Olegi // // 50 10/07/09 9:48a Olegi // USB Hub error handling improvement. EIP#25601. // // 49 9/15/09 10:21a Olegi // Added USB_INCMPT_HID_DATA_OVERFLOW incompatibility type. // // 48 8/26/09 11:41a Olegi // Changes that prevent collision of keyboard activity and mass storage // access. EIP#22808 // // 47 2/23/09 12:56p Olegi // // 46 2/20/09 4:43p Olegi // // 45 2/17/09 4:01p Olegi // // 44 2/17/09 8:58a Olegi // // 43 2/06/09 4:06p Olegi // // 42 1/16/09 3:50p Olegi // Optimization in BulkTransfer scheduling. // // 41 10/06/08 3:33p Olegi // EHCI change ownership testing in DOS fix (EIP#14855). // // 40 9/02/08 10:29a Olegi // EIP14855 bugfix: change ownership request is not processed properly in // case of multiple controllers of the same type. // // 39 5/16/08 12:01p Olegi // Compliance with AMI coding standard. // // 38 2/05/08 3:13p Olegi // Bugfix in BulkTdCallback that showed when data TD returns with stall // condition. // // 37 12/17/07 4:04p Olegi // KBC emulation support added. // // 36 10/15/07 5:13p Olegi // ControlTransfer cleanup. // // 35 9/26/07 9:15a Olegi // Added USB_FORCE_64BIT_ALIGNMENT flag as well as a call ty sync the LEDs // between keyboards in DOS. // // 34 9/21/07 5:10p Davidd // Allocation TDs is forced to be 64-bytes aligned. // // 33 9/06/07 6:12p Olegi // // 32 9/06/07 5:52p Olegi // Tracker 27603 fix added. // // 31 8/14/07 11:56a Olegi // Reverted buggy BulkTransfer changes to make floppy work. // // 30 8/14/07 10:59a Olegi // // 29 7/09/07 2:11p Olegi // Changed the maximum data size of the BulkTransfer from 1kB to 64kB. // // 28 4/17/07 6:13p Fredericko // Modified UHCI_EnableRootHub to preserve the Connect Status Change bit. // // 27 4/17/07 8:24a Olegi // Device detection algorythm update, in sync with Core8. // // 26 3/20/07 12:18p Olegi // // 25 1/26/07 2:52p Olegi // Bugfix in UHCI_BulkTDCallback. // // 24 1/25/07 4:25p Olegi // // 23 1/25/07 10:19a Olegi // // 22 1/02/07 2:08p Olegi // // 21 12/28/06 5:27p Olegi // // 20 12/26/06 10:52a Olegi // // 19 12/20/06 2:30p Olegi // // 17 10/19/06 5:24p Andriyn // // 15 10/12/06 9:37p Andriyn // Fix: unexpected plug-off hangs with endless TIMEOUTs // // 14 7/10/06 2:57p Andriyn // Fix: double delocation of descriptors used for control transfer // // 13 6/29/06 11:54a Andriyn // Removed commented code // // 12 4/14/06 6:39p Olegi // Conversion to be able to use x64 compiler. // // 11 3/20/06 3:37p Olegi // Version 8.5 - x64 compatible. // // 10 3/06/06 6:23p Olegi // // 9 11/29/05 12:33p Andriyn // // 8 9/23/05 12:01p Olegi // // 7 9/23/05 11:58a Olegi // // 6 8/27/05 3:43p Andriyn // Fix: lost mouse click when mouse is not moving // // 5 8/11/05 9:53a Olegi // 60/64 port emulation related fixes for EMU6064 driver. // // 4 6/03/05 6:08p Olegi // HW SMI registration change. // // 3 5/19/05 8:07p Olegi // Aptio changes in driver 8.1 implementation. // // 2 5/17/05 7:51p Andriyn // USB BUS pre-release // // 1 3/28/05 6:20p Olegi // // 1 3/15/05 9:23a Olegi // Initial VSS check-in. // //**************************************************************************** // //----------------------------------------------------------------------------- // // Name: Uhci.c // // Description: AMI USB UHCI driver // //----------------------------------------------------------------------------- // #include "amidef.h" #include "usbdef.h" #include "amiusb.h" #include "usbkbd.h" #if USB_RUNTIME_DRIVER_IN_SMM #include #endif extern VOID* USB_MemAlloc (UINT16); extern UINT8 USB_MemFree (VOID _FAR_ *, UINT16); extern UINT8 USBCheckPortChange (HC_STRUC*, UINT8, UINT8); extern UINT8 USB_InstallCallBackFunction (CALLBACK_FUNC); extern UINT32 ReadPCIConfig(UINT16, UINT8); extern VOID WordWritePCIConfig(UINT16, UINT8, UINT16); extern UINT8 ByteReadIO(UINT16); extern VOID ByteWriteIO(UINT16, UINT8); extern UINT16 WordReadIO(UINT16); extern VOID WordWriteIO(UINT16, UINT16); extern UINT32 DwordReadIO(UINT16); extern VOID DwordWriteIO(UINT16, UINT32); extern VOID FixedDelay(UINTN); extern DEV_INFO* USB_GetDeviceInfoStruc(UINT8, DEV_INFO*, UINT8, HC_STRUC*); extern UINT8 USBLogError(UINT16); extern VOID USB_InitFrameList (HC_STRUC*, UINT32); #if USB_DEV_KBD extern VOID USBKBDPeriodicInterruptHandler(HC_STRUC*); extern VOID USBKeyRepeat(HC_STRUC*, UINT8); #endif UINT8 USB_DisconnectDevice (HC_STRUC*, UINT8, UINT8); UINT8 UsbGetDataToggle(DEV_INFO*,UINT8); VOID UsbUpdateDataToggle(DEV_INFO*, UINT8, UINT8); //--------------------------------------------------------------------------- // Public function declaration UINT8 UHCI_Start (HC_STRUC*); UINT8 UHCI_Stop (HC_STRUC*); UINT8 UHCI_EnumeratePorts (HC_STRUC*); UINT8 UHCI_DisableInterrupts (HC_STRUC*); UINT8 UHCI_EnableInterrupts (HC_STRUC*); UINT8 UHCI_ProcessInterrupt(HC_STRUC*); UINT8 UHCI_GetRootHubStatus (HC_STRUC*,UINT8, BOOLEAN); UINT8 UHCI_DisableRootHub (HC_STRUC*,UINT8); UINT8 UHCI_EnableRootHub (HC_STRUC*,UINT8); UINT8 UHCI_ResetRootHub (HC_STRUC*,UINT8); UINT16 UHCI_ControlTransfer (HC_STRUC*,DEV_INFO*,UINT16,UINT16,UINT16,UINT8*,UINT16); UINT32 UHCI_BulkTransfer (HC_STRUC*,DEV_INFO*,UINT8,UINT8*,UINT32); UINT16 UHCI_InterruptTransfer (HC_STRUC*, DEV_INFO*, UINT8, UINT16, UINT8*, UINT16); UINT8 UHCI_DeactivatePolling (HC_STRUC*,DEV_INFO*); UINT8 UHCI_ActivatePolling (HC_STRUC*,DEV_INFO*); UINT8 UHCI_DisableKeyRepeat (HC_STRUC*); UINT8 UHCI_EnableKeyRepeat (HC_STRUC*); UINT8 UHCI_GlobalSuspend (HC_STRUC*); //(EIP54018+) UINT8 UhciProcessQh (HC_STRUC*, UHCI_QH*); UINT8 UhciProcessTd (HC_STRUC*, UHCI_TD*); UINT8 UhciProcessFrameList (HC_STRUC*); UINT8 UHCI_DisableHCPorts (HC_STRUC*); UINT8 UHCI_StartTDSchedule (HC_STRUC*); UINT8 UHCI_StopTDSchedule (HC_STRUC*); UINT8 UHCI_InterruptTDCallback (HC_STRUC*, DEV_INFO*, UINT8*, UINT8*); UINT8 UhciAddQhToFrameList (HC_STRUC*, UHCI_QH*); UINT8 UhciRemoveQhFromFrameList (HC_STRUC*, UHCI_QH*); VOID UhciInitQh (UHCI_QH*); BOOLEAN UhciIsHalted(HC_STRUC*); UINT8 UhciTranslateInterval(UINT8); UHCI_TD* UhciAllocGeneralTds ( IN UINT8 DeviceAddr, IN BOOLEAN LowSpeed, IN UINT8 PacketId, IN UINT8 EndpointAddr, IN UINT16 MaxPacket, IN BOOLEAN ShortPacket, IN OUT UINTN *BufferAddr, IN OUT UINT32 *Length, IN OUT UINT8 *DataToggle ); VOID UhciFreeTds ( IN UHCI_TD *FirstTd ); VOID UhciActivateTds ( IN UHCI_TD *FirstTd, IN UINT8 DataToggle ); extern USB_GLOBAL_DATA *gUsbData; extern BOOLEAN gCheckUsbApiParameter; UINT8 UhciRootHubQhCallBack(HC_STRUC*, DEV_INFO*, UINT8*, UINT8*, UINT16); UINT8 UhciRepeatQhCallback (HC_STRUC*, DEV_INFO*, UINT8*, UINT8*, UINT16); UINT8 UhciPollingQhCallback (HC_STRUC*, DEV_INFO*, UINT8*, UINT8*, UINT16); // //--------------------------------------------------------------------------- // // Name: UHCI_FillHCDEntries // // Description: // This function fills the host controller driver routine pointers // // Input: // fpHCDHeader Ptr to the host controller header structure // // Output: // USB_SUCCESS = Success, USB_ERROR = Failure // //--------------------------------------------------------------------------- // UINT8 UHCI_FillHCDEntries(HCD_HEADER *fpHCDHeader) { // // Fill the routines here // fpHCDHeader->pfnHCDStart = UHCI_Start; fpHCDHeader->pfnHCDStop = UHCI_Stop; fpHCDHeader->pfnHCDEnumeratePorts = UHCI_EnumeratePorts; fpHCDHeader->pfnHCDDisableInterrupts = UHCI_DisableInterrupts; fpHCDHeader->pfnHCDEnableInterrupts = UHCI_EnableInterrupts; fpHCDHeader->pfnHCDProcessInterrupt = UHCI_ProcessInterrupt; fpHCDHeader->pfnHCDGetRootHubStatus = UHCI_GetRootHubStatus; fpHCDHeader->pfnHCDDisableRootHub = UHCI_DisableRootHub; fpHCDHeader->pfnHCDEnableRootHub = UHCI_EnableRootHub; fpHCDHeader->pfnHCDControlTransfer = UHCI_ControlTransfer; fpHCDHeader->pfnHCDBulkTransfer = UHCI_BulkTransfer; fpHCDHeader->pfnHCDInterruptTransfer = UHCI_InterruptTransfer; fpHCDHeader->pfnHCDDeactivatePolling = UHCI_DeactivatePolling; fpHCDHeader->pfnHCDActivatePolling = UHCI_ActivatePolling; fpHCDHeader->pfnHCDDisableKeyRepeat = UHCI_DisableKeyRepeat; fpHCDHeader->pfnHCDEnableKeyRepeat = UHCI_EnableKeyRepeat; fpHCDHeader->pfnHCDEnableEndpoints = USB_EnableEndpointsDummy; fpHCDHeader->pfnHCDInitDeviceData = USB_InitDeviceDataDummy; fpHCDHeader->pfnHCDDeinitDeviceData = USB_DeinitDeviceDataDummy; fpHCDHeader->pfnHCDResetRootHub = UHCI_ResetRootHub; fpHCDHeader->pfnHCDClearEndpointState = 0; //(EIP54283+) fpHCDHeader->pfnHCDGlobalSuspend = UHCI_GlobalSuspend; //(EIP54018+) USB_InstallCallBackFunction(UhciPollingQhCallback); USB_InstallCallBackFunction(UhciRepeatQhCallback); USB_InstallCallBackFunction(UhciRootHubQhCallBack); return USB_SUCCESS; } // //--------------------------------------------------------------------------- // // Name: UHCI_Start // // Description: // This API function is called to start a UHCI host controller. The input to the // routine is the pointer to the HC structure that defines this host controller // // Input: // fpHCStruc Ptr to the host controller structure // // Output: // Status: USB_SUCCESS = Success, USB_ERROR = Failure // //--------------------------------------------------------------------------- // UINT8 UHCI_Start (HC_STRUC* fpHCStruc) { UINT16 wIOAddr; UINT16 LegSupReg; UINT16 Index; EFI_STATUS EfiStatus; EfiStatus = UsbHcStrucValidation(fpHCStruc); if (EFI_ERROR(EfiStatus)) { return USB_ERROR; } #if USB_RUNTIME_DRIVER_IN_SMM EfiStatus = AmiValidateMmioBuffer((VOID*)fpHCStruc->fpFrameList, 0x1000); if (EFI_ERROR(EfiStatus)) { return USB_ERROR; } #endif /* USB_DEBUG(DEBUG_LEVEL_3, "Enabling IO/BM for UHCI HC %02X\n", fpHCStruc->wBusDevFuncNum); // // Enable IO access and Bus Mastering // WordWritePCIConfig((UINT16)fpHCStruc->wBusDevFuncNum, 4, BIT0 + BIT2); */ // // Set number of root hub ports present // fpHCStruc->bNumPorts = 2; // // Get the I/O base address for the host controller // wIOAddr = (UINT16)ReadPCIConfig((UINT16)fpHCStruc->wBusDevFuncNum, USB_IO_BASE_ADDRESS); // // Mask the low order two bits and store the value in HCStruc // wIOAddr = (UINT16)(wIOAddr & (~(BIT0+BIT1))); USB_DEBUG(DEBUG_LEVEL_4, "HC I/O Address : %X\n", wIOAddr); fpHCStruc->BaseAddress = wIOAddr; fpHCStruc->wAsyncListSize = UHCI_FRAME_LIST_SIZE; // // Disable hardware interrupt generation by programming legacy registers // LegSupReg = (UINT16)ReadPCIConfig((UINT16)fpHCStruc->wBusDevFuncNum, USB_UHCI_REG_LEGSUP); // // Disable generation of SMI/IRQ and clear status bits // LegSupReg = (UINT16)(LegSupReg & (~BIT4)); WordWritePCIConfig((UINT16)fpHCStruc->wBusDevFuncNum, USB_UHCI_REG_LEGSUP, LegSupReg); // // Disable the interrupts (to aVOID spurious interrupts) // UHCI_DisableInterrupts(fpHCStruc); // // Disable the host controller root hub ports // UHCI_DisableHCPorts(fpHCStruc); // // Check whether HC is already stopped // if (!UhciIsHalted(fpHCStruc)) { // // HC is still running. Stop it by programming HC run bit // ByteWriteIO ((UINT16)(wIOAddr + UHCI_COMMAND_REG), ByteReadIO((UINT16)(wIOAddr + UHCI_COMMAND_REG)) & ~UHC_HOST_CONTROLLER_RUN); // // Check whether the host controller is halted (check for 50 ms) // for (Index = 0; Index < 500; Index++) { if ((ByteReadIO((UINT16)(wIOAddr + UHCI_STATUS_REG))) & UHC_HC_HALTED) { break; } FixedDelay(100); // 100 us delay } } ASSERT((ByteReadIO((UINT16)(wIOAddr + UHCI_STATUS_REG))) & UHC_HC_HALTED); if (!((ByteReadIO((UINT16)(wIOAddr + UHCI_STATUS_REG))) & UHC_HC_HALTED)) { return USB_ERROR; } // // Reset the host controller // ByteWriteIO((UINT16)(wIOAddr + UHCI_COMMAND_REG), UHC_GLOBAL_RESET); FixedDelay(10 * 1000); // Recommended 10msec delay, UHCI Spec, p.12, GRESET description ByteWriteIO((UINT16)(wIOAddr + UHCI_COMMAND_REG), 0); // // Memory has been allocated in AMIUHCD // if (!fpHCStruc->fpFrameList) { return USB_ERROR; } USB_InitFrameList (fpHCStruc, UHCI_TERMINATE); // // Program frame list pointer to the HC // USB_DEBUG(DEBUG_LEVEL_4, "Frame list pointer : %x\n", fpHCStruc->fpFrameList); DwordWriteIO((UINT16)(wIOAddr + UHCI_FRAME_LIST_BASE), (UINT32)(UINTN)fpHCStruc->fpFrameList); USB_DEBUG(DEBUG_LEVEL_6, "UHCI_StartTDSchedule\n"); // // Start the TD schedule // if (UHCI_StartTDSchedule(fpHCStruc) != USB_SUCCESS) return USB_ERROR; #if USB_RUNTIME_DRIVER_IN_SMM // // Enable hardware interrupt generation by programming legacy registers // if (!(fpHCStruc->dHCFlag & HC_STATE_EXTERNAL)) { LegSupReg = (UINT16)ReadPCIConfig(fpHCStruc->wBusDevFuncNum, USB_UHCI_REG_LEGSUP); // Enable generation of SMI/IRQ LegSupReg = (UINT16)(LegSupReg | BIT4) & ~BIT13; WordWritePCIConfig((UINT16)fpHCStruc->wBusDevFuncNum, USB_UHCI_REG_LEGSUP, LegSupReg); } #endif // // Start the host controller by setting the run and configure bit // WordWriteIO((UINT16)(wIOAddr + UHCI_COMMAND_REG), UHC_HOST_CONTROLLER_RUN | UHC_CONFIGURE_FLAG | UHC_MAX_PACKET_64_BYTE); // // Enable interrupt generation // // WordWriteIO((UINT16)(wIOAddr + UHCI_INTERRUPT_ENABLE), (UHC_IOC_ENABLE | UHC_TIMEOUT_CRC_ENABLE)); WordWriteIO((UINT16)(wIOAddr + UHCI_INTERRUPT_ENABLE), UHC_IOC_ENABLE); fpHCStruc->dHCFlag |= HC_STATE_RUNNING; // Set USB_FLAG_DRIVER_STARTED flag when HC is running. if (!(gUsbData->dUSBStateFlag & USB_FLAG_DRIVER_STARTED)) { gUsbData->dUSBStateFlag |= USB_FLAG_DRIVER_STARTED; } #if USB_RUNTIME_DRIVER_IN_SMM // // Register the USB HW SMI handler // if (!(fpHCStruc->dHCFlag & HC_STATE_EXTERNAL)) { UsbInstallHwSmiHandler(fpHCStruc); } else { USBSB_InstallUsbIntTimerHandler(); } #endif return USB_SUCCESS; } // //--------------------------------------------------------------------------- // // Name: UHCI_Stop // // Description: // This API function is called to stop the UHCI controller. The input to the // routine is the pointer to the HC structure that defines this host controller. // // Input: // fpHCStruc Ptr to the host controller structure // // Output: // Status: USB_SUCCESS = Success, USB_ERROR = Failure // //--------------------------------------------------------------------------- // UINT8 UHCI_Stop (HC_STRUC* fpHCStruc) { UINT16 wIOAddr = (UINT16)fpHCStruc->BaseAddress; UINT16 LegSupReg; UINT16 Index; EFI_STATUS EfiStatus; EfiStatus = UsbHcStrucValidation(fpHCStruc); if (EFI_ERROR(EfiStatus)) { return USB_ERROR; } if (!(fpHCStruc->dHCFlag & HC_STATE_RUNNING)) { return USB_ERROR; } // // Disable hardware interrupt generation by programming legacy registers // if (!(fpHCStruc->dHCFlag & HC_STATE_EXTERNAL)) { LegSupReg = (UINT16)ReadPCIConfig((UINT16)fpHCStruc->wBusDevFuncNum, USB_UHCI_REG_LEGSUP); // // Disable generation of SMI/IRQ and clear status bits // LegSupReg = (UINT16)(LegSupReg & ~(BIT4)); WordWritePCIConfig((UINT16)fpHCStruc->wBusDevFuncNum, USB_UHCI_REG_LEGSUP, LegSupReg); } // // Disable the host controller interrupt generation // UHCI_DisableInterrupts (fpHCStruc); // Disconnect all devices USB_DisconnectDevice(fpHCStruc, fpHCStruc->bHCNumber | BIT7, 1); USB_DisconnectDevice(fpHCStruc, fpHCStruc->bHCNumber | BIT7, 2); // // Stop the host controller // if (!UhciIsHalted(fpHCStruc)) { // // Clear HC run bit // ByteWriteIO ((UINT16)(wIOAddr + UHCI_COMMAND_REG), ByteReadIO((UINT16)(wIOAddr + UHCI_COMMAND_REG)) & ~(UHC_HOST_CONTROLLER_RUN)); // // Check whether the host controller is halted (check for 50 ms) // for (Index = 0; Index < 500; Index++) { if ((ByteReadIO((UINT16)(wIOAddr + UHCI_STATUS_REG))) & UHC_HC_HALTED) { break; } FixedDelay(100); // 100 us delay } } ASSERT((ByteReadIO((UINT16)(wIOAddr + UHCI_STATUS_REG))) & UHC_HC_HALTED); // Reset the host controller ByteWriteIO((UINT16)(wIOAddr + UHCI_COMMAND_REG), UHC_GLOBAL_RESET); // Recommended 10msec delay, UHCI Spec, p.12, GRESET description FixedDelay(10 * 1000); ByteWriteIO((UINT16)(wIOAddr + UHCI_COMMAND_REG), 0); // // Clear the frame list pointers // USB_InitFrameList (fpHCStruc, UHCI_TERMINATE); // // Disable and free the TD schedule data structures // UHCI_StopTDSchedule (fpHCStruc); // // Set the HC state to stopped // fpHCStruc->dHCFlag &= ~(HC_STATE_RUNNING); CheckBiosOwnedHc(); return USB_SUCCESS; } // //--------------------------------------------------------------------------- // // Name: UHCI_EnumeratePorts // // Description: // This API function is called to enumerate the root hub ports in the UHCI // controller. The input to the routine is the pointer to the HC structure // that defines this host controller // // Input: // fpHCStruc Ptr to the host controller structure // // Output: // Status: USB_SUCCESS = Success, USB_ERROR = Failure // //--------------------------------------------------------------------------- // UINT8 UHCI_EnumeratePorts(HC_STRUC* fpHCStruc) { UINT8 bHCNumber; UINT16 wIOAddr, wPortAddr; EFI_STATUS EfiStatus; EfiStatus = UsbHcStrucValidation(fpHCStruc); if (EFI_ERROR(EfiStatus)) { return USB_ERROR; } if (!(fpHCStruc->dHCFlag & HC_STATE_RUNNING)) { return USB_ERROR; } if (UhciIsHalted(fpHCStruc)) { return USB_ERROR; } wIOAddr = (UINT16)fpHCStruc->BaseAddress; //(USB0061+)> // // Check whether USB host controllers are accessible to aVOID system // hang in ports enumeration. // if (ByteReadIO(wIOAddr) == 0xFF) return USB_ERROR; //<(USB0061+) // // Check whether enumeration is already began // if(gUsbData->bEnumFlag == TRUE) return USB_SUCCESS; gUsbData->bEnumFlag = TRUE; bHCNumber = (UINT8)(fpHCStruc->bHCNumber | BIT7); //(EIP61385)> // // Process Port#1 and clear Port#1 status bit // wPortAddr = wIOAddr + UHCI_PORT1_CONTROL; if ((WordReadIO(wPortAddr) & (UHC_CONNECT_STATUS_CHANGE | UHC_CONNECT_STATUS)) == UHC_CONNECT_STATUS_CHANGE) { WordWriteIO(wPortAddr, UHC_CONNECT_STATUS_CHANGE); } USBCheckPortChange(fpHCStruc, bHCNumber, 1); WordWriteIO(wPortAddr, WordReadIO(wPortAddr)); // // Process Port#2 and clear Port#2 status bit // wPortAddr = wIOAddr + UHCI_PORT2_CONTROL; if ((WordReadIO(wPortAddr) & (UHC_CONNECT_STATUS_CHANGE | UHC_CONNECT_STATUS)) == UHC_CONNECT_STATUS_CHANGE) { WordWriteIO(wPortAddr, UHC_CONNECT_STATUS_CHANGE); } USBCheckPortChange(fpHCStruc, bHCNumber, 2); WordWriteIO(wPortAddr, WordReadIO(wPortAddr)); //<(EIP61385) gUsbData->bEnumFlag = FALSE; return USB_SUCCESS; } // //--------------------------------------------------------------------------- // // Name: UHCI_DisableInterrupts // // Description: // This API function is called to disable the interrupts generated by the UHCI // host controller. The input to the routine is the pointer to the HC structure // that defines this host controller. // // Input: // fpHCStruc Ptr to the host controller structure // // Output: // Status: USB_SUCCESS = Success, USB_ERROR = Failure // //--------------------------------------------------------------------------- // UINT8 UHCI_DisableInterrupts (HC_STRUC* fpHCStruc) { UINT8 IntEnReg; UINT16 IoAddr = (UINT16)fpHCStruc->BaseAddress; EFI_STATUS EfiStatus; EfiStatus = UsbHcStrucValidation(fpHCStruc); if (EFI_ERROR(EfiStatus)) { return USB_ERROR; } IntEnReg = ByteReadIO((UINT16)(IoAddr + UHCI_INTERRUPT_ENABLE)); IntEnReg &= ~(UHC_IOC_ENABLE); ByteWriteIO((UINT16)(IoAddr + UHCI_INTERRUPT_ENABLE), IntEnReg); return USB_SUCCESS; } // //--------------------------------------------------------------------------- // // Name: UHCI_EnableInterrupts // // Description: // This function enables the HC interrupts // // Input: // fpHCStruc Pointer to the HCStruc structure // // Output: // USB_SUCCESS of USB_ERROR // //--------------------------------------------------------------------------- // UINT8 UHCI_EnableInterrupts (HC_STRUC* fpHCStruc) { return USB_SUCCESS; } // //--------------------------------------------------------------------------- // // Name: UHCI_ProcessInterrupt // // Description: // This function is called when the USB interrupt bit is set. This function // will parse through the TDs and QHs to find out completed TDs and call // their respective callback functions. // // Input: // fpHCStruc Pointer to the HCStruc structure // // Output: // USB_ERROR - Need more Interrupt processing // USB_SUCCESS - No interrupts pending // //--------------------------------------------------------------------------- // UINT8 UHCI_ProcessInterrupt( HC_STRUC *HcStruc ) { UINT16 IoPort = (UINT16)HcStruc->BaseAddress; UINT16 LegSupReg = 0; UINT16 UsbSts = 0; EFI_STATUS EfiStatus; EfiStatus = UsbHcStrucValidation(HcStruc); if (EFI_ERROR(EfiStatus)) { return USB_ERROR; } if (!(HcStruc->dHCFlag & HC_STATE_RUNNING)) { return USB_ERROR; } #if USB_RUNTIME_DRIVER_IN_SMM if (!(HcStruc->dHCFlag & HC_STATE_EXTERNAL)) { LegSupReg = (UINT16)ReadPCIConfig(HcStruc->wBusDevFuncNum, USB_UHCI_REG_LEGSUP); if (!(LegSupReg & BIT4)) { return USB_ERROR; } } #endif // // Check whether the controller is still under BIOS control // Read the frame list base address and compare with stored value // if (((UINTN)DwordReadIO(IoPort + UHCI_FRAME_LIST_BASE) & 0xFFFFF000) != (UINTN)HcStruc->fpFrameList) { #if USB_RUNTIME_DRIVER_IN_SMM if (!(HcStruc->dHCFlag & HC_STATE_EXTERNAL)) { // Disable the SMI on IRQ enable bit WordWritePCIConfig(HcStruc->wBusDevFuncNum, USB_UHCI_REG_LEGSUP, LegSupReg & ~BIT4); } #endif return USB_ERROR; // Control is not with us anymore } UsbSts = WordReadIO(IoPort + UHCI_STATUS_REG); if (UsbSts & UHC_HC_HALTED) { return USB_ERROR; } if (UsbSts & UHC_USB_INTERRUPT) { WordWriteIO(IoPort + UHCI_STATUS_REG, UsbSts); UhciProcessFrameList(HcStruc); } if (HcStruc->dHCFlag & HC_STATE_EXTERNAL) { UhciRootHubQhCallBack(HcStruc, NULL, NULL, NULL, 0); } return USB_SUCCESS; } // //--------------------------------------------------------------------------- // // Name: UHCI_GetRootHubStatus // // Description: // This function returns the port connect status for the root hub port // // Input: // pHCStruc Pointer to HCStruc of the host controller // bPortNum Port in the HC whose status is requested // // Output: // NewPortNum Port in the HC that can possibly replace bPortNum // //--------------------------------------------------------------------------- // UINT8 UHCI_GetRootHubStatus( HC_STRUC* fpHCStruc, UINT8 bPortNum, BOOLEAN ClearChangeBits ) { UINT16 wPortAddr, wPortStatus, wPortTemp; EFI_STATUS EfiStatus; EfiStatus = UsbHcStrucValidation(fpHCStruc); if (EFI_ERROR(EfiStatus)) { return USB_ERROR; } wPortStatus = USB_PORT_STAT_DEV_OWNER; wPortAddr = (UINT16)((bPortNum<<1)+UHCI_PORT1_CONTROL-2+fpHCStruc->BaseAddress); // // Read the port status // wPortTemp = WordReadIO(wPortAddr); USB_DEBUG(3, "UHCI port[%d] status: %04x\n", bPortNum, wPortTemp); // // Check for port connect status // if (wPortTemp & UHC_CONNECT_STATUS) { wPortStatus |= USB_PORT_STAT_DEV_CONNECTED; // // Identify the speed of the device (full or low speed) // if (wPortTemp & UHC_LOW_SPEED_ATTACHED) { wPortStatus |= USB_PORT_STAT_DEV_LOWSPEED; } else { wPortStatus |= USB_PORT_STAT_DEV_FULLSPEED; } if (wPortTemp & UHC_PORT_ENABLE) { wPortStatus |= USB_PORT_STAT_DEV_ENABLED; } } // // Check for connect status change // if (wPortTemp & UHC_CONNECT_STATUS_CHANGE) { wPortStatus |= USB_PORT_STAT_DEV_CONNECT_CHANGED; if (ClearChangeBits == TRUE) { WordWriteIO(wPortAddr, UHC_CONNECT_STATUS_CHANGE); //(EIP61385+) } } return (UINT8)wPortStatus; } // //--------------------------------------------------------------------------- // // Name: UHCI_DisableRootHub // // Description: // This function disables the root hub of the UHCI controller. // // Input: // fpHCStruc Pointer to HCStruc of the host controller // bPortNum Root port to be disabled // // Output: // USB_SUCCESS or USB_ERROR // //--------------------------------------------------------------------------- // UINT8 UHCI_DisableRootHub (HC_STRUC* fpHCStruc,UINT8 bPortNum) { UINT16 wPortAddr = (UINT16)(fpHCStruc->BaseAddress + (bPortNum << 1) + UHCI_PORT1_CONTROL - 2); EFI_STATUS EfiStatus; EfiStatus = UsbHcStrucValidation(fpHCStruc); if (EFI_ERROR(EfiStatus)) { return USB_ERROR; } // // Reset the enable bit // WordWriteIO( wPortAddr, (UINT16)(WordReadIO(wPortAddr) & (~UHC_PORT_ENABLE))); return USB_SUCCESS; } // //--------------------------------------------------------------------------- // // Name: UHCI_EnableRootHub // // Description: // This function enables the root hub port specified // // Input: // fpHCStruc Pointer to HCStruc of the host controller // bPortNum Root port to be enabled // // Output: // USB_SUCCESS or USB_ERROR // //--------------------------------------------------------------------------- // UINT8 UHCI_EnableRootHub ( HC_STRUC *HcStruc, UINT8 PortNum) { UINT16 PortStatus; UINT16 PortAddr = (UINT16)(HcStruc->BaseAddress + (PortNum << 1) + UHCI_PORT1_CONTROL - 2); EFI_STATUS EfiStatus; EfiStatus = UsbHcStrucValidation(HcStruc); if (EFI_ERROR(EfiStatus)) { return USB_ERROR; } PortStatus = WordReadIO(PortAddr); // // Set the enable & reset bit, preserve Connect Status Change bit // PortStatus &= ~(UHC_CONNECT_STATUS_CHANGE | UHC_PORT_ENABLE_CHANGE); WordWriteIO(PortAddr, PortStatus | UHC_PORT_RESET); // // Wait for 10ms // FixedDelay(10 * 1000); // 10msec delay // // Clear the reset bit and set the enable, preserve Connect Status Change bit // PortStatus = WordReadIO(PortAddr); PortStatus &= ~(UHC_CONNECT_STATUS_CHANGE | UHC_PORT_ENABLE_CHANGE); WordWriteIO(PortAddr, PortStatus & (~UHC_PORT_RESET)); // Wait 1 ms for stabilize the port status FixedDelay(1 * 1000); // 1 ms delay // Clear Connect Status Change bit and Port Enable Change bit WordWriteIO(PortAddr, WordReadIO(PortAddr)); // // Set the enable bit // PortStatus = WordReadIO(PortAddr); PortStatus &= ~(UHC_CONNECT_STATUS_CHANGE | UHC_PORT_ENABLE_CHANGE); WordWriteIO(PortAddr, PortStatus | UHC_PORT_ENABLE); // // Wait for 100ms // //FixedDelay(gUsbData->UsbTimingPolicy.UhciPortEnable * 1000); // 100msec delay return USB_SUCCESS; } // //--------------------------------------------------------------------------- // // Name: UHCI_ResetRootHub // // Description: // This function resets the UHCI HC root hub port // // Input: // HcStruc Pointer to HCStruc of the host controller // PortNum Root port to be enabled // // Output: // USB_SUCCESS or USB_ERROR // //--------------------------------------------------------------------------- // UINT8 UHCI_ResetRootHub ( HC_STRUC* HcStruc, UINT8 PortNum) { return USB_SUCCESS; } // //---------------------------------------------------------------------------- // // Name: UHCI_GlobalSuspend // // Description: // This function suspend the UHCI HC. // //---------------------------------------------------------------------------- // UINT8 UHCI_GlobalSuspend( HC_STRUC* HcStruc ) { UINT16 IoAddr = (UINT16)HcStruc->BaseAddress; UINT16 UhciCommand; UINT16 UhciStatus; UINT32 i; EFI_STATUS EfiStatus; EfiStatus = UsbHcStrucValidation(HcStruc); if (EFI_ERROR(EfiStatus)) { return USB_ERROR; } if (!(HcStruc->dHCFlag & HC_STATE_RUNNING)) { return USB_ERROR; } if (UhciIsHalted(HcStruc)) { return USB_ERROR; } UhciCommand = WordReadIO(IoAddr + UHCI_COMMAND_REG); UhciCommand &= ~UHC_HOST_CONTROLLER_RUN; WordWriteIO(IoAddr + UHCI_COMMAND_REG, UhciCommand); for (i = 0; i < 1024; i++) { UhciStatus = WordReadIO(IoAddr + UHCI_STATUS_REG); if (UhciStatus & UHC_HC_HALTED) { break; } FixedDelay(1 * 1000); } WordWriteIO((UINT16)(IoAddr + UHCI_INTERRUPT_ENABLE), UHC_RESUME_ENABLE); UhciStatus = WordReadIO(IoAddr + UHCI_STATUS_REG); UhciStatus |= 0x1F; WordWriteIO(IoAddr + UHCI_STATUS_REG, UhciStatus); UhciCommand = WordReadIO(IoAddr + UHCI_COMMAND_REG); UhciCommand |= UHC_ENTER_SUSPEND; WordWriteIO(IoAddr + UHCI_COMMAND_REG, UhciCommand); FixedDelay(50 * 1000); HcStruc->dHCFlag &= ~(HC_STATE_RUNNING); HcStruc->dHCFlag |= HC_STATE_SUSPEND; return USB_SUCCESS; } // //--------------------------------------------------------------------------- // // Name: UhciExecuteTransfer // // Description: // This function execites a transfer and waits for the completion of // the transfer, and returns the transfer results. // // Input: // Pointers to the first data TD and last data TD in the TD list // // Output: // Return value is the size of transferred data, Bytes // //--------------------------------------------------------------------------- // UINT32 UhciExecuteTransfer ( HC_STRUC *HcStruc, UHCI_QH *TransferQh ) { UINT32 Timeout = gUsbData->wTimeOutValue * 100; // *100, makes it number of 10 usec units BOOLEAN InfiniteLoop = (Timeout == 0); TransferQh->ActiveFlag = TRUE; UhciAddQhToFrameList(HcStruc, TransferQh); while (InfiniteLoop || Timeout--) { UhciProcessQh(HcStruc, TransferQh); if (TransferQh->ActiveFlag == FALSE) { break; } FixedDelay(10); // 10 microseconds } UhciRemoveQhFromFrameList(HcStruc, TransferQh); UhciProcessQh(HcStruc, TransferQh); if (TransferQh->ActiveFlag) { USB_DEBUG (DEBUG_LEVEL_3, "UHCI Time-Out\n"); } return TransferQh->BytesTransferred; } // //--------------------------------------------------------------------------- // // Name: UHCI_ControlTransfer // // Description: // This function executes a device request command transaction on the USB. One // setup packet is generated containing the device request parameters supplied // by the caller. The setup packet may be followed by data in or data out packets // containing data sent from the host to the device or vice-versa. This function // will not return until the request either completes successfully or completes in // error (due to time out, etc.) // // Input: // fpHCStruc Pointer to HCStruc of the host controller // pDevInfo DeviceInfo structure (if available else 0) // wRequest Request type (low byte) // Bit 7 : Data direction // 0 = Host sending data to device // 1 = Device sending data to host // Bit 6-5 : Type // 00 = Standard USB request // 01 = Class specific // 10 = Vendor specific // 11 = Reserved // Bit 4-0 : Recipient // 00000 = Device // 00001 = Interface // 00010 = Endpoint // 00100 - 11111 = Reserved // Request code, a one byte code describing // the actual device request to be executed // (ex: Get Configuration, Set Address etc) // wIndex wIndex request parameter (meaning varies) // wValue wValue request parameter (meaning varies) // fpBuffer Buffer containing data to be sent to the // device or buffer to be used to receive data // wLength wLength request parameter, number of bytes // of data to be transferred in or out // of the host controller // // // Output: // Number of bytes transferred: 0 - Failure, <>0 - Success // // // Notes: // Do not use USB_SUCCESS or USB_ERROR as returned values // //--------------------------------------------------------------------------- // UINT16 UHCI_ControlTransfer ( HC_STRUC *fpHCStruc, DEV_INFO *fpDevInfo, UINT16 wRequest, UINT16 wIndex, UINT16 wValue, UINT8 *fpBuffer, UINT16 wLength) { UINT16 wTemp; UINT32 dTemp; UINT32 dValue; DEV_REQ *fpDevReq; UHCI_TD *SetupTd = NULL; UHCI_TD *DataTDs = NULL; UHCI_TD *StatusTd = NULL; UHCI_TD *LastTd = NULL; UHCI_TD *CurrentTd = NULL; UHCI_QH *CtrlQh; UINT16 NumDataTDs = 0; UINT16 BytesRemaining; UINT16 BytesTransferred; UINT8 DataToggle; EFI_STATUS EfiStatus = EFI_SUCCESS; EfiStatus = UsbHcStrucValidation(fpHCStruc); if (EFI_ERROR(EfiStatus)) { return 0; } EfiStatus = UsbDevInfoValidation(fpDevInfo); if (EFI_ERROR(EfiStatus)) { return 0; } #if USB_RUNTIME_DRIVER_IN_SMM if (gCheckUsbApiParameter) { if (wLength != 0) { EfiStatus = AmiValidateMemoryBuffer((VOID*)fpBuffer, wLength); if (EFI_ERROR(EfiStatus)) { USB_DEBUG(3, "Uhci ControlTransfer Invalid Pointer, Buffer is in SMRAM.\n"); return 0; } } gCheckUsbApiParameter = FALSE; } #endif if (!(fpHCStruc->dHCFlag & HC_STATE_RUNNING)) { return 0; } if (UhciIsHalted(fpHCStruc)) { return 0; } if (!VALID_DEVINFO(fpDevInfo)) return 0; gUsbData->bLastCommandStatus &= ~( USB_CONTROL_STALLED ); gUsbData->dLastCommandStatusExtended = 0; // // Allocate TDs for control setup and control status packets // SetupTd = USB_MemAlloc(GET_MEM_BLK_COUNT_STRUC(UHCI_TD)); if(SetupTd == NULL) { return 0; } // // Build the device request in the data area of the control setup TD // fpDevReq = (DEV_REQ*)SetupTd->aDataArea; fpDevReq->wRequestType = wRequest; fpDevReq->wValue = wValue; fpDevReq->wIndex = wIndex; fpDevReq->wDataLength = wLength; // // dTemp will contain the device address and endpoint shifted and ready to go // into the TDs' token field. // 10:0] = Dev. Addr & Endpoint // [18:8] = Dev. Addr & Endpoint // dTemp = ((UINT32)(fpDevInfo->bDeviceAddress)) << 8; // // Fill in various fields in the control setup TD. // The LinkPointer field will point to the control data TD if data will // be sent/received or to the control status TD if no data is expected. // The ControlStatus field will be set to active and interrupt on complete. // The Token field will contain the packet size (size of DeviceRequest // struc), the device address, endpoint, and a setup PID. // The BufferPointer field will point to the TD's DataArea buffer which // was just initialized to contain a DeviceRequest struc. // The CSReloadValue field will contain 0 because this is a "one shot" packet. // The pCallback will be set to point to the UHCI_ControlTDCallback routine. // The ActiveFlag field will be set to TRUE. // // // 11/01/10 for HI/LO/FULL // dValue = (((UINT32)fpDevInfo->bEndpointSpeed) & 1) << 26; //(EIP34448)> dValue |= (UINT32)(UHCI_TD_THREE_ERRORS | UHCI_TD_ACTIVE); //<(EIP34448) SetupTd->dControlStatus = dValue; dValue = dTemp | ((UINT32)UHCI_TD_SETUP_PACKET | ((UINT32)(sizeof(DEV_REQ) - 1) << 21)); // // Set PID=Setup, and MaxLen // SetupTd->dToken = dValue; SetupTd->pBufferPtr = (UINT32)(UINTN)SetupTd->aDataArea; SetupTd->dCSReload = 0; SetupTd->bActiveFlag = 1; LastTd = SetupTd; // // Fill in various fields in the control data TD. // Enough control data TDs must be initialized to handle the amount of // data expected. The length of the data transfer is currently in wLength. // LinkPointer field will be set to the next data TD or the status TD. // ControlStatus field will be se to active and interrupt on complete. // Token field will contain the data transfer size (still in wLength), device // address (in pDevInfo), endpoint (in dTemp), and an in or out PID // (in wReqType). // BufferPointer field will point to the data buffer passed in by the // caller (currently in fpBuffer). // CSReloadValue field will contain 0 because this is a "one shot" packet. // pCallback will be set to point to the UHCI_ControlTDCallback routine. // ActiveFlag field will be set to TRUE. // if(wLength) { NumDataTDs = wLength / fpDevInfo->wEndp0MaxPacket; if (wLength % fpDevInfo->wEndp0MaxPacket) { NumDataTDs++; } DataTDs = USB_MemAlloc(GET_MEM_BLK_COUNT(NumDataTDs * sizeof(UHCI_TD))); if (DataTDs == NULL) { USB_MemFree(SetupTd, GET_MEM_BLK_COUNT_STRUC(UHCI_TD)); return 0; } CurrentTd = DataTDs; DataToggle = 1; BytesRemaining = wLength; // // Allocate one more TD to be used either for more data or for TD Status // do { // // 11/01/10 for HI/LO/FULL // dValue = (((UINT32)(fpDevInfo->bEndpointSpeed) & 1) << 26); dValue = dValue | (UINT32)(UHCI_TD_THREE_ERRORS | UHCI_TD_ACTIVE); if(wRequest & BIT7) { dValue |= UHCI_TD_SHORT_PACKET_DETECT; } CurrentTd->dControlStatus = dValue; CurrentTd->pBufferPtr = (UINT32)(UINTN)fpBuffer; wTemp = (UINT16)((BytesRemaining > (fpDevInfo->wEndp0MaxPacket)) ? fpDevInfo->wEndp0MaxPacket : BytesRemaining); // // Packet size is valid // BytesRemaining = (UINT16)(BytesRemaining - wTemp); fpBuffer = fpBuffer + wTemp; --wTemp; // // [18:8]=Dev. addr & endp // dValue = dTemp | (((UINT32)wTemp) << 21); dValue = (dValue & 0xFFFFFF00) | UHCI_TD_OUT_PACKET; if(wRequest & BIT7) { dValue = (dValue & 0xFFFFFF00) | UHCI_TD_IN_PACKET; } if(DataToggle & 1) { dValue = dValue | UHCI_TD_DATA_TOGGLE; // Make packet into a data 1 } CurrentTd->dToken = dValue; CurrentTd->dCSReload = 0; CurrentTd->bActiveFlag = 1; LastTd->pLinkPtr = (UINT32)((UINTN)CurrentTd | UHCI_VERTICAL_FLAG); LastTd = CurrentTd; CurrentTd++; DataToggle ^= 1; } while (BytesRemaining); // End the data TD list } // // Fill in various fields in the TD control status. // LinkPointer field will point to TERMINATE. // ControlStatus field will be set to active and interrupt on complete. // Token field will contain the packet size (0), the device address, // endpoint, and a setup PID with opposite data direction as that defined // in the request type (wReqType). // BufferPointer field will point to the TD's DataArea buffer even though // we are not expecting any data transfer. // CSReloadValue field will contain 0 because this is a "one shot" packet. // pCallback will be set to point to the UHCI_ControlTDCallback routine. // ActiveFlag field will be set to TRUE. // StatusTd = USB_MemAlloc(GET_MEM_BLK_COUNT_STRUC(UHCI_TD)); if (StatusTd == NULL) { return 0; } LastTd->pLinkPtr = (UINT32)((UINTN)StatusTd | UHCI_VERTICAL_FLAG); LastTd = StatusTd; StatusTd->pLinkPtr = UHCI_TERMINATE; dValue = (((UINT32)(fpDevInfo->bEndpointSpeed) & 1) << 26); //(EIP34448)> dValue = dValue | (UINT32)(UHCI_TD_THREE_ERRORS | UHCI_TD_ACTIVE); //<(EIP34448) StatusTd->dControlStatus = dValue; dValue = dTemp; dValue = (dValue & 0xFFFFFF00) | (UINT32)UHCI_TD_OUT_PACKET; if((wRequest & BIT7) == 0) { dValue = (dValue & 0xFFFFFF00) | (UINT32)UHCI_TD_IN_PACKET; } dValue |= (UHCI_TD_DATA_TOGGLE | ((UINT32)UHCI_TD_ACTUAL_LENGTH << 21)); StatusTd->dToken = dValue; dValue = (UINT32)(UINTN)StatusTd->aDataArea; StatusTd->pBufferPtr = dValue; StatusTd->dCSReload = 0; StatusTd->bActiveFlag = 1; // // Now put the control setup, data and status into the HC's schedule by // pointing QhControl's link pointer to control setup TD. // This will cause the HC to execute the transaction in the next active frame. CtrlQh = USB_MemAlloc(GET_MEM_BLK_COUNT_STRUC(UHCI_QH)); if (CtrlQh == NULL) { return 0; } UhciInitQh(CtrlQh); CtrlQh->pElementPtr = (UINT32)(UINTN)SetupTd; CtrlQh->CurrentTd = SetupTd; CtrlQh->Type = Control; CtrlQh->FirstTd = SetupTd; // Wait till transfer complete BytesTransferred = UhciExecuteTransfer(fpHCStruc, CtrlQh); // Calculate the transferred length BytesTransferred -= (((SetupTd->dControlStatus & UHCI_TD_ACTUAL_LENGTH) + 1) & 0x7FF); // Save error information in global variable gUsbData->dLastCommandStatusExtended = (CtrlQh->CurrentTd->dControlStatus & UHCI_TD_STATUS_FIELD) >> 17; if (CtrlQh->CurrentTd->dControlStatus & UHCI_TD_STALLED ){ gUsbData->bLastCommandStatus |= USB_CONTROL_STALLED; BytesTransferred = 0; } USB_MemFree(SetupTd, GET_MEM_BLK_COUNT_STRUC(UHCI_TD)); if (DataTDs) { USB_MemFree(DataTDs, GET_MEM_BLK_COUNT(NumDataTDs * sizeof(UHCI_TD))); } USB_MemFree(StatusTd, GET_MEM_BLK_COUNT_STRUC(UHCI_TD)); USB_MemFree(CtrlQh, GET_MEM_BLK_COUNT_STRUC(UHCI_QH)); return BytesTransferred; } // UHCI_ControlTransfer // //--------------------------------------------------------------------------- // // Name: UHCI_InitBulkTdCommon // // Description: // This function creates a chain of two TDs for bulk data transfer. It fills // in the following fields in TD: // pLinkPtr - NextTd address // dToken - All bits except length and data toggle // // Input: // BulkDataTd0 1st TD in the chain // BulkDataTd1 2nd TD in the chain // TokenData Data for dToken // NumBulkTds # of bulk TDs // //--------------------------------------------------------------------------- // VOID UHCI_InitBulkTdCommon ( UHCI_TD *BulkDataTd0, UINT32 TokenData, UINT16 NumBulkTds ) { UINT16 i; UHCI_TD *Td0 = BulkDataTd0; UHCI_TD *Td1 = Td0; UINT16 NumTd = NumBulkTds*2; for (i=0; idToken = TokenData; Td1 = (UHCI_TD*)((UINTN)Td0 + sizeof(UHCI_TD)); Td0->pLinkPtr = (UINT32)(UINTN)Td1 | UHCI_VERTICAL_FLAG; } // Terminated later in UHCI_InitBulkDataTds } // //--------------------------------------------------------------------------- // // Name: UHCI_InitBulkDataTds // // Description: // This function initializes the fields in bulk data TD list that remain after // UHCI_InitBulkTdCommon: // - Data buffer pointer // - Data length // - Data toggle (DAT0/DAT1) // // Output: // Pointer to the last TD in the chain // //--------------------------------------------------------------------------- // UHCI_TD* UHCI_InitBulkDataTds( IN UHCI_TD *BulkDataTd, IN UINT16 MaxPkt, IN UINT32 EndpointSpeed, IN OUT UINT32 *Address, IN OUT UINT8 *DatToggle, IN OUT UINT32 *BytesRemaining, IN UINT16 NumBulkTds ) { UINT16 i; UINT32 Length = *BytesRemaining; UHCI_TD *Td = BulkDataTd; UINT32 Addr = *Address; UINT8 Toggle = *DatToggle; BOOLEAN TheLastTd = FALSE; for (i = 0; i < NumBulkTds; i++) { Length = *BytesRemaining; if (Length > (UINT32)MaxPkt) { Length = (UINT32)MaxPkt; } else { TheLastTd = TRUE; } Td->dToken &= 0x1FFFFF; Td->dToken |= (Length - 1) << 21; Td->dToken &= ~UHCI_TD_DATA_TOGGLE; // Make packet go into DAT0 if (Toggle == 1) { Td->dToken |= UHCI_TD_DATA_TOGGLE; // Make packet go into DAT1 } Td->dControlStatus = EndpointSpeed | (UHCI_TD_THREE_ERRORS | UHCI_TD_ACTIVE); if ((Td->dToken & UHCI_TD_PACKET_ID) == UHCI_TD_IN_PACKET) { Td->dControlStatus |= UHCI_TD_SHORT_PACKET_DETECT; } Td->pBufferPtr = Addr; Addr += MaxPkt; Toggle ^= 1; Td = (UHCI_TD*)((UINTN)Td + sizeof(UHCI_TD)); *BytesRemaining -= Length; if (TheLastTd) break; } Td = (UHCI_TD*)((UINTN)Td - sizeof(UHCI_TD)); Td->pLinkPtr = UHCI_TERMINATE; *Address = Addr; *DatToggle = Toggle; return Td; } // //--------------------------------------------------------------------------- // // Name: UHCI_BulkTransfer // // Description: // This function executes a bulk transaction on the USB. The transfer may be // either DATA_IN or DATA_OUT packets containing data sent from the host to // the device or vice-versa. This function wil not return until the request // either completes successfully or completes with error (due to time out, etc.) // // Input: // HcStruc Pointer to HCStruc of the host controller // DevInfo DeviceInfo structure (if available else 0) // XferDir Transfer direction // Bit 7: Data direction // 0 Host sending data to device // 1 Device sending data to host // Bit 6-0 : Reserved // Buffer Buffer containing data to be sent to the device or buffer to be // used to receive data value in Segment:Offset format // Length Length request parameter, number of bytes of data to be transferred // in or out of the host controller // // Output: // Amount of data transferred // //--------------------------------------------------------------------------- // UINT32 UHCI_BulkTransfer ( HC_STRUC *HcStruc, DEV_INFO *DevInfo, UINT8 XferDir, UINT8 *Buffer, UINT32 Length ) { UINT16 MaxPkt; UINT8 Endp; UINT32 Data; UINT8 DatToggle; UINT32 TransferError; UHCI_QH *BulkQh; UHCI_TD *BulkDataTd; UHCI_TD *NextBulkDataTd; UHCI_TD *BulkDataTd0; UHCI_TD *BulkDataTd1; UHCI_TD *LastTd; UHCI_TD *NextLastTd; UINT16 NumAllocTDs; UINT16 NumBulkTDs; UINT32 BytesRemaining; UINT32 BytesTransferred; UINT32 BytesTransferredNow; UINT32 Address; UINT32 Eps; EFI_STATUS EfiStatus = EFI_SUCCESS; EfiStatus = UsbHcStrucValidation(HcStruc); if (EFI_ERROR(EfiStatus)) { return 0; } EfiStatus = UsbDevInfoValidation(DevInfo); if (EFI_ERROR(EfiStatus)) { return 0; } #if USB_RUNTIME_DRIVER_IN_SMM if (gCheckUsbApiParameter) { EfiStatus = AmiValidateMemoryBuffer((VOID*)Buffer, Length); if (EFI_ERROR(EfiStatus)) { USB_DEBUG(3, "Uhci BulkTransfer Invalid Pointer, Buffer is in SMRAM.\n"); return 0; } gCheckUsbApiParameter = FALSE; } #endif if (!(HcStruc->dHCFlag & HC_STATE_RUNNING)) { return 0; } if (UhciIsHalted(HcStruc)) { return 0; } if ( !VALID_DEVINFO( DevInfo) ) return 0; if (Length == 0) return 0; // Clear HW source of error gUsbData->bLastCommandStatus &= ~(USB_BULK_STALLED | USB_BULK_TIMEDOUT ); gUsbData->dLastCommandStatusExtended = 0; // // Get Bulk IN/OUT enpoint number, data sync value & max packet size // Store the appropriate max packet size and endpoint number // in the local variables // MaxPkt = (XferDir & BIT7)? DevInfo->wBulkInMaxPkt : DevInfo->wBulkOutMaxPkt; if (MaxPkt == 0) return 0; Endp = (XferDir & BIT7)? DevInfo->bBulkInEndpoint : DevInfo->bBulkOutEndpoint; // // For multiple LUN devices toggle is maintained by LUN0 // DatToggle = UsbGetDataToggle(DevInfo, Endp | XferDir); // // Form TD token data, less the transfer length and toggle information // Data = (UINT32)Endp << 7; Data = (Data | DevInfo->bDeviceAddress) << 8; Data = (XferDir & BIT7)? Data | UHCI_TD_IN_PACKET : Data | UHCI_TD_OUT_PACKET; BulkQh = USB_MemAlloc(GET_MEM_BLK_COUNT_STRUC(UHCI_QH)); if (BulkQh == NULL) return 0; BulkQh->Type = Bulk; // Allocate data TDs. NumBulkTDs = FULLSPEED_MAX_BULK_DATA_SIZE_PER_FRAME/MaxPkt; ASSERT(NumBulkTDs != 0); NumAllocTDs = NumBulkTDs*2; BulkDataTd0 = (UHCI_TD*)USB_MemAlloc(GET_MEM_BLK_COUNT(NumAllocTDs * sizeof(UHCI_TD))); ASSERT(BulkDataTd0 != NULL); UHCI_InitBulkTdCommon (BulkDataTd0, Data, NumBulkTDs); BulkDataTd1 = (UHCI_TD*)((UINTN)BulkDataTd0 + (NumBulkTDs * sizeof(UHCI_TD))); BulkDataTd = BulkDataTd0; NextBulkDataTd = BulkDataTd1; BytesRemaining = Length; BytesTransferred = 0; BytesTransferredNow = 0; Address = (UINT32)(UINTN)Buffer; TransferError = 0; Eps = ((UINT32)(DevInfo->bEndpointSpeed) & 1) << 26; LastTd = UHCI_InitBulkDataTds( BulkDataTd, MaxPkt, Eps, &Address, &DatToggle, &BytesRemaining, NumBulkTDs); NextLastTd = LastTd; do { // Start the transfer by adding TD in the bulk queue head UhciInitQh(BulkQh); BulkQh->pElementPtr = (UINT32)(UINTN)BulkDataTd; BulkQh->CurrentTd = BulkDataTd; BulkQh->FirstTd = BulkDataTd; // Initialize the next TD block and wait for the current one to complete. // In case MaxPkt is 64 Bytes, we have approx. NumBulkTDs*50mcs for this. if (BytesRemaining != 0) { NextLastTd = UHCI_InitBulkDataTds( NextBulkDataTd, MaxPkt, Eps, &Address, &DatToggle, &BytesRemaining, NumBulkTDs); } // Wait til BulkDataTd is complete, check for errors BytesTransferredNow = UhciExecuteTransfer(HcStruc, BulkQh); DatToggle = BulkQh->DataToggle; TransferError = (BulkQh->CurrentTd->dControlStatus & UHCI_TD_STATUS_FIELD) >> 17; if (TransferError) { break; } BytesTransferred += BytesTransferredNow; NextBulkDataTd = BulkDataTd; LastTd = NextLastTd; BulkDataTd = (BulkDataTd == BulkDataTd0)? BulkDataTd1 : BulkDataTd0; } while ((BytesTransferred < Length) && !BulkQh->ShortPacketDetected); UsbUpdateDataToggle(DevInfo, Endp | XferDir, DatToggle); gUsbData->dLastCommandStatusExtended = TransferError; if (BulkQh->CurrentTd->dControlStatus & UHCI_TD_STALLED){ gUsbData->bLastCommandStatus |= USB_BULK_STALLED; } if (BulkQh->CurrentTd->dControlStatus & UHCI_TD_ACTIVE) { gUsbData->bLastCommandStatus |= USB_BULK_TIMEDOUT; } // // Deallocate memory and return the transferred data size // USB_MemFree(BulkDataTd0, GET_MEM_BLK_COUNT(NumAllocTDs * sizeof(UHCI_TD))); USB_MemFree(BulkQh, GET_MEM_BLK_COUNT_STRUC(UHCI_QH)); return BytesTransferred; } // //--------------------------------------------------------------------------- // // Name: UHCI_InterruptTransfer // // Description: // This function executes an interrupt transaction on the USB. The data transfer // direction is always DATA_IN. This function wil not return until the request // either completes successfully or completes in error (due to time out, etc.) // // Input: // fpHCStruc Pointer to HCStruc of the host controller // fpDevInfo DeviceInfo structure (if available else 0) // EndpointAddress The destination USB device endpoint to which the device request // is being sent. // MaxPktSize Indicates the maximum packet size the target endpoint is capable // of sending or receiving. // fpBuffer Buffer containing data to be sent to the device or buffer to be // used to receive data // wLength wLength request parameter, number of bytes of data to be transferred // // Output: // Number of bytes transferred // // // Notes: // DO NOT TOUCH THE LINK POINTER OF THE TDInterruptData. It is statically allocated // and linked with other items in the 1ms schedule // //--------------------------------------------------------------------------- // UINT16 UHCI_InterruptTransfer( HC_STRUC *fpHCStruc, DEV_INFO *fpDevInfo, UINT8 EndpointAddress, UINT16 MaxPktSize, UINT8 *fpBuffer, UINT16 wLength) { UINT8 bEndp; UINT8 DataToggle; UINT32 dTemp, dValue; UHCI_QH *IntQh; UHCI_TD *IntTd; UINT32 BytesTransferred; EFI_STATUS EfiStatus = EFI_SUCCESS; EfiStatus = UsbHcStrucValidation(fpHCStruc); if (EFI_ERROR(EfiStatus)) { return 0; } EfiStatus = UsbDevInfoValidation(fpDevInfo); if (EFI_ERROR(EfiStatus)) { return 0; } #if USB_RUNTIME_DRIVER_IN_SMM if (gCheckUsbApiParameter) { EfiStatus = AmiValidateMemoryBuffer((VOID*)fpBuffer, wLength); if (EFI_ERROR(EfiStatus)) { USB_DEBUG(3, "Uhci InterruptTransfer Invalid Pointer, Buffer is in SMRAM.\n"); return 0; } gCheckUsbApiParameter = FALSE; } #endif if (!(fpHCStruc->dHCFlag & HC_STATE_RUNNING)) { return 0; } if (UhciIsHalted(fpHCStruc)) { return 0; } if( !VALID_DEVINFO( fpDevInfo) ) return 0; gUsbData->dLastCommandStatusExtended = 0; // // Check for 0 length transfer (if so, exit) // if(wLength == 0) { return 0; } // // Store the descriptor pointer in a local variable // IntTd = USB_MemAlloc(GET_MEM_BLK_COUNT_STRUC(UHCI_TD)); if (IntTd == NULL) { return 0; } IntTd->pLinkPtr = UHCI_TERMINATE; // // It is an interrupt IN transaction get appropriate size // bEndp = EndpointAddress & 0xF; DataToggle = UsbGetDataToggle(fpDevInfo, EndpointAddress); // // Form device address and endpoint in proper order and bit position // dTemp = (UINT32)bEndp << 7; dTemp = (dTemp | (fpDevInfo->bDeviceAddress)) << 8; //[10:0] = Dev. Addr & Endpoint //[18:8] = Dev. Addr & Endpoint // // Fill in various fields in the interrupt data TD // IntTd->dControlStatus = (((UINT32)(fpDevInfo->bEndpointSpeed) & 1) << 26) | UHCI_TD_THREE_ERRORS | UHCI_TD_ACTIVE; // // Set the buffer pointer. Note that currently UHCI Interrupt Transfer // implementation assumes IN packet; the direction is not passed here as // parameter. Should this change in future, make a branch to use // UHCI_TD_OUT_PACKET while constructing dToken. // IntTd->pBufferPtr = (UINT32)(UINTN)fpBuffer; dValue = (UINT32)(wLength - 1); dValue = ((dValue << 21) | dTemp) & 0xffffff00; dValue |= EndpointAddress & BIT7 ? UHCI_TD_IN_PACKET : UHCI_TD_OUT_PACKET; if(DataToggle & 1) { dValue |= UHCI_TD_DATA_TOGGLE; // Make packet into a data 1 } IntTd->dToken = dValue; IntTd->dCSReload = 0; IntTd->bActiveFlag = 1; IntQh = USB_MemAlloc(GET_MEM_BLK_COUNT_STRUC(UHCI_QH)); if (IntQh == NULL) { return 0; } UhciInitQh(IntQh); IntQh->pElementPtr = (UINT32)(UINTN)IntTd; IntQh->CurrentTd = IntTd; IntQh->Type = Interrupt; IntQh->FirstTd = IntTd; IntQh->Interval = UhciTranslateInterval(fpDevInfo->bPollInterval); BytesTransferred = UhciExecuteTransfer(fpHCStruc, IntQh); gUsbData->dLastCommandStatusExtended = (IntQh->CurrentTd->dControlStatus & UHCI_TD_STATUS_FIELD) >> 17; UsbUpdateDataToggle(fpDevInfo, EndpointAddress, IntQh->DataToggle); USB_MemFree(IntTd, GET_MEM_BLK_COUNT_STRUC(UHCI_TD)); USB_MemFree(IntQh, GET_MEM_BLK_COUNT_STRUC(UHCI_QH)); return (UINT16)BytesTransferred; } // //--------------------------------------------------------------------------- // // Name: UHCI_DeactivatePolling // // Description: // This function de-activates the polling TD for the requested device. The // device may be a USB keyboard or USB hub // // Input: // fpHCStruc Pointer to the HC structure // fpDevInfo Pointer to the device information structure // // Output: // USB_SUCCESS or USB_ERROR // //--------------------------------------------------------------------------- // UINT8 UHCI_DeactivatePolling ( HC_STRUC *HcStruc, DEV_INFO *DevInfo ) { UHCI_QH *PollQh; UINT8 DataToggle; EFI_STATUS EfiStatus; EfiStatus = UsbHcStrucValidation(HcStruc); if (EFI_ERROR(EfiStatus)) { return USB_ERROR; } EfiStatus = UsbDevInfoValidation(DevInfo); if (EFI_ERROR(EfiStatus)) { return USB_ERROR; } if (!(HcStruc->dHCFlag & HC_STATE_RUNNING)) { return USB_ERROR; } if (UhciIsHalted(HcStruc)) { return USB_ERROR; } if (DevInfo->fpPollTDPtr == NULL) { return USB_ERROR; } PollQh = (UHCI_QH*)DevInfo->fpPollTDPtr; UhciRemoveQhFromFrameList(HcStruc, PollQh); DataToggle = (PollQh->FirstTd->dToken & UHCI_TD_DATA_TOGGLE)? 1 : 0; if (!(PollQh->FirstTd->dControlStatus & UHCI_TD_STATUS_FIELD)) { UsbUpdateDataToggle(DevInfo, DevInfo->IntInEndpoint, DataToggle ^ 1); } UhciFreeTds(PollQh->FirstTd); USB_MemFree(PollQh, GET_MEM_BLK_COUNT_STRUC(UHCI_QH)); DevInfo->fpPollTDPtr = NULL; if (DevInfo->fpPollDataBuffer) { USB_MemFree(DevInfo->fpPollDataBuffer, GET_MEM_BLK_COUNT(DevInfo->PollingLength)); DevInfo->fpPollDataBuffer = NULL; } return USB_SUCCESS; } // //--------------------------------------------------------------------------- // // Name: UHCI_ActivatePolling // // Description: // This function activates the polling TD for the requested device. The device // may be a USB keyboard or USB hub // // Input: // fpHCStruc Pointer to the HC structure // fpDevInfo Pointer to the device information structure // // Output: // USB_SUCCESS or USB_ERROR // // Notes: // For the keyboard device this routine allocates TDRepeat also, if it is not // already allocated. This routine allocate a polling TD and schedule it to 8ms // schedule for keyboards and to 1024ms schedule for hubs. // //--------------------------------------------------------------------------- // UINT8 UHCI_ActivatePolling ( HC_STRUC *HcStruc, DEV_INFO *DevInfo) { UHCI_TD *PollTd; UHCI_QH *PollQh; BOOLEAN LowSpeed; UINT8 PacketId; UINTN BufferAddr; UINT32 DataLen; UINT8 DataToggle; EFI_STATUS EfiStatus; EfiStatus = UsbHcStrucValidation(HcStruc); if (EFI_ERROR(EfiStatus)) { return USB_ERROR; } EfiStatus = UsbDevInfoValidation(DevInfo); if (EFI_ERROR(EfiStatus)) { return USB_ERROR; } if (!(HcStruc->dHCFlag & HC_STATE_RUNNING)) { return USB_ERROR; } if (UhciIsHalted(HcStruc)) { return USB_ERROR; } if( !VALID_DEVINFO(DevInfo) ) return USB_ERROR; DevInfo->fpPollDataBuffer = USB_MemAlloc(GET_MEM_BLK_COUNT(DevInfo->PollingLength)); if (DevInfo->fpPollDataBuffer == NULL) { return USB_ERROR; } LowSpeed = (DevInfo->bEndpointSpeed & 1) != 0; PacketId = DevInfo->IntInEndpoint & BIT7 ? UHCI_TD_IN_PACKET : UHCI_TD_OUT_PACKET; BufferAddr = (UINTN)DevInfo->fpPollDataBuffer; DataLen = DevInfo->PollingLength; DataToggle = UsbGetDataToggle(DevInfo, DevInfo->IntInEndpoint); PollTd = UhciAllocGeneralTds(DevInfo->bDeviceAddress, LowSpeed, PacketId, DevInfo->IntInEndpoint & 0xF, DevInfo->IntInMaxPkt, TRUE, &BufferAddr, &DataLen, &DataToggle); if (PollTd == NULL) { USB_MemFree(DevInfo->fpPollDataBuffer, GET_MEM_BLK_COUNT(DevInfo->PollingLength)); return USB_ERROR; } PollQh = USB_MemAlloc(GET_MEM_BLK_COUNT_STRUC(UHCI_QH)); if (PollQh == NULL) { USB_MemFree(DevInfo->fpPollDataBuffer, GET_MEM_BLK_COUNT(DevInfo->PollingLength)); UhciFreeTds(PollTd); return USB_ERROR; } DevInfo->fpPollTDPtr = (UINT8*)PollQh; UhciInitQh(PollQh); PollQh->pElementPtr = (UINT32)(UINTN)PollTd; PollQh->CurrentTd = PollTd; PollQh->Type = Interrupt; PollQh->FirstTd = PollTd; PollQh->Interval = UhciTranslateInterval(DevInfo->bPollInterval); PollQh->CallBackIndex = USB_InstallCallBackFunction(UhciPollingQhCallback); PollQh->DevInfoPtr = DevInfo; PollQh->ActiveFlag = TRUE; UhciAddQhToFrameList(HcStruc, PollQh); return USB_SUCCESS; } // //--------------------------------------------------------------------------- // // Name: UHCI_DisableKeyRepeat // // Description: // This function disables the keyboard repeat rate logic // // Input: // fpHCStruc Pointer to the HCStruc structure // // Output: // USB_SUCCESS or USB_ERROR // //--------------------------------------------------------------------------- // UINT8 UHCI_DisableKeyRepeat ( HC_STRUC *HcStruc ) { UHCI_DESC_PTRS *UhicDescPtrs; UHCI_QH *Qh; EFI_STATUS EfiStatus; UINT8 *MemBlockEnd = gUsbData->fpMemBlockStart + (gUsbData->MemPages << 12); EfiStatus = UsbHcStrucValidation(HcStruc); if (EFI_ERROR(EfiStatus)) { return USB_ERROR; } if (!(HcStruc->dHCFlag & HC_STATE_RUNNING)) { return USB_ERROR; } if (UhciIsHalted(HcStruc)) { return USB_ERROR; } UhicDescPtrs = HcStruc->stDescPtrs.fpUHCIDescPtrs; if (UhicDescPtrs == NULL) { return USB_ERROR; } if (((UINT8*)UhicDescPtrs < gUsbData->fpMemBlockStart) || ((UINT8*)(UhicDescPtrs + sizeof(UHCI_DESC_PTRS)) > MemBlockEnd)) { return USB_ERROR; } Qh = UhicDescPtrs->RepeatQh; if (Qh == NULL) { return USB_ERROR; } if (((UINT8*)Qh < gUsbData->fpMemBlockStart) || ((UINT8*)(Qh + sizeof(UHCI_DESC_PTRS)) > MemBlockEnd)) { return USB_ERROR; } if (((UINT8*)Qh->FirstTd < gUsbData->fpMemBlockStart) || ((UINT8*)(Qh->FirstTd + sizeof(UHCI_TD)) > MemBlockEnd)) { return USB_ERROR; } Qh->FirstTd->dCSReload = UHCI_TD_ONE_ERROR; Qh->FirstTd->dControlStatus= UHCI_TD_ONE_ERROR; Qh->FirstTd->bActiveFlag = 0; Qh->ActiveFlag = FALSE; Qh->pElementPtr = UHCI_TERMINATE; return USB_SUCCESS; } // //--------------------------------------------------------------------------- // // Name: UHCI_EnableKeyRepeat // // Description: // This function enables the keyboard repeat rate logic // // Input: // fpHCStruc Pointer to the HCStruc structure // // Output: // USB_SUCCESS or USB_ERROR // //--------------------------------------------------------------------------- // UINT8 UHCI_EnableKeyRepeat ( HC_STRUC *HcStruc ) { UHCI_DESC_PTRS *UhicDescPtrs; UHCI_QH *Qh; EFI_STATUS EfiStatus; UINT8 *MemBlockEnd = gUsbData->fpMemBlockStart + (gUsbData->MemPages << 12); EfiStatus = UsbHcStrucValidation(HcStruc); if (EFI_ERROR(EfiStatus)) { return USB_ERROR; } if (!(HcStruc->dHCFlag & HC_STATE_RUNNING)) { return USB_ERROR; } if (UhciIsHalted(HcStruc)) { return USB_ERROR; } UhicDescPtrs = HcStruc->stDescPtrs.fpUHCIDescPtrs; if (UhicDescPtrs == NULL) { return USB_ERROR; } if (((UINT8*)UhicDescPtrs < gUsbData->fpMemBlockStart) || ((UINT8*)(UhicDescPtrs + sizeof(UHCI_DESC_PTRS)) > MemBlockEnd)) { return USB_ERROR; } Qh = UhicDescPtrs->RepeatQh; if (((UINT8*)Qh < gUsbData->fpMemBlockStart) || ((UINT8*)(Qh + sizeof(UHCI_DESC_PTRS)) > MemBlockEnd)) { return USB_ERROR; } if (((UINT8*)Qh->FirstTd < gUsbData->fpMemBlockStart) || ((UINT8*)(Qh->FirstTd + sizeof(UHCI_TD)) > MemBlockEnd)) { return USB_ERROR; } Qh->FirstTd->dCSReload = (UHCI_TD_INTERRUPT_ON_COMPLETE | UHCI_TD_ONE_ERROR | UHCI_TD_ACTIVE); Qh->FirstTd->dControlStatus = Qh->FirstTd->dCSReload; Qh->FirstTd->bActiveFlag = 1; Qh->pElementPtr = (UINT32)(UINTN)Qh->FirstTd; Qh->CurrentTd = Qh->FirstTd; Qh->ActiveFlag = TRUE; return USB_SUCCESS; } // //--------------------------------------------------------------------------- // // Name: UHCI_DisableHCPorts (fpHCStruc) // // Description: // This routine disables the UHCI HC root hub ports // // Input: // fpHCStruc Ptr to the host controller structure // // Output: // Status: USB_SUCCESS = Success, USB_ERROR = Failure // //--------------------------------------------------------------------------- // UINT8 UHCI_DisableHCPorts (HC_STRUC* fpHCStruc) { UINT16 wIOAddr = (UINT16)fpHCStruc->BaseAddress; // // Disable the root hub port 1 // ByteWriteIO((UINT16)(wIOAddr+UHCI_PORT1_CONTROL), (UINT8)(ByteReadIO( (UINT16)(wIOAddr+UHCI_PORT1_CONTROL)) & (~UHC_PORT_ENABLE))); // // Disable the root hub port 2 // ByteWriteIO((UINT16)(wIOAddr+UHCI_PORT2_CONTROL), (UINT8)(ByteReadIO( (UINT16)(wIOAddr+UHCI_PORT2_CONTROL)) & (~UHC_PORT_ENABLE))); return USB_SUCCESS; } // //--------------------------------------------------------------------------- // // Name: UhciAddQhToFrameList // // Description: // This routine will add the particular QH into the frame list // // Input: // HcStruc Pointerr to the host controller structure // NewQh Address of the QH to be linked // // Output: // USB_SUCCESS/USB_ERROR // //--------------------------------------------------------------------------- // UINT8 UhciAddQhToFrameList ( HC_STRUC *HcStruc, UHCI_QH *NewQh ) { UINT16 Index; UINT32 *PrevPtr; UINT32 LinkPtr; UHCI_QH *Qh; BOOLEAN ByInterval = FALSE; EFI_STATUS Status = EFI_SUCCESS; if (NewQh == NULL) { return USB_ERROR; } switch (NewQh->Type) { case Control: case Bulk: ByInterval = FALSE; break; case Interrupt: ByInterval = TRUE; break; case Isochronous: ASSERT(FALSE); default: return USB_ERROR; } if (ByInterval && NewQh->Interval == 0) { return USB_ERROR; } for (Index = 0; Index < HcStruc->wAsyncListSize; ByInterval ? Index += NewQh->Interval : Index++) { PrevPtr = &HcStruc->fpFrameList[Index]; LinkPtr = *PrevPtr; while (!(LinkPtr & UHCI_TERMINATE)) { Qh = (UHCI_QH*)(LinkPtr & UHCI_POINTER_MASK); #if USB_RUNTIME_DRIVER_IN_SMM Status = AmiValidateMemoryBuffer((VOID*)Qh, sizeof(UHCI_QH)); if (EFI_ERROR(Status)) { return USB_ERROR; } #endif if (Qh->Type <= NewQh->Type) { if (ByInterval == FALSE || Qh->Interval <= NewQh->Interval) { break; } } PrevPtr = &Qh->pLinkPtr; LinkPtr = *PrevPtr; } if (Qh == NewQh) { continue; } #if USB_RUNTIME_DRIVER_IN_SMM Status = AmiValidateMemoryBuffer((VOID*)PrevPtr, sizeof(UINT32)); if (EFI_ERROR(Status)) { return USB_ERROR; } #endif NewQh->pLinkPtr = *PrevPtr; *PrevPtr = (UINT32)((UINTN)NewQh | UHCI_QUEUE_HEAD); } return USB_SUCCESS; } // //--------------------------------------------------------------------------- // // Name: UhciRemoveQhFromFrameList // // Description: // This routine will remove a QH from the the frame list // // Input: // HcStruc Pointerr to the host controller structure // RetiredQh Address of the QH to be removed // // Output: // USB_SUCCESS/USB_ERROR // //--------------------------------------------------------------------------- // UINT8 UhciRemoveQhFromFrameList ( HC_STRUC *HcStruc, UHCI_QH *RetiredQh ) { UINT16 Index; UINT32 *PrevPtr; UINT32 LinkPtr; UHCI_QH *Qh; BOOLEAN ByInterval = FALSE; EFI_STATUS Status = EFI_SUCCESS; if (RetiredQh == NULL) { return USB_ERROR; } switch (RetiredQh->Type) { case Control: case Bulk: ByInterval = FALSE; break; case Interrupt: ByInterval = TRUE; break; case Isochronous: ASSERT(FALSE); default: return USB_ERROR; } if (ByInterval && RetiredQh->Interval == 0) { return USB_ERROR; } RetiredQh->pElementPtr = UHCI_TERMINATE; for (Index = 0; Index < HcStruc->wAsyncListSize; ByInterval ? Index += RetiredQh->Interval : Index++) { PrevPtr = &HcStruc->fpFrameList[Index]; LinkPtr = *PrevPtr; while (!(LinkPtr & UHCI_TERMINATE)) { Qh = (UHCI_QH*)(LinkPtr & UHCI_POINTER_MASK); #if USB_RUNTIME_DRIVER_IN_SMM Status = AmiValidateMemoryBuffer((VOID*)Qh, sizeof(UHCI_QH)); if (EFI_ERROR(Status)) { return USB_ERROR; } #endif if (Qh == RetiredQh) { break; } PrevPtr = &Qh->pLinkPtr; LinkPtr = *PrevPtr; } if (LinkPtr & UHCI_TERMINATE) { continue; } #if USB_RUNTIME_DRIVER_IN_SMM Status = AmiValidateMemoryBuffer((VOID*)PrevPtr, sizeof(UINT32)); if (EFI_ERROR(Status)) { return USB_ERROR; } #endif *PrevPtr = RetiredQh->pLinkPtr; } RetiredQh->pLinkPtr = UHCI_TERMINATE; return USB_SUCCESS; } // //--------------------------------------------------------------------------- // // Name: UHCI_StartTDSchedule (fpHCStruc) // // Description: // This routine will start the TD schedule for the UHCI controller. After this // routine TD's can be scheduled for execution. // // Input: // fpHCStruc Pointer to the HC information structure // // Output: // USB_SUCCESS/USB_ERROR // //--------------------------------------------------------------------------- // UINT8 UHCI_StartTDSchedule ( HC_STRUC *HcStruc ) { UHCI_DESC_PTRS *DescPtr; UHCI_TD *Td; // // Allocate the UHCI descriptor pointer structure // DescPtr = (UHCI_DESC_PTRS*) USB_MemAlloc (GET_MEM_BLK_COUNT_STRUC(UHCI_DESC_PTRS)); if (DescPtr == NULL) { USB_DEBUG(DEBUG_LEVEL_4, "UHCI Descriptor struc alloc failed.\n"); return USB_ERROR; } // // Save the value in the HC struc // HcStruc->stDescPtrs.fpUHCIDescPtrs = DescPtr; DescPtr->StaticQh = USB_MemAlloc(GET_MEM_BLK_COUNT(1 * sizeof(UHCI_QH))); if (DescPtr->StaticQh == NULL) { return USB_ERROR; } UhciInitQh(DescPtr->StaticQh); DescPtr->StaticQh->Type = Interrupt; DescPtr->StaticQh->Interval = 1; UhciAddQhToFrameList(HcStruc, DescPtr->StaticQh); if (HcStruc->dHCFlag & HC_STATE_EXTERNAL) { return USB_SUCCESS; } DescPtr->RepeatQh = USB_MemAlloc(GET_MEM_BLK_COUNT(1 * sizeof(UHCI_QH) + 1 * sizeof(UHCI_TD))); if(DescPtr->RepeatQh == NULL) { return USB_ERROR; } Td = (UHCI_TD*)((UINTN)DescPtr->RepeatQh + sizeof (UHCI_QH)); // // Initialize the body of TdRepeat. It will run a interrupt transaction // to a non-existant dummy device. This will have the effect of generating // a periodic interrupt used to generate keyboard repeat. This TD is normally // inactive, and is only activated when a key is pressed. TdRepeat will be // set to timeout after two attempts. Since the TD is in the schedule // at 16ms intervals, this will generate an interrupt at intervals of 32ms // (when the TD is active). This 32ms periodic interrupt may then // approximate the fastest keyboard repeat rate of 30 characters per second. // Td->pLinkPtr = UHCI_TERMINATE; Td->dControlStatus = UHCI_TD_ONE_ERROR; Td->dToken = (UHCI_TD_IN_PACKET | ((UINT32)DUMMY_DEVICE_ADDR << 8) | ((UINT32)(DEFAULT_PACKET_LENGTH - 1) << 21)); Td->pBufferPtr = (UINT32)(UINTN)Td->aDataArea; Td->dCSReload = UHCI_TD_ONE_ERROR; Td->bActiveFlag = 0; UhciInitQh(DescPtr->RepeatQh); DescPtr->RepeatQh->Type = Interrupt; DescPtr->RepeatQh->FirstTd = Td; DescPtr->RepeatQh->Interval = REPEAT_INTERVAL; DescPtr->RepeatQh->CallBackIndex = USB_InstallCallBackFunction(UhciRepeatQhCallback); DescPtr->RepeatQh->ActiveFlag = FALSE; // // Schedule the TDRepeat to 8ms schedule // UhciAddQhToFrameList(HcStruc, DescPtr->RepeatQh); // // Inform the common code that key repeat is implemented // USBKeyRepeat(HcStruc, 0); // // Initialize the body of root hub TD. It will run a interrupt // transaction to a nonexistent dummy device. This will have the effect // of generating a periodic interrupt for the purpose of checking for // attach/detach on the root hub's ports // This initialization is done only once for the first HC // DescPtr->RootHubQh = USB_MemAlloc(GET_MEM_BLK_COUNT(1 * sizeof(UHCI_QH) + 1 * sizeof(UHCI_TD))); ASSERT(DescPtr->RootHubQh != NULL); if (DescPtr->RootHubQh == NULL) { return USB_ERROR; } Td = (UHCI_TD*)((UINTN)DescPtr->RootHubQh + sizeof (UHCI_QH)); Td->pLinkPtr = UHCI_TERMINATE; Td->dControlStatus = 0; Td->dToken = (UHCI_TD_IN_PACKET | ((UINT32)DUMMY_DEVICE_ADDR << 8) | ((UINT32)(DEFAULT_PACKET_LENGTH - 1) << 21)); Td->pBufferPtr = (UINT32)(UINTN)Td->aDataArea; Td->dCSReload = 0; Td->bActiveFlag = 0; UhciInitQh(DescPtr->RootHubQh); DescPtr->RootHubQh->Type = Interrupt; DescPtr->RootHubQh->FirstTd = Td; DescPtr->RootHubQh->Interval = 128; DescPtr->RootHubQh->CallBackIndex = USB_InstallCallBackFunction(UhciRootHubQhCallBack); DescPtr->RootHubQh->ActiveFlag = FALSE; // // Schedule the root hub TD to 256ms schedule // UhciAddQhToFrameList(HcStruc, DescPtr->RootHubQh); if (gUsbData->RootHubHcStruc == NULL) { Td->dCSReload = UHCI_TD_INTERRUPT_ON_COMPLETE | UHCI_TD_ONE_ERROR | UHCI_TD_ACTIVE; Td->bActiveFlag = 1; Td->dControlStatus = Td->dCSReload; DescPtr->RootHubQh->pElementPtr = (UINT32)(UINTN)Td; DescPtr->RootHubQh->CurrentTd = Td; DescPtr->RootHubQh->ActiveFlag = TRUE;; gUsbData->RootHubHcStruc = HcStruc; } USB_DEBUG(DEBUG_LEVEL_4, "TD's are scheduled\n"); return USB_SUCCESS; } // //--------------------------------------------------------------------------- // // Name: UHCI_StopTDSchedule (fpHCStruc) // // Description: // This routine will stop the TD schedules and frees the data structures // // Input: // fpHCStruc Pointer to the HC information structure // // Output: // USB_SUCCESS/USB_ERROR // //--------------------------------------------------------------------------- // UINT8 UHCI_StopTDSchedule ( HC_STRUC *HcStruc ) { UINT8 i; UHCI_DESC_PTRS *DescPtrs = HcStruc->stDescPtrs.fpUHCIDescPtrs; UINT8 *MemBlockEnd = gUsbData->fpMemBlockStart + (gUsbData->MemPages << 12); // // Free all the TD/QH data structures // if (DescPtrs == NULL) { return USB_ERROR; } if (((UINT8*)DescPtrs < gUsbData->fpMemBlockStart) || ((UINT8*)(DescPtrs + sizeof(UHCI_DESC_PTRS)) > MemBlockEnd)) { return USB_ERROR; } if (((UINT8*)DescPtrs->StaticQh < gUsbData->fpMemBlockStart) || ((UINT8*)(DescPtrs->StaticQh + sizeof(UHCI_QH)) > MemBlockEnd)) { return USB_ERROR; } if (((UINT8*)DescPtrs->RootHubQh < gUsbData->fpMemBlockStart) || ((UINT8*)(DescPtrs->RootHubQh + sizeof(UHCI_QH)) > MemBlockEnd)) { return USB_ERROR; } if (((UINT8*)DescPtrs->RepeatQh < gUsbData->fpMemBlockStart) || ((UINT8*)(DescPtrs->RepeatQh + sizeof(UHCI_QH)) > MemBlockEnd)) { return USB_ERROR; } USB_MemFree (DescPtrs->StaticQh, GET_MEM_BLK_COUNT(sizeof(UHCI_QH))); if (DescPtrs->RootHubQh) { USB_MemFree (DescPtrs->RootHubQh, GET_MEM_BLK_COUNT(sizeof(UHCI_QH) + sizeof(UHCI_TD))); } if (DescPtrs->RepeatQh) { USB_MemFree (DescPtrs->RepeatQh, GET_MEM_BLK_COUNT(sizeof(UHCI_QH) + sizeof(UHCI_TD))); } // // Finally free the descriptor pointer // USB_MemFree (DescPtrs, GET_MEM_BLK_COUNT_STRUC(UHCI_DESC_PTRS)); USBKeyRepeat(HcStruc, 3); if (gUsbData->RootHubHcStruc == HcStruc) { gUsbData->RootHubHcStruc = NULL; for (i = 0; i < gUsbData->HcTableCount; i++) { if (gUsbData->HcTable[i] == NULL) { continue; } if ((gUsbData->HcTable[i]->bHCNumber) && (gUsbData->HcTable[i]->bHCType == USB_HC_UHCI) && (gUsbData->HcTable[i]->dHCFlag & HC_STATE_RUNNING) && (HcStruc != gUsbData->HcTable[i])) { DescPtrs = gUsbData->HcTable[i]->stDescPtrs.fpUHCIDescPtrs; if (((UINT8*)DescPtrs < gUsbData->fpMemBlockStart) || ((UINT8*)(DescPtrs + sizeof(UHCI_DESC_PTRS)) > MemBlockEnd)) { return USB_ERROR; } if (((UINT8*)DescPtrs->RootHubQh < gUsbData->fpMemBlockStart) || ((UINT8*)(DescPtrs->RootHubQh + sizeof(UHCI_QH)) > MemBlockEnd)) { return USB_ERROR; } if (((UINT8*)DescPtrs->RootHubQh->FirstTd < gUsbData->fpMemBlockStart) || ((UINT8*)(DescPtrs->RootHubQh->FirstTd + sizeof(UHCI_TD)) > MemBlockEnd)) { return USB_ERROR; } if (((UINT8*)DescPtrs->RootHubQh->CurrentTd < gUsbData->fpMemBlockStart) || ((UINT8*)(DescPtrs->RootHubQh->CurrentTd + sizeof(UHCI_TD)) > MemBlockEnd)) { return USB_ERROR; } DescPtrs->RootHubQh->FirstTd->dCSReload = UHCI_TD_INTERRUPT_ON_COMPLETE | UHCI_TD_ONE_ERROR | UHCI_TD_ACTIVE; DescPtrs->RootHubQh->FirstTd->bActiveFlag = 1; DescPtrs->RootHubQh->FirstTd->dControlStatus = DescPtrs->RootHubQh->FirstTd->dCSReload; DescPtrs->RootHubQh->pElementPtr = (UINT32)(UINTN)DescPtrs->RootHubQh->FirstTd; DescPtrs->RootHubQh->CurrentTd = DescPtrs->RootHubQh->FirstTd; DescPtrs->RootHubQh->ActiveFlag = TRUE;; gUsbData->RootHubHcStruc = gUsbData->HcTable[i]; } } } return USB_SUCCESS; } // //--------------------------------------------------------------------------- // // Name: UhciProcessQh // // Description: // This function will check whether the QH is completed if so, it will call // the call back routine associated with the TDs present in the QH // // Input: // HcStruc HCStruc structure // Qh Pointer to the QH // // Output: // USB_SUCCESS or USB_ERROR // //--------------------------------------------------------------------------- // UINT8 UhciProcessQh( HC_STRUC *HcStruc, UHCI_QH *Qh ) { UHCI_TD *Td; UINT16 Length; EFI_STATUS Status; if (Qh == NULL) { return USB_ERROR; } if (Qh->ActiveFlag == FALSE) { return USB_SUCCESS; } if (Qh->FirstTd == NULL) { return USB_SUCCESS; } if (Qh->CurrentTd == NULL) { Qh->CurrentTd = Qh->FirstTd; } Td = Qh->CurrentTd; while (Td) { Qh->CurrentTd = Td; Qh->DataToggle = Td->dToken & UHCI_TD_DATA_TOGGLE ? 1 : 0; if (Td->dControlStatus & UHCI_TD_ACTIVE) { return USB_ERROR; } Length = (UINT16)((Td->dControlStatus + 1) & UHCI_TD_ACTUAL_LENGTH); Qh->BytesTransferred += Length; if (Td->dControlStatus & UHCI_TD_STATUS_FIELD) { break; } Qh->DataToggle ^= 1; Qh->ShortPacketDetected = (Length < (((Td->dToken >> 21) + 1) & 0x7FF)); if (Qh->ShortPacketDetected) { if (Qh->Type == Control) { while (!(Td->pLinkPtr & UHCI_TERMINATE)) { Td = (UHCI_TD*)((UINTN)Td->pLinkPtr & UHCI_POINTER_MASK); } Qh->pElementPtr = (UINT32)(UINTN)Td; continue; } break; } Td = Td->pLinkPtr & UHCI_TERMINATE ? NULL : (UHCI_TD*)(Td->pLinkPtr & UHCI_POINTER_MASK); } Qh->ActiveFlag = FALSE; if (Qh->CallBackIndex == 0) { return USB_SUCCESS; } if ((Qh->CallBackIndex) && (Qh->CallBackIndex <= MAX_CALLBACK_FUNCTION)) { if (gUsbData->aCallBackFunctionTable[Qh->CallBackIndex - 1]) { if ((gUsbData->aCallBackFunctionTable[Qh->CallBackIndex - 1] != UhciRepeatQhCallback) && (gUsbData->aCallBackFunctionTable[Qh->CallBackIndex - 1] != UhciRootHubQhCallBack)) { Status = UsbDevInfoValidation(Qh->DevInfoPtr); if (EFI_ERROR(Status)) { return USB_ERROR; } } (*gUsbData->aCallBackFunctionTable[Qh->CallBackIndex - 1])( HcStruc, (DEV_INFO*)Qh->DevInfoPtr, (UINT8*)Qh, 0, 0); } } return USB_SUCCESS; } // //--------------------------------------------------------------------------- // // Name: UhciProcessTd // // Description: // This function will check whether the TD is completed if so, it will call // the call back routine associated with this TD // // Input: // HcStruc HCStruc structure // Td Pointer to the TD // // Output: // USB_SUCCESS or USB_ERROR // // Notes: // For any TD whose ActiveFlag is TRUE and its ControlStatus bit 23 is clear // (completed), process the TD by calling its callback routine, if one is present. // //--------------------------------------------------------------------------- // UINT8 UhciProcessTd( HC_STRUC *HcStruc, UHCI_TD *Td ) { UINT8 DevAddr; DEV_INFO *DevInfo; if (Td == NULL) { // Check for NULL return USB_ERROR; } if (Td->bActiveFlag == 0) { return USB_SUCCESS; } if (Td->dControlStatus & UHCI_TD_ACTIVE) { return USB_ERROR; } Td->bActiveFlag = 0; if ((Td->bCallBackIndex) && (Td->bCallBackIndex <= MAX_CALLBACK_FUNCTION)) { // // Get the device address from the completed TD // DevAddr = (UINT8)(((Td->dToken) >> 8) & 0x7F); DevInfo = USB_GetDeviceInfoStruc(USB_SRCH_DEV_ADDR, 0, DevAddr, HcStruc); if (gUsbData->aCallBackFunctionTable[Td->bCallBackIndex - 1]) { (*gUsbData->aCallBackFunctionTable[Td->bCallBackIndex - 1])( HcStruc, DevInfo, (UINT8*)Td, 0, 0); } } return USB_SUCCESS; } // //--------------------------------------------------------------------------- // // Name: UhciProcessFrameList // // Description: // This function will parse through frame list to find completed QH/TD // and invoke corresponding call back routine // // Input: // HcStruc HCStruc structure // // Output: // USB_SUCCESS or USB_ERROR // // Notes: // For any TD whose ActiveFlag is TRUE and its ControlStatus bit 23 is clear // (completed), process the TD by calling its call back routine, if one is present. // //--------------------------------------------------------------------------- // UINT8 UhciProcessFrameList ( HC_STRUC *HcStruc ) { UINT32 ListPtr; EFI_STATUS Status = EFI_SUCCESS; ListPtr = HcStruc->fpFrameList[0]; while (!(ListPtr & UHCI_TERMINATE)) { if (ListPtr & UHCI_QUEUE_HEAD) { #if USB_RUNTIME_DRIVER_IN_SMM Status = AmiValidateMemoryBuffer((VOID*)ListPtr, sizeof(UHCI_QH)); if (EFI_ERROR(Status)) { return USB_ERROR; } #endif UhciProcessQh(HcStruc, (UHCI_QH*)(ListPtr & UHCI_POINTER_MASK)); ListPtr = ((UHCI_QH*)(ListPtr & UHCI_POINTER_MASK))->pLinkPtr; } else { #if USB_RUNTIME_DRIVER_IN_SMM Status = AmiValidateMemoryBuffer((VOID*)ListPtr, sizeof(UHCI_TD)); if (EFI_ERROR(Status)) { return USB_ERROR; } #endif UhciProcessTd(HcStruc, (UHCI_TD*)(ListPtr & UHCI_POINTER_MASK)); ListPtr = ((UHCI_TD*)(ListPtr & UHCI_POINTER_MASK))->pLinkPtr; } } return USB_SUCCESS; } // //--------------------------------------------------------------------------- // // Name: UHCI_RootHubTDCallBack // // Description: // This function is called when TD256ms completes a transaction. This TD runs // a dummy interrupt transaction to a non-existant device address for the // purpose of generating a periodic timeout interrupt. This periodic interrupt // may be used to check for new devices on the root hub etc. // // Input: // fpHCStruc Pointer to the HCStruc structure // fpDevInfo NULL (pDevInfo is not valid) // fpTD Pointer to the TD that completed // fpBuffer Not used // // Output: // USB_SUCCESS or USB_ERROR // //--------------------------------------------------------------------------- // UINT8 UhciRootHubQhCallBack( HC_STRUC *HcStruc, DEV_INFO *DevInfo, UINT8 *Qh, UINT8 *Buffer, UINT16 DataLength ) { UINT8 Index; HC_STRUC *Hc; UINT16 IoPort; UINT16 PortAddr; UHCI_QH *RootHubQh; // // First deactivate the TDRootHub so this callback function will not get // reentered. // if (Qh != NULL) { RootHubQh = (UHCI_QH*)Qh; RootHubQh->FirstTd->bActiveFlag = 0; } for (Index = 0; Index < gUsbData->HcTableCount; Index++) { Hc = gUsbData->HcTable[Index]; if (Hc == NULL) { continue; } if (Hc->bHCType != USB_HC_UHCI) { // Process for UHCI only continue; } if (!(Hc->dHCFlag & HC_STATE_RUNNING)) { continue; } // // Check whether the controller is still under BIOS control // Read the frame list base address and compare with stored value // IoPort = (UINT16)Hc->BaseAddress; if ((DwordReadIO(IoPort + UHCI_FRAME_LIST_BASE) & 0xFFFFF000) != (UINT32)Hc->fpFrameList) { continue; } // // Check whether USB host controllers are accessible to aVOID system // hang in ports enumeration. // if (ByteReadIO(IoPort) == 0xFF) { continue; } // // Check whether enumeration is already began // if(gUsbData->bEnumFlag == FALSE) { gUsbData->bEnumFlag = TRUE; // // Mask the Host Controller interrupt so the ISR does not get re-entered due // to an IOC interrupt from any TDs that complete in frames while we are // configuring a new device that has just been plugged in. // // Disable IOC, timeout & CRC interrupt // WordWriteIO((UINT16)(IoPort + UHCI_INTERRUPT_ENABLE), 0); // // Process Port#1 and clear Port#1 status bit // PortAddr = IoPort + UHCI_PORT1_CONTROL; if (WordReadIO(PortAddr) & UHC_CONNECT_STATUS_CHANGE) { USBCheckPortChange(Hc, Hc->bHCNumber | BIT7, 1); WordWriteIO(PortAddr, WordReadIO(PortAddr)); } // // Process Port#2 and clear Port#2 status bit // PortAddr = IoPort + UHCI_PORT2_CONTROL; if (WordReadIO(PortAddr) & UHC_CONNECT_STATUS_CHANGE) { USBCheckPortChange(Hc, Hc->bHCNumber | BIT7, 2); WordWriteIO(PortAddr, WordReadIO(PortAddr)); } // // Renable interrupts from the host controller // Enable IOC, timeout & CRC interrupt // WordWriteIO((UINT16)(IoPort + UHCI_INTERRUPT_ENABLE), (UINT16)(UHC_IOC_ENABLE)); gUsbData->bEnumFlag = FALSE; } } // // Reactivate the TdRootHub // if (Qh != NULL) { RootHubQh->FirstTd->dControlStatus = RootHubQh->FirstTd->dCSReload; RootHubQh->FirstTd->bActiveFlag = 1; RootHubQh->pElementPtr = (UINT32)(UINTN)RootHubQh->FirstTd; RootHubQh->CurrentTd = RootHubQh->FirstTd; RootHubQh->ActiveFlag = TRUE; } return USB_SUCCESS; } // //--------------------------------------------------------------------------- // // Name: UHCI_RepeatTDCallback // // Description: // This function is called when TdRepeat completes a transaction. This TD // runs a dummy interrupt transaction to a non-existant device address for // the purpose of generating a periodic timeout interrupt which in turn is // used to generate keyboard repeat. // // Input: // fpHCStruc Pointer to the HCStruc structure // fpDevInfo NULL (pDevInfo is not valid) // fpTD Pointer to the TD that completed // fpBuffer Not used // // Output: // USB_SUCCESS or USB_ERROR // //--------------------------------------------------------------------------- // UINT8 UhciRepeatQhCallback( HC_STRUC *HcStruc, DEV_INFO *DevInfo, UINT8 *Qh, UINT8 *Buffer, UINT16 DataLength ) { UHCI_QH *RepeatQh = (UHCI_QH*)Qh; USB_DEBUG(DEBUG_LEVEL_8, "Processing Repeat TD ...\n"); // // First deactivate the TdRepeat so this callback function will not get // re-entered. // RepeatQh->FirstTd->bActiveFlag = 0; #if USB_DEV_KBD USBKBDPeriodicInterruptHandler(HcStruc); #endif // // Reactivate the TdRepeat // if (RepeatQh->FirstTd->dCSReload & UHCI_TD_ACTIVE) { RepeatQh->FirstTd->dControlStatus = RepeatQh->FirstTd->dCSReload; RepeatQh->FirstTd->bActiveFlag = 1; RepeatQh->pElementPtr = (UINT32)(UINTN)RepeatQh->FirstTd; RepeatQh->CurrentTd = RepeatQh->FirstTd; RepeatQh->ActiveFlag = TRUE; } return USB_SUCCESS; } // //--------------------------------------------------------------------------- // // Name: UHCI_PollingTDCallback // // Description: // This function is called when a polling TD from the TD pool completes an // interrupt transaction to its assigned device. // This routine should process any data in the TD's data buffer, handle any // errors, and then copy the TD's CSReloadValue field into its control status // field to put the TD back into service. // // Input: // fpHCStruc Pointer to the HCStruc structure // fpDevInfo NULL (pDevInfo is not valid) // fpTD Pointer to the TD that completed // // Output: // USB_SUCCESS or USB_ERROR // //--------------------------------------------------------------------------- // UINT8 UhciPollingQhCallback( HC_STRUC *HcStruc, DEV_INFO *DevInfo, UINT8 *Qh, UINT8 *Buffer, UINT16 DataLength ) { UHCI_QH *PollQh = (UHCI_QH*)Qh; USB_DEBUG(DEBUG_LEVEL_8, "Processing polling TD ...\n"); UsbUpdateDataToggle(DevInfo, DevInfo->IntInEndpoint, PollQh->DataToggle); if ((PollQh->CurrentTd->dControlStatus & UHCI_TD_STATUS_FIELD) == 0) { if ((DevInfo->bCallBackIndex) && (DevInfo->bCallBackIndex <= MAX_CALLBACK_FUNCTION)) { if (gUsbData->aCallBackFunctionTable[DevInfo->bCallBackIndex - 1]) { (*gUsbData->aCallBackFunctionTable[DevInfo->bCallBackIndex-1])( HcStruc, DevInfo, Qh, DevInfo->fpPollDataBuffer, PollQh->BytesTransferred); } } } UhciActivateTds(PollQh->FirstTd, PollQh->DataToggle); PollQh->pElementPtr = (UINT32)(UINTN)PollQh->FirstTd; PollQh->CurrentTd = PollQh->FirstTd; PollQh->BytesTransferred = 0; PollQh->ActiveFlag = TRUE; return USB_SUCCESS; } // //---------------------------------------------------------------------------- // // Procedure: UhciInitQh // // Description: This function check whether HC is halted. // //---------------------------------------------------------------------------- // VOID UhciInitQh ( UHCI_QH *Qh ) { Qh->pLinkPtr = UHCI_TERMINATE; Qh->pElementPtr = UHCI_TERMINATE; Qh->CurrentTd = NULL; Qh->DataToggle = 0; Qh->BytesTransferred = 0; Qh->ShortPacketDetected = FALSE; Qh->FirstTd = NULL; Qh->Interval = 0; Qh->CallBackIndex = 0; Qh->ActiveFlag = FALSE; Qh->DevInfoPtr = NULL; } // //---------------------------------------------------------------------------- // // Procedure: UhciIsHalted // // Description: This function check whether HC is halted. // //---------------------------------------------------------------------------- // BOOLEAN UhciIsHalted ( HC_STRUC *HcStruc ) { return (ByteReadIO((UINT16)(HcStruc->BaseAddress + UHCI_STATUS_REG)) & UHC_HC_HALTED) == UHC_HC_HALTED; } // //---------------------------------------------------------------------------- // // Procedure: UhciTranslateInterval // // Description: This function calculates the polling rate. // //---------------------------------------------------------------------------- // UINT8 UhciTranslateInterval( UINT8 Interval ) { UINT8 BitCount = 0; // The Interval value should be from 1 to 255 ASSERT(Interval >= 1 && Interval <= 255); for (BitCount = 0; Interval != 0; BitCount++) { Interval >>= 1; } return (1 << (BitCount - 1)); } // //---------------------------------------------------------------------------- // // Procedure: UhciAllocGeneralTds // // Description: // //---------------------------------------------------------------------------- // UHCI_TD* UhciAllocGeneralTds ( IN UINT8 DeviceAddr, IN BOOLEAN LowSpeed, IN UINT8 PacketId, IN UINT8 EndpointAddr, IN UINT16 MaxPacket, IN BOOLEAN ShortPacket, IN OUT UINTN *BufferAddr, IN OUT UINT32 *Length, IN OUT UINT8 *DataToggle ) { UINT16 NumTds = 0; UHCI_TD *FirstTd = NULL; UHCI_TD *Td = NULL; UINTN Address = *BufferAddr; UINT32 BytesRemaining = *Length; UINT8 Toggle = *DataToggle; UINT16 MaxLen = 0; if (BytesRemaining == 0) { return NULL; } NumTds = BytesRemaining / MaxPacket; if (BytesRemaining % MaxPacket) { NumTds++; } FirstTd = USB_MemAlloc(GET_MEM_BLK_COUNT(NumTds * sizeof(UHCI_TD))); if (FirstTd == NULL) { return NULL; } for (Td = FirstTd;;) { MaxLen = BytesRemaining > MaxPacket ? MaxPacket : BytesRemaining; Td->pLinkPtr = UHCI_TERMINATE; Td->dToken = (UINT32)PacketId | ((UINT32)DeviceAddr << 8) | ((UINT32)EndpointAddr << 15) | ((MaxLen - 1) << 21); if (Toggle) { Td->dToken |= UHCI_TD_DATA_TOGGLE; } Td->pBufferPtr = (UINT32)Address; Td->dCSReload = UHCI_TD_THREE_ERRORS | UHCI_TD_ACTIVE; if (LowSpeed) { Td->dCSReload |= UHCI_TD_LOW_SPEED_DEVICE; } if (ShortPacket) { Td->dCSReload |= UHCI_TD_SHORT_PACKET_DETECT; } Td->dControlStatus = Td->dCSReload; Td->bActiveFlag = 1; BytesRemaining -= MaxLen; Address += MaxLen; Toggle ^= 1; if (BytesRemaining == 0) { break; } Td->pLinkPtr = (UINT32)(((UINTN)Td + sizeof(UHCI_TD)) | UHCI_VERTICAL_FLAG); Td = (UHCI_TD*)((UINTN)Td->pLinkPtr & UHCI_POINTER_MASK); } Td->dCSReload |= UHCI_TD_INTERRUPT_ON_COMPLETE; Td->dControlStatus = Td->dCSReload; *Length = BytesRemaining; *BufferAddr = Address; *DataToggle = Toggle; return FirstTd; } // //---------------------------------------------------------------------------- // // Procedure: UhciFreeTds // // Description: // //---------------------------------------------------------------------------- // VOID UhciFreeTds ( IN UHCI_TD *FirstTd ) { UHCI_TD *Td = FirstTd; UINT16 NumTds = 0; if (FirstTd == NULL) { return; } while (Td) { NumTds++; Td = Td->pLinkPtr & UHCI_TERMINATE ? NULL : (UHCI_TD*)((UINTN)Td->pLinkPtr & UHCI_POINTER_MASK); } USB_MemFree(FirstTd, GET_MEM_BLK_COUNT(NumTds * sizeof(UHCI_TD))); } // //---------------------------------------------------------------------------- // // Procedure: UhciActivateTds // // Description: // //---------------------------------------------------------------------------- // VOID UhciActivateTds ( IN UHCI_TD *FirstTd, IN UINT8 DataToggle ) { UHCI_TD *Td = FirstTd; UINT8 Toogle = DataToggle; if (FirstTd == NULL) { return; } while (Td) { Td->dToken &= ~UHCI_TD_DATA_TOGGLE; if (Toogle) { Td->dToken |= UHCI_TD_DATA_TOGGLE; } Td->dControlStatus = Td->dCSReload; Td->bActiveFlag = 1; Toogle ^= 1; Td = Td->pLinkPtr & UHCI_TERMINATE ? NULL : (UHCI_TD*)((UINTN)Td->pLinkPtr & UHCI_POINTER_MASK); } } //**************************************************************************** //**************************************************************************** //** ** //** (C)Copyright 1985-2016, American Megatrends, Inc. ** //** ** //** All Rights Reserved. ** //** ** //** 5555 Oakbrook Pkwy, Norcross, GA 30093 ** //** ** //** Phone (770)-246-8600 ** //** ** //**************************************************************************** //****************************************************************************