diff options
Diffstat (limited to 'Core/EM/usb/rt/ohci.c')
-rw-r--r-- | Core/EM/usb/rt/ohci.c | 3379 |
1 files changed, 3379 insertions, 0 deletions
diff --git a/Core/EM/usb/rt/ohci.c b/Core/EM/usb/rt/ohci.c new file mode 100644 index 0000000..2389a93 --- /dev/null +++ b/Core/EM/usb/rt/ohci.c @@ -0,0 +1,3379 @@ +//**************************************************************************** +//**************************************************************************** +//** ** +//** (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/ohci.c 98 10/16/16 10:12p Wilsonlee $ +// +// $Revision: 98 $ +// +// $Date: 10/16/16 10:12p $ +//**************************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/USB/ALASKA/RT/ohci.c $ +// +// 98 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 +// +// 97 7/28/16 4:56a Wilsonlee +// [TAG] EIP264662 +// [Category] Improvement +// [Description] Don't install usb hw smi after reconnecting usb +// controllers. +// [Files] uhcd.c, usb.c, ohci.c, amiusb.c, amiusbhc.c +// +// 96 7/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 +// +// 95 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 +// +// 94 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 +// +// 93 3/02/16 9:42p Wilsonlee +// [TAG] EIP254309 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] GK-FORCE K83 USB KB function abnormal. +// [RootCause] This device has an interrupt out endpoint and doesn't +// support "Set Report" request. +// [Solution] Use the interrupt out endpoint instead of sending "Set +// Report" request. +// [Files] AmiUsbController.h, xhci.c, usbmass.c, usbkbd.h, usbkbd.c, +// usbhub.c, usbhid.c, usbdef.h, usbCCID.c, usb.c, uhci.c, ohci.c, ehci.c, +// amiusb.h, efiusbms,c, amiusbhc.c +// +// 92 9/01/15 10:46p Wilsonlee +// [TAG] EIP235977 +// [Category] Improvement +// [Description] Break the loop which we check list processing TD if +// NextTd is the same as Td. +// [Files] ohci.c +// +// 91 3/08/15 10:50p 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 +// +// 90 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 +// +// 89 5/01/14 3:56a Ryanchou +// [TAG] EIP162589 +// [Category] Improvement +// [Description] Do not register external controller as key repeat +// controller. +// [Files] ehci.c, ohci.c, uhci.c +// +// 88 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 +// +// 87 4/30/14 5:25a Wilsonlee +// [TAG] EIP164842 +// [Category] Improvement +// [Description] Check if the devices have put into to our queue before +// we put them. +// [Files] UsbInt13.c, amiusb.c, ehci.c, ohci.c, usb.c, usbdef.h, +// usbmass.c, xhci.c, amiusbhc.c, efiusbmass.c, uhcd.c, usbbus.c, usbsb.c +// +// 86 2/26/14 1:56a 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 +// +// 85 7/26/13 2:36a 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 +// +// 84 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 +// +// 83 6/28/13 2:29a Roberthsu +// [TAG] EIP124581 +// [Category] Improvement +// [Description] Controller driver always return the length passed in +// parameter, devices may return zero length data, it should be corrected. +// [Files] ohci.c +// +// 82 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 +// +// 81 4/18/13 1:02p Ryanchou +// Add Teradici USB controller support. +// +// 80 4/10/13 11:23p Ryanchou +// [TAG] EIP111483 +// [Category] Improvement +// [Description] Increase the delay when OHCI port reset complete. +// [Files] ohci.c +// +// 79 3/19/13 3:59a 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 +// +// 78 3/18/13 4:48a 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 +// +// 77 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 +// +// 76 1/11/13 4:16a Ryanchou +// [TAG] EIP102491 +// [Category] Improvement +// [Description] Synchronized with Aptio V USB module +// [Files] usbport.c, usbsb.c, ehci.c, ehci.h, ohci.c, ohci.h, uhci.h, +// usb.c, usbdef.h, usbhid.c, usbhub.c, usbkbd.c, usbkbd.h, usbmass.c. +// usbms.c, usbpoint.c, xhci.h, usb.sd, amiusbhc.c, componentname.c, +// efiusbkc.c, efiusbmass.c, uhcd.c, uhcd.h, usbbus.c, usbbus.h, usbmisc.c +// +// 75 12/24/12 5:06a Ryanchou +// [TAG] EIP103031 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] System hans when loading QNX 6.5.0 +// [RootCause] The EHCI port detect change SMI is generated after +// ownership change to OS. +// [Solution] Clear the SMI enable bits and status bits even the +// controller is OS owned. +// [Files] ehci.c, ohci.c +// +// 74 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 +// +// 73 11/13/12 7:12a Wilsonlee +// [TAG] EIP82553 +// [Category] New Feature +// [Description] Support usb S5 wake up function for XHCI. +// [Files] usb.c, ehci.c, ohci.c, xhci.c, xhci.h +// +// 72 11/10/12 6:40a 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 +// +// 71 10/25/12 4:16a Wilsonlee +// [TAG] EIP82354 +// [Category] New Feature +// [Description] Support usb S5 wake up function for OHCI. +// [Files] usb.c, ehci.c, ohci.c +// +// 70 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 +// +// 69 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 +// +// 68 8/28/12 5:19a Ryanchou +// [TAG] EIP98857 +// [Category] Improvement +// [Description] WriteBackDoneHead status bit shall be cleared even +// HccaDoneHead is zero. +// [Files] ohci.c +// +// 67 7/25/12 4:44a Wilsonlee +// [TAG] EIP95959 +// [Category] Improvement +// [Description] Don't set INTERRUPT_ROUTING if the ohci is external usb +// pci controller card. +// [Files] ohci.c +// +// 66 5/04/12 6:38a 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 +// +// 65 5/04/12 5:25a Wilsonlee +// [TAG] EIP89307 +// [Category] Improvement +// [Description] Modify incorrect #pragma pack directive. +// [Files] amidef.h, amiusb.c, ehci.h, ohci.c, ohci.h, uhci.h, usb.c, +// usbdef.h, xhci.h, efiusbmass.c, uhcd.c, uhcd.h, usbbus.c, usbbus.h, +// UsbIo.h +// +// 64 5/03/12 6:01a 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 +// +// 63 11/08/11 1:57a 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 +// +// 62 9/26/11 11:40p 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 +// +// 61 8/24/11 2:14a Ryanchou +// [TAG] EIP66448 +// [Category] New Feature +// [Description] Clear connect status change and port enable status +// change. +// [Files] ohci.c +// +// 60 8/08/11 6:58a 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 +// +// 59 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 +// +// 58 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 +// +// 57 7/12/11 8:10a 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 +// +// 56 7/12/11 6:17a Ryanchou +// [TAG] EIP59707 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] The wireless USB keyboard does not work after boot into +// windows loader. +// [RootCause] The amount of data returned by the device exceeded the +// size of the maximum data packet allowed, that causes babble error, and +// BIOS does not re-init the polling TD. +// [Solution] Re-init polling TD even the last transaction get error. +// [Files] ohci.c +// +// 55 6/21/11 9:56a Ryanchou +// [TAG] EIP59663 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Plug USB WLAN device may causes OHCI malfunction. +// [RootCause] The devices have to connect to OHCI first, or it can't be +// configured. +// [Solution] Port routing route to EHCI after OHCI initialization. +// [Files] ehci.c, ohci.c +// +// 54 5/03/11 10:10a 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 +// +// 53 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 +// +// 52 3/30/11 9:04a Ryanchou +// +// 51 3/29/11 10:50p 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 +// +// 50 3/29/11 10:11a 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 +// +// 49 3/16/11 8:51a Ryanchou +// [TAG] EIP55025 +// [Category] Bug Fix +// [Severity] Normal +// [Symptom] Finger Print function fail +// [RootCause] Wrong tranferred data size on short packet condition. +// [Files] ohci.c +// +// 48 11/11/10 11:34p 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 +// +// 47 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. +// +// 46 6/07/10 8:55a Ryanchou +// EIP38547: Fixed system halt when installing FreeBSD. +// +// 45 3/10/10 6:35p Olegi +// +// 44 3/06/10 1:11p Olegi +// +// 43 2/26/10 4:23p Olegi +// +// 42 2/23/10 1:21p Olegi +// Work around Klockwork issues. EIP34370 +// +// 41 2/08/10 10:00a Olegi +// EIP33381: Implement multiple bulk endpoint in UsbIoProtocol. +// +// 40 1/04/10 9:20a Olegi +// EIP32956: Polling rate for the keyboards has been changed from 8 ms to +// 32 ms. +// +// 39 12/23/09 11:59a Olegi +// +// 38 12/08/09 3:33p Olegi +// EIP32387: Bugfix in OHCI_FreeAllStruc; memory was not released properly +// when USB_FORCE_64BIT_ALIGNMENT is set. +// +// 37 11/24/09 12:43p Olegi +// EIP#26693: fixed OHCI_DISABLE_32MS_POLLING implementation. +// +// 36 10/30/09 5:47p Olegi +// +// 35 10/13/09 9:11a Olegi +// EIP28707: OHCI ownership change modifications. +// +// 34 10/07/09 9:48a Olegi +// USB Hub error handling improvement. EIP#25601. +// +// 33 9/15/09 10:21a Olegi +// Added USB_INCMPT_HID_DATA_OVERFLOW incompatibility type. +// +// 32 2/17/09 4:01p Olegi +// +// 31 2/17/09 8:59a Olegi +// Additional modifications in BulkTransfer routine to maximize the +// bandwidth. +// +// 30 1/30/09 10:08a Olegi +// MAX_BULK_DATA_SIZE limitation moved to individual HC drivers. +// +// 29 10/06/08 3:33p Olegi +// EHCI change ownership testing in DOS fix (EIP#14855). +// +// 28 9/24/08 3:58p Olegi +// Bugfix in the memory allocation in OHCI_ActivatePolling. +// +// 27 6/16/08 10:07a Olegi +// Bugfix in OHCI_Start. +// +// 26 5/16/08 12:01p Olegi +// Compliance with AMI coding standard. +// +// 25 7/09/07 2:11p Olegi +// Changed the maximum data size of the BulkTransfer from 1kB to 64kB. +// +// 24 4/17/07 8:24a Olegi +// Device detection algorythm update, in sync with Core8. +// +// 23 3/20/07 12:22p Olegi +// +// 22 1/16/07 3:24p Olegi +// Change in OHCI_ControlTransfer: return 0 if transfer stalled. +// +// 21 1/02/07 12:17p Olegi +// +// 20 1/02/07 11:13a Olegi +// +// 19 12/28/06 4:32p Olegi +// OHCI_ProcessRootHubStatusChange is modified to properly clear the +// connect change status bit +// +// 18 12/22/06 4:05p Olegi +// Timeout implementation. +// +// 17 12/20/06 2:30p Olegi +// +// 16 12/13/06 5:40p Olegi +// X64 build update +// +// 14 11/09/06 10:16a Olegi +// +// 13 10/18/06 9:43a Andriyn +// Fix: race condition on hot-plug in / plug-off +// +// 12 10/12/06 9:37p Andriyn +// Fix: unexpected plug-off hangs with endless TIMEOUTs +// +// 11 6/09/06 10:29a Olegi +// USB_FLAG_ENABLE_BEEP_MESSAGE flag is reset while handling change of the +// controller ownership. +// +// 10 5/16/06 11:22a Olegi +// +// 9 4/14/06 6:39p Olegi +// Conversion to be able to use x64 compiler. +// +// 8 3/20/06 3:37p Olegi +// Version 8.5 - x64 compatible. +// +// 7 3/06/06 6:26p Olegi +// +// 6 1/11/06 11:53a Olegi +// +// 5 12/01/05 5:48p Olegi +// +// 4 11/29/05 12:33p Andriyn +// +// 3 6/20/05 8:55a Olegi +// .NET compiler with highest warning level and warning-as-error +// modification. +// +// 2 6/03/05 6:09p Olegi +// HW SMI registration change. +// +// 1 3/28/05 6:20p Olegi +// +// 1 3/15/05 9:23a Olegi +// Initial VSS check-in. +// +//**************************************************************************** + +//<AMI_FHDR_START> +//----------------------------------------------------------------------------- +// +// Name: Ohci.c +// +// Description: AMI USB OHCI driver source file +// +//----------------------------------------------------------------------------- +//<AMI_FHDR_END> + +#include "amidef.h" +#include "usbdef.h" +#include "amiusb.h" +#include "usbkbd.h" +#if USB_RUNTIME_DRIVER_IN_SMM +#include <AmiBufferValidationLib.h> +#endif + +#pragma warning (disable :4213) +#pragma warning (disable :4706) + +UINT8 OHCI_FillHCDEntries(HCD_HEADER*); +UINT8 OHCI_Start (HC_STRUC*); +UINT8 OHCI_Stop (HC_STRUC*); +UINT8 OHCI_DisableInterrupts (HC_STRUC*); +UINT8 OHCI_EnableInterrupts (HC_STRUC*); +UINT8 OHCI_ProcessInterrupt(HC_STRUC*); +UINT8 OHCI_GetRootHubStatus (HC_STRUC*,UINT8, BOOLEAN); +UINT8 OHCI_DisableRootHub (HC_STRUC*,UINT8); +UINT8 OHCI_EnableRootHub (HC_STRUC*,UINT8); +UINT16 OHCI_ControlTransfer (HC_STRUC*,DEV_INFO*,UINT16,UINT16,UINT16,UINT8*,UINT16); +UINT32 OHCI_BulkTransfer (HC_STRUC*,DEV_INFO*,UINT8,UINT8*,UINT32); +UINT16 OHCI_InterruptTransfer (HC_STRUC*, DEV_INFO*, UINT8, UINT16, UINT8*, UINT16); +UINT8 OHCI_DeactivatePolling (HC_STRUC*,DEV_INFO*); +UINT8 OHCI_ActivatePolling (HC_STRUC*,DEV_INFO*); +UINT8 OHCI_DisableKeyRepeat (HC_STRUC*); +UINT8 OHCI_EnableKeyRepeat (HC_STRUC*); +UINT8 OHCI_ResetRootHub (HC_STRUC*,UINT8); +UINT8 OHCI_GlobalSuspend (HC_STRUC*); //(EIP54018+) + +UINT8 OHCI_EnumeratePorts(HC_STRUC*); +UINT8 OHCI_StartEDSchedule(HC_STRUC*); +UINT8 OhciAddPeriodicEd (HC_STRUC*, OHCI_ED*); +UINT8 OhciRemovePeriodicEd (HC_STRUC*, OHCI_ED*); +UINT8 OHCI_RepeatTDCallBack(HC_STRUC*, DEV_INFO*, UINT8*, UINT8*, UINT16); +UINT8 OHCI_ResetHC(HC_STRUC*); +UINT8 OHCI_StopUnsupportedHC(HC_STRUC*); +UINT32 OHCI_ProcessRootHubStatusChange(HC_STRUC*); +UINT8 OHCIWaitForTransferComplete(HC_STRUC*, OHCI_ED*, OHCI_TD*,DEV_INFO*); +UINT8 OHCI_ControlTDCallback(HC_STRUC*, DEV_INFO*, UINT8*, UINT8*, UINT16); +VOID OHCI_ProcessTD(HC_STRUC*, OHCI_TD*); +UINT8 OHCI_GeneralTDCallback(HC_STRUC*, DEV_INFO*, UINT8*, UINT8*, UINT16); +UINT8 OHCI_PollingTDCallback(HC_STRUC*, DEV_INFO*, UINT8*, UINT8*, UINT16); +VOID StopControllerType(UINT8); +UINT8 USBCheckPortChange (HC_STRUC*, UINT8, UINT8); +VOID OHCI_FreeAllStruc(HC_STRUC* fpHCStruc); //(EIP28707+) +BOOLEAN OhciIsHalted(HC_STRUC*); +UINT8 OhciTranslateInterval(UINT8); + +UINT8 UsbGetDataToggle(DEV_INFO*,UINT8); +VOID UsbUpdateDataToggle(DEV_INFO*, UINT8, UINT8); + +extern USB_GLOBAL_DATA *gUsbData; +extern BOOLEAN gCheckUsbApiParameter; + +extern void USB_InitFrameList (HC_STRUC*, UINT32); +extern UINT32 ReadPCIConfig(UINT16, UINT8); +extern void WordWritePCIConfig(UINT16, UINT8, UINT16); +extern void DwordWritePCIConfig(UINT16, UINT8, UINT32); +extern UINT32 DwordReadMem(UINT32, UINT16); +extern void DwordWriteMem(UINT32, UINT16, UINT32); +extern void DwordSetMem(UINT32, UINT16, UINT32); +extern void DwordResetMem(UINT32, UINT16, UINT32); +extern void FixedDelay(UINTN); +extern void* USB_MemAlloc (UINT16); +extern UINT8 USB_InstallCallBackFunction (CALLBACK_FUNC); +extern DEV_INFO* USB_GetDeviceInfoStruc(UINT8, DEV_INFO*, UINT8, HC_STRUC*); +extern UINT8 USB_MemFree(void _FAR_*, UINT16); +extern UINT8 USB_DisconnectDevice(HC_STRUC*, UINT8, UINT8); //(EIP28707+) +#if USB_DEV_KBD +extern void USBKBDPeriodicInterruptHandler(HC_STRUC*); +extern void USBKeyRepeat(HC_STRUC*, UINT8); +#endif + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// FUNCTION: OHCI_FillHCDEntries +// +// DESCRIPTION: This function fills the host controller driver +// routine pointers +// +// PARAMETERS: fpHCDHeader Ptr to the host controller header structure +// +// RETURN: Status: USB_SUCCESS = Success +// USB_ERROR = Failure +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +OHCI_FillHCDEntries(HCD_HEADER *fpHCDHeader) +{ + // + // Fill the routines here + // + fpHCDHeader->pfnHCDStart = OHCI_Start; + fpHCDHeader->pfnHCDStop = OHCI_Stop; + fpHCDHeader->pfnHCDEnumeratePorts = OHCI_EnumeratePorts; + fpHCDHeader->pfnHCDDisableInterrupts = OHCI_DisableInterrupts; + fpHCDHeader->pfnHCDEnableInterrupts = OHCI_EnableInterrupts; + fpHCDHeader->pfnHCDProcessInterrupt = OHCI_ProcessInterrupt; + fpHCDHeader->pfnHCDGetRootHubStatus = OHCI_GetRootHubStatus; + fpHCDHeader->pfnHCDDisableRootHub = OHCI_DisableRootHub; + fpHCDHeader->pfnHCDEnableRootHub = OHCI_EnableRootHub; + fpHCDHeader->pfnHCDControlTransfer = OHCI_ControlTransfer; + fpHCDHeader->pfnHCDBulkTransfer = OHCI_BulkTransfer; + fpHCDHeader->pfnHCDInterruptTransfer = OHCI_InterruptTransfer; + fpHCDHeader->pfnHCDDeactivatePolling = OHCI_DeactivatePolling; + fpHCDHeader->pfnHCDActivatePolling = OHCI_ActivatePolling; + fpHCDHeader->pfnHCDDisableKeyRepeat = OHCI_DisableKeyRepeat; + fpHCDHeader->pfnHCDEnableKeyRepeat = OHCI_EnableKeyRepeat; + fpHCDHeader->pfnHCDEnableEndpoints = USB_EnableEndpointsDummy; + fpHCDHeader->pfnHCDInitDeviceData = USB_InitDeviceDataDummy; + fpHCDHeader->pfnHCDDeinitDeviceData = USB_DeinitDeviceDataDummy; + fpHCDHeader->pfnHCDResetRootHub = OHCI_ResetRootHub; + fpHCDHeader->pfnHCDClearEndpointState = 0; //(EIP54283+) + fpHCDHeader->pfnHCDGlobalSuspend = OHCI_GlobalSuspend; //(EIP54018+) + + USB_InstallCallBackFunction(OHCI_ControlTDCallback); + USB_InstallCallBackFunction(OHCI_GeneralTDCallback); + USB_InstallCallBackFunction(OHCI_PollingTDCallback); + USB_InstallCallBackFunction(OHCI_RepeatTDCallBack); + + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// FUNCTION: OHCI_Start +// +// DESCRIPTION: This API function is called to start a OHCI host controller. +// The input to the routine is the pointer to the HC structure +// that defines this host controller +// +// PARAMETERS: fpHCStruc Ptr to the host controller structure +// +// RETURN: Status: USB_SUCCESS = Success +// USB_ERROR = Failure +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +OHCI_Start (HC_STRUC* fpHCStruc) +{ + UINT32 OhciControlReg = 0; + UINT32 BaseAddr; + UINT32 HcFmInterval; + EFI_STATUS EfiStatus = EFI_SUCCESS; + + EfiStatus = UsbHcStrucValidation(fpHCStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + fpHCStruc->wAsyncListSize = OHCI_FRAME_LIST_SIZE; + fpHCStruc->dMaxBulkDataSize = MAX_OHCI_BULK_DATA_SIZE; + + // + // Get memory base address of the HC and store it in the HCStruc + // + BaseAddr = ReadPCIConfig(fpHCStruc->wBusDevFuncNum, USB_MEM_BASE_ADDRESS); + BaseAddr &= 0xFFFFFFF0; // Mask lower bits + +#if USB_RUNTIME_DRIVER_IN_SMM + EfiStatus = AmiValidateMmioBuffer((VOID*)BaseAddr, fpHCStruc->BaseAddressSize); + if (EFI_ERROR(EfiStatus)) { + USB_DEBUG(3, "Usb Mmio address is invalid, it is in SMRAM\n"); + return USB_ERROR; + } + EfiStatus = AmiValidateMmioBuffer((VOID*)fpHCStruc->fpFrameList, 0x100); + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } +#endif + + fpHCStruc->BaseAddress = BaseAddr; + + // + // Get the number of ports supported by the host controller (Offset 48h) + // + fpHCStruc->bNumPorts = (UINT8)DwordReadMem(BaseAddr, OHCI_RH_DESCRIPTOR_A); + + USB_InitFrameList (fpHCStruc, 0); + + // + // Enable the ED schedules + // + if (OHCI_StartEDSchedule(fpHCStruc) == USB_ERROR) return USB_ERROR; + + // + // First stop the host controller if it is at all active + // + if (OHCI_DisableInterrupts(fpHCStruc) == USB_ERROR) return USB_ERROR; + + // Save the contents of the HcFmInterval register + HcFmInterval = DwordReadMem(BaseAddr, OHCI_FRAME_INTERVAL); + HcFmInterval &= 0x3FFF; + if (HcFmInterval != 0x2EDF) { + USB_DEBUG(3, "OHCI: HcFmInterval %x\n", HcFmInterval); + } + HcFmInterval |= (((6 * (HcFmInterval - 210)) / 7) & 0x7FFF) << 16; + + // Issue a controller reset + if (OHCI_ResetHC(fpHCStruc) != USB_SUCCESS) { + return USB_ERROR; + } + + // Restore the value of the HcFmInterval register + DwordWriteMem(BaseAddr, OHCI_FRAME_INTERVAL, HcFmInterval); + + // + // Program the frame list base address register + // + DwordWriteMem(BaseAddr, OHCI_HCCA_REG, (UINT32)(UINTN)fpHCStruc->fpFrameList); + + // + // Set the periodic start time = 2A27h (10% off from HcFmInterval-2EDFh) + // + DwordWriteMem(BaseAddr, OHCI_PERIODIC_START, (((HcFmInterval & 0x3FFF) * 9) / 10) & 0x3FFF); + + // + // Start the host controller for periodic list and control list. + // + OhciControlReg = (PERIODIC_LIST_ENABLE | CONTROL_LIST_ENABLE | + BULK_LIST_ENABLE | USBOPERATIONAL); +#if USB_RUNTIME_DRIVER_IN_SMM + if (!(fpHCStruc->dHCFlag & HC_STATE_EXTERNAL)) { + OhciControlReg |= INTERRUPT_ROUTING; + } +#endif + DwordWriteMem((UINT32)fpHCStruc->BaseAddress, OHCI_CONTROL_REG, + OhciControlReg); + + // + // Enable interrupts from the host controller, enable SOF, WDH, RHSC interrupts + // + DwordWriteMem(BaseAddr, OHCI_INTERRUPT_ENABLE, + MASTER_INTERRUPT_ENABLE | WRITEBACK_DONEHEAD_ENABLE | + RH_STATUS_CHANGE_ENABLE | OWNERSHIP_CHANGE_ENABLE); + + // + // Set the HC state to running + // + 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; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// FUNCTION: OHCI_Stop +// +// DESCRIPTION: This API function is called to stop the OHCI controller. +// The input to the routine is the pointer to the HC structure +// that defines this host controller. +// +// PARAMETERS: fpHCStruc Ptr to the host controller structure +// +// RETURN: Status: USB_SUCCESS = Success +// USB_ERROR = Failure +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +OHCI_Stop (HC_STRUC* fpHCStruc) +{ + UINT8 Port; + EFI_STATUS EfiStatus; + + EfiStatus = UsbHcStrucValidation(fpHCStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + + if (!(fpHCStruc->dHCFlag & HC_STATE_RUNNING)) { + return USB_ERROR; + } + + for (Port = 1; Port <= fpHCStruc->bNumPorts; Port++) { + USB_DisconnectDevice(fpHCStruc, (UINT8)(fpHCStruc->bHCNumber | BIT7), Port); + } + + // + // Reset Host Controller + // + DwordWriteMem((UINT32)fpHCStruc->BaseAddress, OHCI_CONTROL_REG, USBRESET); + FixedDelay(gUsbData->UsbTimingPolicy.OhciHcResetDelay * 1000); // Wait 10ms for assertion of reset + + // + // Disable interrupts + // + DwordWriteMem((UINT32)fpHCStruc->BaseAddress, OHCI_INTERRUPT_DISABLE, 0xffffffff); + + // + // Disable OHCI KBC Emulation + // + DwordWriteMem((UINT32)fpHCStruc->BaseAddress, OHCI_HCE_CONTROL, 0); + + USB_InitFrameList (fpHCStruc, 0); + OHCI_FreeAllStruc(fpHCStruc); //(EIP28707+) + + USBKeyRepeat(fpHCStruc, 3); + + fpHCStruc->dHCFlag &= ~HC_STATE_RUNNING; + + CheckBiosOwnedHc(); + + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// FUNCTION: OHCI_RepeatTDCallBack +// +// DESCRIPTION: This function is called when TdRepeat/TD32ms 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 or update LED status. +// +// PARAMETERS: fpHCStruc Pointer to the HCStruc structure +// fpDevInfo NULL (pDevInfo is not valid) +// fpTD Pointer to the TD that completed +// fpBuffer Not used +// +// RETURN: USB_SUCCESS or USB_ERROR +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +OHCI_RepeatTDCallBack( + HC_STRUC *HcStruc, + DEV_INFO *DevInfo, + UINT8 *Td, + UINT8 *Buffer, + UINT16 DataLength +) +{ + OHCI_DESC_PTRS *DescPtrs = HcStruc->stDescPtrs.fpOHCIDescPtrs; + UINT8 *MemBlockEnd = gUsbData->fpMemBlockStart + (gUsbData->MemPages << 12); + + if (((UINT8*)DescPtrs < gUsbData->fpMemBlockStart) || + ((UINT8*)(DescPtrs + sizeof(OHCI_DESC_PTRS)) > MemBlockEnd)) { + return USB_ERROR; + } + + if (((UINT8*)DescPtrs->fpTDRepeat < gUsbData->fpMemBlockStart) || + ((UINT8*)(DescPtrs->fpTDRepeat + sizeof(OHCI_TD)) > MemBlockEnd)) { + return USB_ERROR; + } + + DescPtrs->fpTDRepeat->bActiveFlag = FALSE; + +#if USB_DEV_KBD + USBKBDPeriodicInterruptHandler(HcStruc); +#endif + + if (((UINT8*)DescPtrs->fpEDRepeat < gUsbData->fpMemBlockStart) || + ((UINT8*)(DescPtrs->fpEDRepeat + sizeof(OHCI_ED)) > MemBlockEnd)) { + return USB_ERROR; + } + + if (!(DescPtrs->fpEDRepeat->dControl & ED_SKIP_TDQ)) { + // + // Rebind the TD to its parent ED + // + DescPtrs->fpEDRepeat->fpHeadPointer = (UINT32)(UINTN)DescPtrs->fpTDRepeat; + + // + // Clear the link pointer. It may point to some other TD + // + DescPtrs->fpTDRepeat->fpLinkPointer = OHCI_TERMINATE; + + // + // Reactivate the TD + // + DescPtrs->fpTDRepeat->dControlStatus = DescPtrs->fpTDRepeat->dCSReloadValue; + DescPtrs->fpTDRepeat->bActiveFlag = TRUE; + } + + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// FUNCTION: OHCI_DisableInterrupts +// +// DESCRIPTION: This API function is called to disable the interrupts +// generated by the OHCI host controller. The input to the +// routine is the pointer to the HC structure that defines this +// host controller. This routine will stop the HC to avoid +// further interrupts. +// +// PARAMETERS: fpHCStruc Ptr to the host controller structure +// +// RETURN: USB_SUCCESS or USB_ERROR +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +OHCI_DisableInterrupts (HC_STRUC* fpHCStruc) +{ + EFI_STATUS EfiStatus; + + EfiStatus = UsbHcStrucValidation(fpHCStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + // + // Disable interrupt generation (global) bit (Set bit31) + // + DwordWriteMem((UINT32)fpHCStruc->BaseAddress, OHCI_INTERRUPT_DISABLE, MASTER_INTERRUPT_ENABLE); + // + // Disable periodic, isochronous, control and bulk list processing, reset bits 2 to 5 + // + DwordResetMem((UINT32)fpHCStruc->BaseAddress, OHCI_CONTROL_REG, BIT2 + BIT3 + BIT4 + BIT5); + + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// FUNCTION: OHCI_EnableInterrupts +// +// DESCRIPTION: This function enables the HC interrupts +// +// PARAMETERS: fpHCStruc Pointer to the HCStruc structure +// +// RETURN: USB_SUCCESS or USB_ERROR +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +OHCI_EnableInterrupts (HC_STRUC* fpHCStruc) +{ + EFI_STATUS EfiStatus; + + EfiStatus = UsbHcStrucValidation(fpHCStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + // + // Enable periodic, control and bulk list processing + // Set bit 2, 4 & 5 + // + DwordSetMem((UINT32)fpHCStruc->BaseAddress, OHCI_CONTROL_REG, BIT2 + BIT4 + BIT5); + // + // Enable interrupt generation (global) bit + // + DwordWriteMem((UINT32)fpHCStruc->BaseAddress, OHCI_INTERRUPT_ENABLE, MASTER_INTERRUPT_ENABLE); + + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// FUNCTION: OHCI_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 call +// back functions +// +// PARAMETERS: fpHCStruc Pointer to the HCStruc structure +// +// RETURN: USB_ERROR - Interrupt not processed +// USB_SUCCESS - Interrupt processed +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +OHCI_ProcessInterrupt(HC_STRUC* fpHCStruc) +{ + OHCI_TD *fpTD, *fpTD1; + UINT8 bIntProcessFlag = USB_ERROR; // Set as interrupt not processed + EFI_STATUS EfiStatus; + + EfiStatus = UsbHcStrucValidation(fpHCStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + // Make sure MEMIO & Bus mastering are enabled + if (((UINT8)ReadPCIConfig(fpHCStruc->wBusDevFuncNum, USB_REG_COMMAND) & 0x6) != 0x6) { + return bIntProcessFlag; + } + + if ((ReadPCIConfig(fpHCStruc->wBusDevFuncNum, USB_MEM_BASE_ADDRESS) & ~(0x7F)) != + (UINT32)fpHCStruc->BaseAddress) { + return bIntProcessFlag; + } + // + // Check the interrupt status register for an ownership change. If this bit + // is set, it means that the O/S USB device driver is attempting to takeover + // control of the host controller. In this case the host controller is + // shut down and the interrupt routing bit in the control register is cleared + // (this disables SMI generation and enebles standard IRQ generation from + // the USB host controller. + // + if (DwordReadMem((UINT32)fpHCStruc->BaseAddress, OHCI_INTERRUPT_STATUS) & OWNERSHIP_CHANGE) { + DwordWriteMem((UINT32)fpHCStruc->BaseAddress, OHCI_INTERRUPT_STATUS, OWNERSHIP_CHANGE); + if (DwordReadMem((UINT32)fpHCStruc->BaseAddress, OHCI_HCCA_REG) == (UINT32)(UINTN)fpHCStruc->fpFrameList) { + // + // OS tries to take the control over HC + // + gUsbData->dUSBStateFlag &= (~USB_FLAG_ENABLE_BEEP_MESSAGE); + + OHCI_StopUnsupportedHC(fpHCStruc); + + OHCI_Stop(fpHCStruc); + return USB_SUCCESS; // Set interrupt as processed + } else { // Ownership comes back to the driver - reinit + gUsbData->bHandOverInProgress = FALSE; + gUsbData->dUSBStateFlag |= (USB_FLAG_ENABLE_BEEP_MESSAGE); + OHCI_Start(fpHCStruc); + return USB_SUCCESS; // Set interrupt as processed + } + } // ownership change + + if (!(fpHCStruc->dHCFlag & HC_STATE_RUNNING)) return USB_ERROR; + + if (OhciIsHalted(fpHCStruc)) { + // Clear All bits of the interrupt status + DwordWriteMem((UINT32)fpHCStruc->BaseAddress, OHCI_INTERRUPT_STATUS, + DwordReadMem((UINT32)fpHCStruc->BaseAddress, OHCI_INTERRUPT_STATUS)); + return bIntProcessFlag; + } + // + // Check whether the controller is still under BIOS control + // Read the base address of the Periodic Frame List to the OHCI HCCA + // register and compare with stored value + // + if ((DwordReadMem((UINT32)fpHCStruc->BaseAddress, OHCI_HCCA_REG) & 0xFFFFFF00) != + (UINT32)(UINTN)fpHCStruc->fpFrameList) { + return bIntProcessFlag; + } + // + // Check the interrupt status register for a root hub status change. If + // this bit is set, then a device has been attached or removed from one of + // the ports on the root hub. + // + if (DwordReadMem((UINT32)fpHCStruc->BaseAddress, OHCI_INTERRUPT_STATUS) & RH_STATUS_CHANGE) { + // + // Stop the periodic list processing to avoid more interrupts from HC + // + DwordResetMem((UINT32)fpHCStruc->BaseAddress, OHCI_CONTROL_REG, PERIODIC_LIST_ENABLE); +// USB_DEBUG(3, "before OHCI_ProcessRootHubStatusChange\n"); + // Handle root hub change + bIntProcessFlag = (UINT8)OHCI_ProcessRootHubStatusChange(fpHCStruc); +// USB_DEBUG(3, "after OHCI_ProcessRootHubStatusChange\n"); + // + // Re-enable the periodic list processing + // + DwordSetMem((UINT32)fpHCStruc->BaseAddress, OHCI_CONTROL_REG, PERIODIC_LIST_ENABLE); + } + + // + // Check the interrupt status register for a one or more TDs completing. + // + if (!(DwordReadMem((UINT32)fpHCStruc->BaseAddress, OHCI_INTERRUPT_STATUS) & WRITEBACK_DONEHEAD)) { + return USB_SUCCESS; + } + bIntProcessFlag = USB_SUCCESS; // Set interrupt as processed + + // + // The memory dword at HCCADONEHEAD has been updated to contain the head + // pointer of the linked list of TDs that have completed. Walk through + // this list processing TDs as we go. + // + for (;;) { + fpTD = (OHCI_TD*)(UINTN)(((OHCI_HCCA_PTRS*)fpHCStruc->fpFrameList)->dHccaDoneHead); +#if USB_RUNTIME_DRIVER_IN_SMM + EfiStatus = AmiValidateMemoryBuffer((VOID*)fpTD, sizeof(OHCI_TD)); + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } +#endif + ((OHCI_HCCA_PTRS*)fpHCStruc->fpFrameList)->dHccaDoneHead = 0; + + // + // Clear the WRITEBACK_DONEHEAD bit of the interrupt status register + // in the host controller + // + DwordWriteMem((UINT32)fpHCStruc->BaseAddress, OHCI_INTERRUPT_STATUS, WRITEBACK_DONEHEAD); + + if (!fpTD) break; // no TDs in the list + + do { + fpTD = (OHCI_TD*)((UINTN)fpTD & 0xfffffff0); +#if USB_RUNTIME_DRIVER_IN_SMM + EfiStatus = AmiValidateMemoryBuffer((VOID*)fpTD, sizeof(OHCI_TD)); + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } +#endif + fpTD1 = (OHCI_TD*)fpTD->fpLinkPointer; + OHCI_ProcessTD(fpHCStruc, fpTD); + // Host controllers might change NextTD pointer to Td, then it causes + // infinite loop in this routing. Break this loop if NextTd is the same as Td. + if (fpTD == fpTD1) { + break; + } + fpTD = fpTD1; + } while (fpTD); + } // Check if any TDs completed while processing + + return bIntProcessFlag; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// FUNCTION: OHCI_GetRootHubStatus +// +// DESCRIPTION: This function returns the port connect status for the +// root hub port +// +// PARAMETERS: pHCStruc Pointer to HCStruc of the host controller +// bPortNum Port in the HC whose status is requested +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +OHCI_GetRootHubStatus( + HC_STRUC* fpHCStruc, + UINT8 bPortNum, + BOOLEAN ClearChangeBits +) +{ + UINT8 bRHStatus = USB_PORT_STAT_DEV_OWNER; + UINT32 dPortStatus; + UINT16 wPortReg = ((UINT16)bPortNum << 2) + (OHCI_RH_PORT1_STATUS - 4); + EFI_STATUS EfiStatus; + + EfiStatus = UsbHcStrucValidation(fpHCStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + dPortStatus = DwordReadMem((UINT32)fpHCStruc->BaseAddress, wPortReg); + USB_DEBUG(3, "Ohci port[%d] status: %08x\n", bPortNum, dPortStatus); + + if (dPortStatus & CURRENT_CONNECT_STATUS) { + bRHStatus |= USB_PORT_STAT_DEV_CONNECTED; + if (dPortStatus & PORT_ENABLE_STATUS) { + bRHStatus |= USB_PORT_STAT_DEV_ENABLED; + } + } + + bRHStatus |= USB_PORT_STAT_DEV_FULLSPEED; // Assume full speed and set the flag + if (dPortStatus & LOW_SPEED_DEVICE_ATTACHED) { + bRHStatus &= ~USB_PORT_STAT_DEV_FULLSPEED; // Reset full speed + bRHStatus |= USB_PORT_STAT_DEV_LOWSPEED; // Set low speed flag + } + + if (dPortStatus & CONNECT_STATUS_CHANGE) { + if (ClearChangeBits == TRUE) + DwordWriteMem((UINT32)fpHCStruc->BaseAddress, wPortReg, CONNECT_STATUS_CHANGE); //(EIP66448+) + bRHStatus |= USB_PORT_STAT_DEV_CONNECT_CHANGED; // Set connect status change flag + } + //(EIP66448+)> + if (dPortStatus & PORT_ENABLE_STATUS_CHANGE) { + if (ClearChangeBits == TRUE) { + DwordWriteMem((UINT32)fpHCStruc->BaseAddress, wPortReg, PORT_ENABLE_STATUS_CHANGE); + } + } + //<(EIP66448+) + return bRHStatus; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// FUNCTION: OHCI_DisableRootHub +// +// DESCRIPTION: This function disables the specified root hub port. +// +// PARAMETERS: fpHCStruc Pointer to HCStruc of the host controller +// bPortNum Port in the HC to be disabled. +// +// RETURN: USB_SUCCESS or USB_ERROR +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +OHCI_DisableRootHub (HC_STRUC* fpHCStruc, UINT8 bPortNum) +{ + UINT32 dPortReg = ((UINT32)bPortNum << 2) + (OHCI_RH_PORT1_STATUS - 4); + EFI_STATUS EfiStatus; + + EfiStatus = UsbHcStrucValidation(fpHCStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + DwordWriteMem((UINT32)fpHCStruc->BaseAddress, (UINT16)dPortReg, CLEAR_PORT_ENABLE); + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// FUNCTION: OHCI_EnableRootHub +// +// DESCRIPTION: This function enables the specified root hub port. +// +// PARAMETERS: fpHCStruc Pointer to HCStruc of the host controller +// bPortNum Port in the HC to be enabled. +// +// RETURN: USB_SUCCESS or USB_ERROR +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +OHCI_EnableRootHub (HC_STRUC* fpHCStruc,UINT8 bPortNum) +{ + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// FUNCTION: OHCI_ResetRootHub +// +// DESCRIPTION: This function resets the specified root hub port. +// +// PARAMETERS: HcStruc Pointer to HCStruc of the host controller +// PortNum Port in the HC to be disabled. +// +// RETURN: USB_SUCCESS or USB_ERROR +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +OHCI_ResetRootHub (HC_STRUC* HcStruc, UINT8 PortNum) +{ + UINT32 BaseAddr = (UINT32)HcStruc->BaseAddress; + UINT16 PortReg = ((UINT16)PortNum << 2) + (OHCI_RH_PORT1_STATUS - 4); + UINT32 i; + EFI_STATUS EfiStatus; + + EfiStatus = UsbHcStrucValidation(HcStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + DwordWriteMem(BaseAddr, PortReg, SET_PORT_RESET); // Reset the port + + // The reset signaling must be driven for a minimum of 10ms + FixedDelay(10 * 1000); + + // + // Wait for reset to complete + // + for (i = 0; i < 500; i++) { + if (DwordReadMem(BaseAddr, PortReg) & PORT_RESET_STATUS_CHANGE) { + break; + } + FixedDelay(100); // 100 us delay + } + + if (!(DwordReadMem(BaseAddr, PortReg) & PORT_RESET_STATUS_CHANGE)) { + USB_DEBUG(3, "OHCI: port reset timeout, status: %08x\n", + DwordReadMem(BaseAddr, PortReg)); + return USB_ERROR; + } + + // + // Clear the reset status change status + // + DwordWriteMem(BaseAddr, PortReg, PORT_RESET_STATUS_CHANGE); + + // Some devices need a delay here + FixedDelay(3 * 1000); // 3 ms delay + + return USB_SUCCESS; +} + + //(EIP54018+)> +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Name: OHCI_GlobalSuspend +// +// Description: +// This function suspend the OHCI HC. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +OHCI_GlobalSuspend( + HC_STRUC* HcStruc +) +{ + EFI_STATUS EfiStatus; + + EfiStatus = UsbHcStrucValidation(HcStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + if (!(HcStruc->dHCFlag & HC_STATE_RUNNING)) { + return USB_ERROR; + } + + if (OhciIsHalted(HcStruc)) { + return USB_ERROR; + } + + DwordWriteMem((UINT32)HcStruc->BaseAddress, OHCI_INTERRUPT_ENABLE, + RESUME_DETECTED_ENABLE); + FixedDelay(40 * 1000); + DwordWriteMem((UINT32)HcStruc->BaseAddress, OHCI_CONTROL_REG, + USBSUSPEND | REMOTE_WAKEUP_ENABLE); + FixedDelay(20 * 1000); + + HcStruc->dHCFlag &= ~(HC_STATE_RUNNING); + HcStruc->dHCFlag |= HC_STATE_SUSPEND; + + return USB_SUCCESS; +} + //<(EIP54018+) + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// FUNCTION: OHCI_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.) +// +// PARAMETERS: 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 +// +// +// RETURN: Number of bytes transferred +// +// +// NOTES: Do not use USB_SUCCESS or USB_ERROR as returned values +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT16 +OHCI_ControlTransfer ( + HC_STRUC* fpHCStruc, + DEV_INFO* fpDevInfo, + UINT16 wRequest, + UINT16 wIndex, + UINT16 wValue, + UINT8 *fpBuffer, + UINT16 wLength) +{ + UINT16 *fpData; + OHCI_DESC_PTRS *fpDescPtrs = fpHCStruc->stDescPtrs.fpOHCIDescPtrs; + OHCI_ED *fpED; + OHCI_TD *fpTD; + UINT32 dData; + UINT16 wData; + UINT8 CompletionCode; + UINT32 TransferLength; + UINT8 *MemBlockEnd = gUsbData->fpMemBlockStart + (gUsbData->MemPages << 12); + 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, "Ohci ControlTransfer Invalid Pointer, Buffer is in SMRAM.\n"); + return 0; + } + } + gCheckUsbApiParameter = FALSE; + } +#endif + + if (!(fpHCStruc->dHCFlag & HC_STATE_RUNNING)) { + return 0; + } + + if (OhciIsHalted(fpHCStruc)) { + return 0; + } + //FixedDelay(5 * 1000); // 5 ms delay is necessary for OHCI host controllers + + if( !VALID_DEVINFO( fpDevInfo) ) + return 0; + if (((UINT8*)fpDescPtrs < gUsbData->fpMemBlockStart) || + ((UINT8*)(fpDescPtrs + sizeof(OHCI_DESC_PTRS)) > MemBlockEnd)) { + return 0; + } + if (((UINT8*)fpDescPtrs->fpEDControl < gUsbData->fpMemBlockStart) || + ((UINT8*)(fpDescPtrs->fpEDControl + sizeof(OHCI_ED)) > MemBlockEnd)) { + return 0; + } + if (((UINT8*)fpDescPtrs->fpTDControlSetup < gUsbData->fpMemBlockStart) || + ((UINT8*)(fpDescPtrs->fpTDControlSetup + sizeof(OHCI_TD)) > MemBlockEnd)) { + return 0; + } + if (((UINT8*)fpDescPtrs->fpTDControlData < gUsbData->fpMemBlockStart) || + ((UINT8*)(fpDescPtrs->fpTDControlData + sizeof(OHCI_TD)) > MemBlockEnd)) { + return 0; + } + if (((UINT8*)fpDescPtrs->fpTDControlStatus < gUsbData->fpMemBlockStart) || + ((UINT8*)(fpDescPtrs->fpTDControlStatus + sizeof(OHCI_TD)) > MemBlockEnd)) { + return 0; + } + gUsbData->dLastCommandStatusExtended = 0; + + // + // Build the device request in the data area of the control setup qTD + // + fpData = (UINT16*)fpDescPtrs->fpTDControlSetup->aSetupData; + *fpData++ = wRequest; + *fpData++ = wValue; + *fpData++ = wIndex; + *fpData++ = wLength; + *(UINTN*)fpData = (UINTN)fpBuffer; + // + // Prepare some registers that will be used in building the TDs below. + // wLength contains the data length. + // fpBuffer contains the absolute address of the data buffer. + // wRequest contains the request type (bit 7 = 0/1 for Out/In). + // fpDevInfo will contain a pointer to the DeviceInfo structure for the given device. + // + // Ready the EDControl for the control transfer. + // + fpED = fpDescPtrs->fpEDControl; + // + // The ED control field will be set so + // Function address & Endpoint number = ESI, + // Direction = From TD, + // Speed = DeviceInfo.bEndpointSpeed, + // Skip = 1, Format = 0, + // Max packet size = DeviceInfo.wEndp0MaxPacket + // The HeadPointer field will be set to TDControlSetup + // The TailPointer field will be set to OHCI_TERMINATE + // The LinkPointer field will be set to OHCI_TERMINATE + // + dData = (UINT32)fpDevInfo->wEndp0MaxPacket; + if (dData > 0x40) dData = 0x40; // Force the max packet size to 64 bytes + dData <<= 16; // dData[26:16] = device's packet size + wData = (UINT16)fpDevInfo->bEndpointSpeed; // 00/01/10 for HI/LO/FULL + wData = (wData & 1) << 13; // wData[13] = full/low speed flag + wData |= fpDevInfo->bDeviceAddress | ED_SKIP_TDQ; + fpED->dControl = dData | wData; + fpED->fpTailPointer = 0; + fpED->fpEDLinkPointer = 0; + + fpTD = fpDescPtrs->fpTDControlSetup; + // + // The ControlStatus field will be set so + // Buffer Rounding = 1, + // Direction PID = GTD_SETUP_PACKET, + // Delay Interrupt = GTD_IntD, + // Data Toggle = GTD_SETUP_TOGGLE, + // Error Count = GTD_NO_ERRORS, + // Condition Code = GTD_NOT_ACCESSED + // The CurrentBufferPointer field will point to the TD's SetupData buffer + // which was before initialized to contain a DeviceRequest struc. + // The BufferEnd field will point to the last byte of the TD's SetupData + // buffer. + // The LinkPointer field will point to the TDControlData if data will + // be sent/received or to the TDControlStatus if no data is expected. + // The CSReloadValue field will contain 0 because this is a "one shot" packet. + // The pCallback will be set to point to the OHCI_ControlTDCallback routine. + // The ActiveFlag field will be set to TRUE. + // The DeviceAddress field does not need to be set since the Control TDs do + // not need rebinding to the EDControl. + // + fpTD->dControlStatus = (UINT32)(GTD_BUFFER_ROUNDING | GTD_SETUP_PACKET | GTD_SETUP_TOGGLE | + GTD_NO_ERRORS | (GTD_NOT_ACCESSED << 28)); + + fpTD->fpCurrentBufferPointer = (UINT32)(UINTN)fpTD->aSetupData; + fpTD->fpBufferEnd = (UINT32)(UINTN)fpTD->aSetupData + 7; // size of aSetupData - 1 + + wData = wLength ; //(EIP67230) + + if (wLength) { // some data to transfer + fpTD = fpDescPtrs->fpTDControlData; // Fill in various fields in the TDControlData. + // + // The ControlStatus field will be set so + // Buffer Rounding = 1, + // Direction PID = GTD_OUT_PACKET/GTD_IN_PACKET, + // Delay Interrupt = GTD_IntD, + // Data Toggle = GTD_DATA1_TOGGLE, + // Error Count = GTD_NO_ERRORS, + // Condition Code = GTD_NOT_ACCESSED + // The CurrentBufferPointer field will point to the caller's buffer + // which is now in EBP. + // The BufferEnd field will point to the last byte of the caller's buffer. + // The LinkPointer field will point to the TDControlStatus. + // The CSReloadValue field will contain 0 because this is a "one shot" packet. + // The pCallback will be set to point to the OHCI_ControlTDCallback routine. + // The ActiveFlag field will be set to TRUE. + // The DeviceAddress field does not need to be set since the Control TDs do + // not need rebinding to the EDControl. + // The CSReloadValue field will contain 0 because this is a "one shot" packet. + // The pCallback will be set to point to the OHCI_ControlTDCallback routine. + // The ActiveFlag field will be set to TRUE. return USB_SUCCESS; + // The DeviceAddress field does not need to be set since the Control TDs do} + // not need rebinding to the EDControl. + // + dData = (UINT32)(GTD_BUFFER_ROUNDING | GTD_DATA1_TOGGLE | GTD_NO_ERRORS | (GTD_NOT_ACCESSED << 28)); + dData = (wRequest & BIT7)? (dData | GTD_IN_PACKET | GTD_IntD) : (dData | GTD_OUT_PACKET); + fpTD->dControlStatus = dData; + fpTD->fpCurrentBufferPointer = (UINT32)(UINTN)fpBuffer; + fpTD->fpBufferEnd = (UINT32)((UINTN)fpBuffer + wData - 1); + } + fpTD = fpDescPtrs->fpTDControlStatus; // Fill in various fields in the TDControlStatus. + // + // The ControlStaus field will be set so + // Buffer Rounding = 1, + // Direction PID = GTD_OUT_PACKET/GTD_IN_PACKET, + // Delay Interrupt = GTD_IntD, + // Data Toggle = GTD_DATA1_TOGGLE, + // Error Count = GTD_NO_ERRORS, + // Condition Code = GTD_NOT_ACCESSED + // The CurrentBufferPointer field will point to NULL + // The BufferEnd field will point to NULL. + // The LinkPointer field will point to OHCI_TERMINATE. + // The CSReloadValue field will contain 0 because this is a "one shot" packet. + // The pCallback will be set to point to the OHCI_ControlTdCallback routine. + // The ActiveFlag field will be set to TRUE. + // The DeviceAddress field does not need to be set since the Control TDs do + // not need rebinding to the EdControl. + // + // Note: For OUT control transfer status should be IN and + // for IN cotrol transfer, status should be OUT. + // + dData = (UINT32)(GTD_BUFFER_ROUNDING | GTD_DATA1_TOGGLE | GTD_NO_ERRORS | (GTD_NOT_ACCESSED << 28)); + dData = (wRequest & BIT7)? (dData | GTD_OUT_PACKET) : (dData | GTD_IN_PACKET | GTD_IntD); + fpTD->dControlStatus = dData; + fpTD->fpCurrentBufferPointer = 0; + fpTD->fpBufferEnd = 0; + fpTD->fpLinkPointer = 0; + // + // Link all the pointers together + // + fpTD = fpDescPtrs->fpTDControlSetup; + fpED->fpHeadPointer = (UINT32)(UINTN)fpTD; + if (wLength) { // chain in data TD + fpTD->fpLinkPointer = (UINT32)(UINTN)fpDescPtrs->fpTDControlData; + fpTD = fpDescPtrs->fpTDControlData; + } + fpTD->fpLinkPointer = (UINT32)(UINTN)fpDescPtrs->fpTDControlStatus; + + fpDescPtrs->fpTDControlStatus->fpLinkPointer = 0; + + fpTD = fpDescPtrs->fpTDControlSetup; + do { + fpTD->dCSReloadValue = 0; + fpTD->bCallBackIndex = USB_InstallCallBackFunction(OHCI_ControlTDCallback); + fpTD->bActiveFlag = TRUE; + fpTD = (OHCI_TD*)fpTD->fpLinkPointer; + } while (fpTD); + // + // Now control queue is complete, so set ED_SKIP_TDQ=0 + // + fpED->dControl &= ~ED_SKIP_TDQ; + // + // Set the HcControlHeadED register to point to the EDControl. + // + DwordWriteMem((UINT32)fpHCStruc->BaseAddress, OHCI_CONTROL_HEAD_ED, (UINT32)(UINTN)fpED); + // + // Now put the control setup, data and status into the HC's schedule by + // setting the ControllListFilled field of HcCommandStatus reg. + // This will cause the HC to execute the transaction in the next active frame. + // + DwordWriteMem((UINT32)fpHCStruc->BaseAddress, OHCI_COMMAND_STATUS, CONTROL_LIST_FILLED); + // + // Now wait for the control status TD to complete. When it has completed, + // the OHCI_ControlTDCallback will set its active flag to FALSE. + // + OHCIWaitForTransferComplete(fpHCStruc, fpED, fpDescPtrs->fpTDControlStatus,fpDevInfo); + // + // Stop the HC from processing the EDControl by setting its Skip bit. + // + fpED->dControl |= ED_SKIP_TDQ; + + // + // Finally check for any error bits set in both the TDControlStatus. + // If the TD did not complete successfully, return STC. + // + CompletionCode = (UINT8)(fpDescPtrs->fpTDControlStatus->dControlStatus >> 28); // dData[3:0] = Completion status + gUsbData->bLastCommandStatus &= ~USB_CONTROL_STALLED; + + fpTD = fpDescPtrs->fpTDControlData; + TransferLength = wLength ; + if(fpTD->fpCurrentBufferPointer != 0){ + TransferLength = fpTD->fpCurrentBufferPointer - (UINT32)(UINTN)fpBuffer; + } + + + wData = 0; + switch (CompletionCode) { + case GTD_NO_ERROR: + wData = TransferLength; + break; + case GTD_STALL: + gUsbData->bLastCommandStatus |= USB_CONTROL_STALLED; + gUsbData->dLastCommandStatusExtended |= USB_TRSFR_STALLED; + break; + case GTD_NOT_ACCESSED: + gUsbData->dLastCommandStatusExtended |= USB_TRNSFR_TIMEOUT; + break; + default: + break; + } + + return wData; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// FUNCTION: OHCI_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.) +// Size of data can be upto 64K +// +// PARAMETERS: pHCStruc Pointer to HCStruc of the host controller +// pDevInfo DeviceInfo structure (if available else 0) +// bXferDir Transfer direction +// Bit 7: Data direction +// 0 Host sending data to device +// 1 Device sending data to host +// Bit 6-0 : Reserved +// fpBuffer Buffer containing data to be sent to the +// device or buffer to be used to receive data +// value in Segment:Offset format +// dwLength dwLength request parameter, number of bytes +// of data to be transferred in or out +// of the host controller +// +// RETURN: Amount of data transferred +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT32 +OHCI_BulkTransfer ( + HC_STRUC *fpHCStruc, + DEV_INFO *fpDevInfo, + UINT8 bXferDir, + UINT8 *fpBuffer, + UINT32 dwLength) +{ + UINT32 dData; + UINT8 bData; + OHCI_DESC_PTRS *fpDescPtrs; + UINT16 wMaxPkt; + UINT8 bEndp; + UINT8 bDatToggle; + UINT32 dBytesToTransfer, dBytesRemaining; + UINT32 dBytesTransferred; + UINT32 Buffer; + UINT8 *MemBlockEnd = gUsbData->fpMemBlockStart + (gUsbData->MemPages << 12); + 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, dwLength); + if (EFI_ERROR(EfiStatus)) { + USB_DEBUG(3, "Ohci BulkTransfer Invalid Pointer, Buffer is in SMRAM.\n"); + return 0; + } + gCheckUsbApiParameter = FALSE; + } +#endif + + if (!(fpHCStruc->dHCFlag & HC_STATE_RUNNING)) { + return 0; + } + + if (OhciIsHalted(fpHCStruc)) { + return 0; + } + + if( !VALID_DEVINFO( fpDevInfo) ) + return 0; + + gUsbData->dLastCommandStatusExtended = 0; + + fpDescPtrs = fpHCStruc->stDescPtrs.fpOHCIDescPtrs; + + if (((UINT8*)fpDescPtrs < gUsbData->fpMemBlockStart) || + ((UINT8*)(fpDescPtrs + sizeof(OHCI_DESC_PTRS)) > MemBlockEnd)) { + return 0; + } + + if (((UINT8*)fpDescPtrs->fpEDBulk < gUsbData->fpMemBlockStart) || + ((UINT8*)(fpDescPtrs->fpEDBulk + sizeof(OHCI_ED)) > MemBlockEnd)) { + return 0; + } + + if (((UINT8*)fpDescPtrs->fpTDBulkData < gUsbData->fpMemBlockStart) || + ((UINT8*)(fpDescPtrs->fpTDBulkData + sizeof(OHCI_TD)) > MemBlockEnd)) { + return 0; + } + + wMaxPkt = (bXferDir & 0x80)? fpDevInfo->wBulkInMaxPkt : fpDevInfo->wBulkOutMaxPkt; + bEndp = (bXferDir & 0x80)? fpDevInfo->bBulkInEndpoint : fpDevInfo->bBulkOutEndpoint; + bDatToggle = UsbGetDataToggle(fpDevInfo, bEndp | bXferDir); + + if( wMaxPkt == 0){ + return 0; + } + + dBytesRemaining = dwLength; + dBytesTransferred = 0; + dBytesToTransfer = 0; + + for (;dBytesRemaining != 0; dBytesRemaining -= dBytesToTransfer) { + dBytesToTransfer = + (dBytesRemaining < FULLSPEED_MAX_BULK_DATA_SIZE_PER_FRAME)? + dBytesRemaining : FULLSPEED_MAX_BULK_DATA_SIZE_PER_FRAME; + + Buffer = (UINT32)(UINTN)fpBuffer + dBytesTransferred; + + // + // Set the SKIP bit in the EdBulk to avoid accidental scheduling + // + fpDescPtrs->fpEDBulk->dControl = ED_SKIP_TDQ; + // + // Set the ED's head pointer field to bulk data TD and tail pointer field to + // OHCI_TERMINATE. Also set ED's link pointer to OHCI_TERMINATE. + // + fpDescPtrs->fpEDBulk->fpHeadPointer = (UINT32)(UINTN)fpDescPtrs->fpTDBulkData; + fpDescPtrs->fpEDBulk->fpTailPointer = OHCI_TERMINATE; + fpDescPtrs->fpEDBulk->fpEDLinkPointer = OHCI_TERMINATE; + // + // Form the data needed for ED's control field with the available information + // + dData = (bXferDir & 0x80)? ED_IN_PACKET : ED_OUT_PACKET; + dData |= fpDevInfo->bDeviceAddress; + dData |= (UINT16)bEndp << 7; + dData |= (UINT32)wMaxPkt << 16; + // + // Update the ED's control field with the data formed + // ASSUME ALL MASS DEVICES ARE FULL SPEED DEVICES. + // + fpDescPtrs->fpEDBulk->dControl = dData; + // + // Fill the general bulk data TD with relevant information. Set the + // TD's control field with buffer rounding set to 1, direction PID to + // don't care, delay interrupt to INTD, data toggle to the latest data + // toggle value, error count to no errors and condition code to not accessed. + // + // Set the data toggle to DATA0 (SETUP_TOGGLE) + fpDescPtrs->fpTDBulkData->dControlStatus = (UINT32)(GTD_BUFFER_ROUNDING | GTD_IN_PACKET | + GTD_IntD | GTD_SETUP_TOGGLE | GTD_NO_ERRORS | (GTD_NOT_ACCESSED << 28)); + fpDescPtrs->fpTDBulkData->dControlStatus |= (UINT32)bDatToggle << 24; + // + // GTD current buffer pointer field will point to the caller's buffer which + // now in the variable fpBuffer + // + fpDescPtrs->fpTDBulkData->fpCurrentBufferPointer = Buffer; + fpDescPtrs->fpTDBulkData->fpBufferEnd = Buffer + dBytesToTransfer - 1; + fpDescPtrs->fpTDBulkData->fpLinkPointer = OHCI_TERMINATE; + // + // GTD's CSReloadValue field will contain 0 because this is a "one shot" packet + // + fpDescPtrs->fpTDBulkData->dCSReloadValue = 0; + fpDescPtrs->fpTDBulkData->bCallBackIndex = USB_InstallCallBackFunction(OHCI_GeneralTDCallback); + fpDescPtrs->fpTDBulkData->bActiveFlag = TRUE; + + fpDescPtrs->fpEDBulk->dControl &= ~ED_SKIP_TDQ; + // + // Set the HCBulkHeadED register to point to the bulk ED + // + DwordWriteMem((UINT32)fpHCStruc->BaseAddress, OHCI_BULK_HEAD_ED, (UINT32)(UINTN)fpDescPtrs->fpEDBulk); + // + // Clear bulk stall/time out condition flag + // + gUsbData->bLastCommandStatus &= ~(USB_BULK_STALLED + USB_BULK_TIMEDOUT); + // + // Enable the bulk list processing + // + DwordWriteMem((UINT32)fpHCStruc->BaseAddress, OHCI_COMMAND_STATUS, BULK_LIST_FILLED); + + OHCIWaitForTransferComplete(fpHCStruc, fpDescPtrs->fpEDBulk, fpDescPtrs->fpTDBulkData,fpDevInfo); + // + // Stop the HC from processing the EDBulk by setting its Skip bit. + // + fpDescPtrs->fpEDBulk->dControl |= ED_SKIP_TDQ; + // + // Update the data toggle value into the mass info structure + // + UsbUpdateDataToggle(fpDevInfo, bEndp | bXferDir, + (UINT8)(((fpDescPtrs->fpTDBulkData->dControlStatus & GTD_DATA_TOGGLE) >> 24) & 1)); + // + // Check for the error conditions - if possible recover from them + // + bData = (UINT8)(fpDescPtrs->fpTDBulkData->dControlStatus >> 28); + switch (bData) { + case GTD_STALL: + gUsbData->bLastCommandStatus |= USB_BULK_STALLED; + gUsbData->dLastCommandStatusExtended |= USB_TRSFR_STALLED; + break; + case GTD_NOT_ACCESSED: + gUsbData->bLastCommandStatus |= USB_BULK_TIMEDOUT; + gUsbData->dLastCommandStatusExtended |= USB_TRNSFR_TIMEOUT; + break; + default: + break; + } + + if (bData != GTD_NO_ERROR) { + break; + } + + // + // Get the size of data transferred + // + dData = fpDescPtrs->fpTDBulkData->fpCurrentBufferPointer; + if (dData != 0) + { + // + // Device sent less data than requested, calculate the + // transferred size and exit + // + //dBytesTransferred += (UINT32)(UINTN)fpDescPtrs->fpTDBulkData->fpBufferEnd - dData; //(EIP55025-) + dBytesTransferred += dData - Buffer; //Short Packet (OHCI Spec 4.3.1.3.5 Transfer Completion, Pg.23) //<(EIP55025)+ + break; + } + + // + // CurrentBufferPointer equals 0. This indicates the successfull TD completion, + // all data is transferred. Adjust the total amount and continue. + // + dBytesTransferred += dBytesToTransfer; + } + + return dBytesTransferred; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// FUNCTION: OHCI_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.) +// +// PARAMETERS: 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 in +// +// RETURN: 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 +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT16 +OHCI_InterruptTransfer ( + HC_STRUC *fpHCStruc, + DEV_INFO *fpDevInfo, + UINT8 EndpointAddress, + UINT16 MaxPktSize, + UINT8 *fpBuffer, + UINT16 wLength) +{ + UINT8 bEndp, bDatToggle; + UINT32 dData; + OHCI_ED *IntEd; + OHCI_TD *IntTd; + UINT8 CompletionCode; + 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, "Ohci InterruptTransfer Invalid Pointer, Buffer is in SMRAM.\n"); + return 0; + } + gCheckUsbApiParameter = FALSE; + } +#endif + + if (!(fpHCStruc->dHCFlag & HC_STATE_RUNNING)) { + return 0; + } + + if (OhciIsHalted(fpHCStruc)) { + return 0; + } + + if(!VALID_DEVINFO( fpDevInfo)) { + return 0; + } + + gUsbData->dLastCommandStatusExtended = 0; + + IntEd = USB_MemAlloc(GET_MEM_BLK_COUNT(sizeof(OHCI_ED) + sizeof(OHCI_TD))); + + if (IntEd == NULL) { + return 0; + } + + IntTd = (OHCI_TD*)((UINTN)IntEd + sizeof(OHCI_ED)); + + // + // Set the SKIP bit to avoid accidental scheduling + // + IntEd->dControl = ED_SKIP_TDQ; + // + // Set the ED's head pointer field to interrupt data TD and tail pointer + // field to OHCI_TERMINATE. Also set ED's link pointer to OHCI_TERMINATE. + // + IntEd->fpHeadPointer = (UINT32)(UINTN)IntTd; + IntEd->fpTailPointer = OHCI_TERMINATE; + IntEd->fpEDLinkPointer = OHCI_TERMINATE; + IntEd->Interval = OhciTranslateInterval(fpDevInfo->bPollInterval); + + // + // Get maximum packet size from device info structure + // + bEndp = EndpointAddress & 0xF; + bDatToggle = UsbGetDataToggle(fpDevInfo, EndpointAddress); + + // + // Form the data needed for ED's control field with the available information + // + dData = (EndpointAddress & BIT7)? ED_IN_PACKET : ED_OUT_PACKET; + dData |= fpDevInfo->bDeviceAddress | ((UINT16)bEndp << 7); + dData |= ((UINT32)MaxPktSize << 16); + dData |= (UINT32)(fpDevInfo->bEndpointSpeed & 1) << 13; + // + // Update the ED's control field with the data formed + // ASSUME ALL MASS DEVICES ARE FULL SPEED DEVICES. + // + IntEd->dControl = dData; + // + // Fill the general interrupt data TD with relevant information. Set the + // TD's control field with buffer rounding set to 1, direction PID to + // don't care, delay interrupt to INTD, data toggle to the latest data + // toggle value, error count to no errors and condition code to not accessed. + // + // Set the data toggle to DATA0 (SETUP_TOGGLE) + // + dData = (UINT32)(GTD_BUFFER_ROUNDING | GTD_IN_PACKET | GTD_IntD | GTD_SETUP_TOGGLE | + GTD_NO_ERRORS | (GTD_NOT_ACCESSED << 28)); + IntTd->dControlStatus = dData; + // + // Set the data toggle depending on the bDatToggle value + // + IntTd->dControlStatus |= ((UINT32)bDatToggle << 24); + // + // GTD current buffer pointer field will point to the caller's buffer + // + IntTd->fpCurrentBufferPointer = (UINT32)(UINTN)fpBuffer; + // + // GTD's buffer end field will point to the last byte of the caller's buffer + // + IntTd->fpBufferEnd = (UINT32)(UINTN)(fpBuffer + wLength - 1); + // + // GTD's link pointer field will be set to OHCI_TERMINATE + // + IntTd->fpLinkPointer = OHCI_TERMINATE; + // + // GTD's CSReloadValue field will contain 0 because this is a "one shot" packet + // + IntTd->dCSReloadValue = 0; + // + // GTD's pCallback will point to the OHCI_GeneralTDCallback routine + // + IntTd->bCallBackIndex = USB_InstallCallBackFunction(OHCI_GeneralTDCallback); + // + // GTD's ActiveFlag field will be set to TRUE. + // + OhciAddPeriodicEd(fpHCStruc, IntEd); + + IntTd->bActiveFlag = TRUE; + IntEd->dControl &= ~ED_SKIP_TDQ; + + // + // Now wait for the interrupt data TD to complete. + // + OHCIWaitForTransferComplete(fpHCStruc, IntEd, IntTd, fpDevInfo); + // + // Stop the HC from processing the EDInterrupt by setting its Skip bit. + // + OhciRemovePeriodicEd(fpHCStruc, IntEd); + // + // Get appropriate data sync shift value + // + bDatToggle = (UINT8)((IntTd->dControlStatus & GTD_DATA_TOGGLE) >> 24) & 1; + UsbUpdateDataToggle(fpDevInfo, EndpointAddress, bDatToggle); + + // + // Check for the error conditions - if possible recover from them + // + CompletionCode = (UINT8)(IntTd->dControlStatus >> 28); + switch (CompletionCode) { + case GTD_STALL: + gUsbData->dLastCommandStatusExtended |= USB_TRSFR_STALLED; + break; + case GTD_NOT_ACCESSED: + gUsbData->dLastCommandStatusExtended |= USB_TRNSFR_TIMEOUT; + break; + default: + break; + } + + BytesTransferred = IntTd->fpCurrentBufferPointer == 0 ? wLength : + IntTd->fpCurrentBufferPointer - (UINT32)fpBuffer; + + USB_MemFree(IntEd, GET_MEM_BLK_COUNT(sizeof(OHCI_ED) + sizeof(OHCI_TD))); + + return (UINT16)BytesTransferred; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// FUNCTION: OHCI_ActivatePolling +// +// DESCRIPTION: This function activates the polling TD for the requested +// device. The device may be a USB keyboard or USB hub +// +// PARAMETERS: fpHCStruc Pointer to the HC structure +// fpDevInfo Pointer to the device information structure +// +// RETURN: 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. +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +OHCI_ActivatePolling ( + HC_STRUC* fpHCStruc, + DEV_INFO* fpDevInfo) +{ + UINT32 dData; + UINT8 *fpPtr; + UINT8 bDatToggle; + + EFI_STATUS EfiStatus; + + EfiStatus = UsbHcStrucValidation(fpHCStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + EfiStatus = UsbDevInfoValidation(fpDevInfo); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + if (!(fpHCStruc->dHCFlag & HC_STATE_RUNNING)) { + return USB_ERROR; + } + + if (OhciIsHalted(fpHCStruc)) { + return USB_ERROR; + } + + if (!VALID_DEVINFO(fpDevInfo)) { + return USB_ERROR; + } + + bDatToggle = UsbGetDataToggle(fpDevInfo, fpDevInfo->IntInEndpoint); + + fpPtr = USB_MemAlloc(1); + ASSERT(fpPtr); + fpDevInfo->fpPollEDPtr = fpPtr; + fpPtr = USB_MemAlloc(1); + ASSERT(fpPtr); + fpDevInfo->fpPollTDPtr = fpPtr; + + dData = (fpDevInfo->IntInEndpoint & BIT7)? ED_IN_PACKET : ED_OUT_PACKET; + dData |= (UINT32)fpDevInfo->bDeviceAddress | ((fpDevInfo->IntInEndpoint & 0xF) << 7); + dData |= ((UINT32)fpDevInfo->IntInMaxPkt << 16); + dData |= (UINT32)(fpDevInfo->bEndpointSpeed & 1) << 13; + dData |= ED_SKIP_TDQ; + + ((OHCI_ED*)fpDevInfo->fpPollEDPtr)->dControl = dData; + ((OHCI_ED*)fpDevInfo->fpPollEDPtr)->fpHeadPointer = (UINT32)(UINTN)fpDevInfo->fpPollTDPtr; + ((OHCI_ED*)fpDevInfo->fpPollEDPtr)->fpHeadPointer |= bDatToggle << 1; + ((OHCI_ED*)fpDevInfo->fpPollEDPtr)->fpEDLinkPointer = OHCI_TERMINATE; + ((OHCI_ED*)fpDevInfo->fpPollEDPtr)->fpTailPointer = OHCI_TERMINATE; + ((OHCI_ED*)fpDevInfo->fpPollEDPtr)->Interval = OhciTranslateInterval(fpDevInfo->bPollInterval); + + fpDevInfo->fpPollDataBuffer = USB_MemAlloc(GET_MEM_BLK_COUNT(fpDevInfo->PollingLength)); + ASSERT(fpDevInfo->fpPollDataBuffer); + + ((OHCI_TD*)fpDevInfo->fpPollTDPtr)->dControlStatus = (UINT32)(GTD_BUFFER_ROUNDING | GTD_IN_PACKET | GTD_IntD | + GTD_NO_ERRORS | (GTD_NOT_ACCESSED << 28)); + ((OHCI_TD*)fpDevInfo->fpPollTDPtr)->dCSReloadValue = (UINT32)(GTD_BUFFER_ROUNDING | GTD_IN_PACKET | GTD_IntD | + GTD_NO_ERRORS | (GTD_NOT_ACCESSED << 28)); + ((OHCI_TD*)fpDevInfo->fpPollTDPtr)->fpCurrentBufferPointer = + (UINT32)(fpDevInfo->fpPollDataBuffer); //(EIP54782) + ((OHCI_TD*)fpDevInfo->fpPollTDPtr)->fpBufferEnd = + (UINT32)(fpDevInfo->fpPollDataBuffer + fpDevInfo->PollingLength - 1); + ((OHCI_TD*)fpDevInfo->fpPollTDPtr)->fpLinkPointer = OHCI_TERMINATE; + ((OHCI_TD*)fpDevInfo->fpPollTDPtr)->bCallBackIndex = USB_InstallCallBackFunction(OHCI_PollingTDCallback); + + OhciAddPeriodicEd(fpHCStruc, (OHCI_ED*)fpDevInfo->fpPollEDPtr); + + ((OHCI_TD*)fpDevInfo->fpPollTDPtr)->bActiveFlag = TRUE; + ((OHCI_ED*)fpDevInfo->fpPollEDPtr)->dControl &= ~ED_SKIP_TDQ; + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// FUNCTION: OHCI_DeactivatePolling +// +// DESCRIPTION: This function de-activates the polling TD for the requested +// device. The device may be a USB keyboard or USB hub +// +// PARAMETERS: fpHCStruc Pointer to the HC structure +// fpDevInfo Pointer to the device information structure +// +// RETURN: USB_SUCCESS or USB_ERROR +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +OHCI_DeactivatePolling ( + HC_STRUC* fpHCStruc, + DEV_INFO* fpDevInfo) +{ + OHCI_ED *fpOHCIED = (OHCI_ED*)fpDevInfo->fpPollEDPtr; + OHCI_TD *fpOHCITD = (OHCI_TD*)fpDevInfo->fpPollTDPtr; + + EFI_STATUS EfiStatus; + + EfiStatus = UsbHcStrucValidation(fpHCStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + EfiStatus = UsbDevInfoValidation(fpDevInfo); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + if (!(fpHCStruc->dHCFlag & HC_STATE_RUNNING)) { + return USB_ERROR; + } + + if (OhciIsHalted(fpHCStruc)) { + return USB_ERROR; + } + + if(!fpOHCIED) { + return USB_SUCCESS; + } + + fpOHCITD->dControlStatus = 0; + fpOHCITD->dCSReloadValue = 0; + fpOHCITD->bActiveFlag = FALSE; + + OhciRemovePeriodicEd(fpHCStruc, fpOHCIED); + + UsbUpdateDataToggle(fpDevInfo, fpDevInfo->IntInEndpoint, + (UINT8)((fpOHCIED->fpHeadPointer & ED_TOGGLE_CARRY) >> 1)); + + USB_MemFree(fpOHCITD, GET_MEM_BLK_COUNT_STRUC(OHCI_TD)); + fpDevInfo->fpPollTDPtr = NULL; + + USB_MemFree(fpOHCIED, GET_MEM_BLK_COUNT_STRUC(OHCI_ED)); + fpDevInfo->fpPollEDPtr = NULL; + + if(fpDevInfo->fpPollDataBuffer) { + USB_MemFree(fpDevInfo->fpPollDataBuffer, + GET_MEM_BLK_COUNT(fpDevInfo->PollingLength)); + fpDevInfo->fpPollDataBuffer = 0; + } + + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// FUNCTION: OHCI_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. +// +// +// +// RETURN: USB_SUCCESS or USB_ERROR +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +OHCI_PollingTDCallback( + HC_STRUC* HcStruc, + DEV_INFO* DevInfo, + UINT8* Td, + UINT8* Buffer, + UINT16 DataLength +) +{ + UINT8 i; + UINT16 BytesTransferred; + + if (((OHCI_TD*)Td)->bActiveFlag == FALSE) { + return USB_SUCCESS; + } + + ((OHCI_TD*)Td)->bActiveFlag = FALSE; + DwordResetMem((UINT32)HcStruc->BaseAddress, OHCI_CONTROL_REG, PERIODIC_LIST_ENABLE); + + for (i = 1; i < MAX_DEVICES; i++) { + DevInfo = &gUsbData->aDevInfoTable[i]; + if (DevInfo->Flag & DEV_INFO_DEV_PRESENT) { + if (DevInfo->fpPollTDPtr == Td) { + break; + } + } + } + + if (i == MAX_DEVICES) { + return USB_ERROR; + } + + UsbUpdateDataToggle(DevInfo, DevInfo->IntInEndpoint, + (UINT8)((((OHCI_ED*)DevInfo->fpPollEDPtr)->fpHeadPointer & ED_TOGGLE_CARRY) >> 1)); + + //(EIP59707)> + if ((((OHCI_TD*)Td)->dControlStatus & GTD_STATUS_FIELD) == GTD_NO_ERROR) { + // + // Get the size of data transferred + // + if (((OHCI_TD*)Td)->fpCurrentBufferPointer != 0) { + BytesTransferred = ((OHCI_TD*)Td)->fpCurrentBufferPointer - + (UINT32)(UINTN)(DevInfo->fpPollDataBuffer); + } else { + BytesTransferred = DevInfo->PollingLength; + } + if ((DevInfo->bCallBackIndex) && (DevInfo->bCallBackIndex <= MAX_CALLBACK_FUNCTION)) { + (*gUsbData->aCallBackFunctionTable[DevInfo->bCallBackIndex-1])( + HcStruc, + DevInfo, + (UINT8*)Td, + DevInfo->fpPollDataBuffer, + BytesTransferred); + } + } + //<(EIP59707) + DwordSetMem((UINT32)HcStruc->BaseAddress, OHCI_CONTROL_REG, PERIODIC_LIST_ENABLE); + + // Clear the link pointer. It may point to some other TD + ((OHCI_TD*)Td)->fpLinkPointer = OHCI_TERMINATE; + ((OHCI_TD*)Td)->dControlStatus = ((OHCI_TD*)Td)->dCSReloadValue; + ((OHCI_TD*)Td)->fpCurrentBufferPointer = (UINT32)(UINTN)(DevInfo->fpPollDataBuffer); //(EIP54782) + ((OHCI_ED*)DevInfo->fpPollEDPtr)->fpHeadPointer &= ED_TOGGLE_CARRY; + ((OHCI_ED*)DevInfo->fpPollEDPtr)->fpHeadPointer |= (UINTN)((OHCI_TD*)Td); + ((OHCI_TD*)Td)->bActiveFlag = TRUE; + // Reset the TD's control and buffer pointer fields to their original values. + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// FUNCTION: OHCI_DisableKeyRepeat +// +// DESCRIPTION: This function disables the keyboard repeat rate logic by +// enabling the repeat TD +// +// PARAMETERS: fpHCStruc Pointer to the HCStruc structure +// +// RETURN: USB_SUCCESS or USB_ERROR +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +OHCI_DisableKeyRepeat ( + HC_STRUC *HcStruc +) +{ + OHCI_DESC_PTRS *DescPtrs; + 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 (OhciIsHalted(HcStruc)) { + return USB_ERROR; + } + + DescPtrs = HcStruc->stDescPtrs.fpOHCIDescPtrs; + + if (DescPtrs == NULL) { + return USB_ERROR; + } + + if (((UINT8*)DescPtrs < gUsbData->fpMemBlockStart) || + ((UINT8*)(DescPtrs + sizeof(OHCI_DESC_PTRS)) > MemBlockEnd)) { + return USB_ERROR; + } + + if (DescPtrs->fpEDRepeat == NULL) { + return USB_ERROR; + } + + if (((UINT8*)DescPtrs->fpEDRepeat < gUsbData->fpMemBlockStart) || + ((UINT8*)(DescPtrs->fpEDRepeat + sizeof(OHCI_ED)) > MemBlockEnd)) { + return USB_ERROR; + } + + DescPtrs->fpEDRepeat->dControl |= ED_SKIP_TDQ; // Inactive + DescPtrs->fpTDRepeat->bActiveFlag = FALSE; + + return USB_SUCCESS; + +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// FUNCTION: OHCI_EnableKeyRepeat +// +// DESCRIPTION: This function enables the keyboard repeat rate logic by +// enabling the repeat TD +// +// PARAMETERS: fpHCStruc Pointer to the HCStruc structure +// +// RETURN: USB_SUCCESS or USB_ERROR +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +OHCI_EnableKeyRepeat ( + HC_STRUC *HcStruc +) +{ + OHCI_DESC_PTRS *DescPtrs; + 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 (OhciIsHalted(HcStruc)) { + return USB_ERROR; + } + + DescPtrs = HcStruc->stDescPtrs.fpOHCIDescPtrs; + + if (DescPtrs == NULL) { + return USB_ERROR; + } + + if (((UINT8*)DescPtrs < gUsbData->fpMemBlockStart) || + ((UINT8*)(DescPtrs + sizeof(OHCI_DESC_PTRS)) > MemBlockEnd)) { + return USB_ERROR; + } + + if (DescPtrs->fpEDRepeat == NULL) { + return USB_ERROR; + } + + if (((UINT8*)DescPtrs->fpEDRepeat < gUsbData->fpMemBlockStart) || + ((UINT8*)(DescPtrs->fpEDRepeat + sizeof(OHCI_ED)) > MemBlockEnd)) { + return USB_ERROR; + } + + DescPtrs->fpTDRepeat->fpLinkPointer = OHCI_TERMINATE; + DescPtrs->fpEDRepeat->fpHeadPointer = (UINT32)(UINTN)DescPtrs->fpTDRepeat; + DescPtrs->fpTDRepeat->dControlStatus = + DescPtrs->fpTDRepeat->dCSReloadValue; + DescPtrs->fpTDRepeat->bActiveFlag = TRUE; + DescPtrs->fpEDRepeat->dControl &= (~ED_SKIP_TDQ); // Active + + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// FUNCTION: OHCI_EnumeratePorts +// +// DESCRIPTION: This API function is called to enumerate the root hub ports +// in the OHCI controller. The input to the routine is the +// pointer to the HC structure that defines this host controller +// +// PARAMETERS: fpHCStruc Ptr to the host controller structure +// +// RETURN: Status: USB_SUCCESS = Success +// USB_ERROR = Failure +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +OHCI_EnumeratePorts(HC_STRUC* fpHCStruc) +{ + UINT32 BaseAddr = (UINT32)fpHCStruc->BaseAddress; + UINT32 RhDescriptorA = 0; + UINT8 PowerOnDelay = 0; + UINT8 Index = 0; + UINT16 PortReg = OHCI_RH_PORT1_STATUS; + EFI_STATUS EfiStatus; + + EfiStatus = UsbHcStrucValidation(fpHCStruc); + + if (EFI_ERROR(EfiStatus)) { + return USB_ERROR; + } + + if (!(fpHCStruc->dHCFlag & HC_STATE_RUNNING)) { + return USB_ERROR; + } + + if (OhciIsHalted(fpHCStruc)) { + return USB_ERROR; + } + + RhDescriptorA = DwordReadMem(BaseAddr, OHCI_RH_DESCRIPTOR_A); + if (!(RhDescriptorA & NO_POWER_SWITCH)) { + if (!(RhDescriptorA & POWER_SWITCH_MODE)) { + // All ports are powered at the same time, enable global port power + DwordWriteMem(BaseAddr, OHCI_RH_STATUS, SET_GLOBAL_POWER); + } else { + // Each port is powered individually, enable individual port's power + for (Index = 0; Index < fpHCStruc->bNumPorts; PortReg+=4, Index++) { + // Set PortPowerControlMask bit + DwordSetMem(BaseAddr, OHCI_RH_DESCRIPTOR_B, ((1 << (Index + 1)) << 16)); + // Set PortPower bit + DwordWriteMem(BaseAddr, PortReg, SET_PORT_POWER); + } + } + PowerOnDelay = ((RhDescriptorA & POWERON2POWERGOOD_TIME) >> 24) << 1; + FixedDelay(PowerOnDelay * 1000); + } + + OHCI_ProcessRootHubStatusChange(fpHCStruc); + + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// FUNCTION: OhciAddPeriodicEd +// +// DESCRIPTION: This function adds a ED to the frame list +// +// PARAMETERS: HcStruc - Ptr to the host controller structure +// Ed - ED will be added in periodic schedule +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +OhciAddPeriodicEd ( + HC_STRUC *HcStruc, + OHCI_ED *Ed +) +{ + UINT16 Index; + UINT32 *PrevPtr; + OHCI_ED *Current; + EFI_STATUS Status = EFI_SUCCESS; + + if (Ed == NULL || Ed->Interval == 0) { + return USB_ERROR; + } + + for (Index = 0; Index < HcStruc->wAsyncListSize; Index += Ed->Interval) { + PrevPtr = &HcStruc->fpFrameList[Index]; + Current = (OHCI_ED*)(*PrevPtr); + + while (Current != NULL) { +#if USB_RUNTIME_DRIVER_IN_SMM + Status = AmiValidateMemoryBuffer((VOID*)Current, sizeof(OHCI_ED)); + if (EFI_ERROR(Status)) { + return USB_ERROR; + } +#endif + if (Current->Interval <= Ed->Interval) { + break; + } + + PrevPtr = &Current->fpEDLinkPointer; + Current = (OHCI_ED*)Current->fpEDLinkPointer; + } + + if (Current == Ed) { + continue; + } + Ed->fpEDLinkPointer = (UINT32)(UINTN)Current; +#if USB_RUNTIME_DRIVER_IN_SMM + Status = AmiValidateMemoryBuffer((VOID*)PrevPtr, sizeof(UINT32)); + if (EFI_ERROR(Status)) { + return USB_ERROR; + } +#endif + *PrevPtr = (UINT32)(UINTN)Ed; + } + + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// FUNCTION: OhciRemovePeriodicEd +// +// DESCRIPTION: This function removes a ED from the frame list +// +// PARAMETERS: HcStruc - Ptr to the host controller structure +// Ed - ED will be removed from periodic schedule +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +OhciRemovePeriodicEd ( + HC_STRUC *HcStruc, + OHCI_ED *Ed +) +{ + UINT16 Index; + UINT32 *PrevPtr; + OHCI_ED *Current; + EFI_STATUS Status = EFI_SUCCESS; + + if (Ed == NULL || Ed->Interval == 0) { + return USB_ERROR; + } + + Ed->dControl |= ED_SKIP_TDQ; + + for (Index = 0; Index < HcStruc->wAsyncListSize; Index += Ed->Interval) { + PrevPtr = &HcStruc->fpFrameList[Index]; + Current = (OHCI_ED*)(*PrevPtr); + + while (Current != NULL) { +#if USB_RUNTIME_DRIVER_IN_SMM + Status = AmiValidateMemoryBuffer((VOID*)Current, sizeof(OHCI_ED)); + if (EFI_ERROR(Status)) { + return USB_ERROR; + } +#endif + if (Current == Ed) { + break; + } + + PrevPtr = &Current->fpEDLinkPointer; + Current = (OHCI_ED*)Current->fpEDLinkPointer; + } + + if (Current == NULL) { + continue; + } +#if USB_RUNTIME_DRIVER_IN_SMM + Status = AmiValidateMemoryBuffer((VOID*)PrevPtr, sizeof(UINT32)); + if (EFI_ERROR(Status)) { + return USB_ERROR; + } +#endif + *PrevPtr = Ed->fpEDLinkPointer; + } + + DwordWriteMem((UINT32)HcStruc->BaseAddress, OHCI_INTERRUPT_STATUS, START_OF_FRAME); + DwordWriteMem((UINT32)HcStruc->BaseAddress, OHCI_INTERRUPT_ENABLE, START_OF_FRAME_ENABLE); + + for (Index = 0; Index < 100; Index++) { + if (DwordReadMem((UINT32)HcStruc->BaseAddress, + OHCI_INTERRUPT_STATUS) & START_OF_FRAME) { + break; + } + FixedDelay(10); // 10 us delay + } + ASSERT(Index < 100); + ASSERT(DwordReadMem((UINT32)HcStruc->BaseAddress, OHCI_INTERRUPT_STATUS) & START_OF_FRAME); + DwordWriteMem((UINT32)HcStruc->BaseAddress, OHCI_INTERRUPT_DISABLE, START_OF_FRAME_DISABLE); + + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// FUNCTION: OHCI_StartEDSchedule +// +// DESCRIPTION: This function starts the standard TD schedules for the +// USB host controller +// +// PARAMETERS: HCStruc for the controller +// +// RETURN: USB_ERROR on error, USB_SUCCESS on success +// +// NOTES: This routine creates 1, 2, 8, 32 and 1024ms schedules +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +OHCI_StartEDSchedule( + HC_STRUC *HcStruc +) +{ + OHCI_DESC_PTRS *DescPtrs; + UINT8 *Ptr; + + // + // Allocate descriptor structure and fill it in HCStruc + // + DescPtrs = (OHCI_DESC_PTRS*)USB_MemAlloc (GET_MEM_BLK_COUNT_STRUC(OHCI_DESC_PTRS)); + ASSERT(DescPtrs); + if (!DescPtrs) return USB_ERROR; + + // + // Save the value in the HC struc + // + HcStruc->stDescPtrs.fpOHCIDescPtrs = DescPtrs; + + // + // Allocate 4 EDs + 1 TDs and put them in Descriptor list + // + Ptr = USB_MemAlloc(GET_MEM_BLK_COUNT_STRUC(OHCI_ED)); + ASSERT(Ptr); + if (!Ptr) return USB_ERROR; + + DescPtrs->PeriodicEd = (OHCI_ED*)Ptr; + DescPtrs->PeriodicEd->dControl = ED_SKIP_TDQ; + DescPtrs->PeriodicEd->fpEDLinkPointer = 0; + DescPtrs->PeriodicEd->Interval = 1; + + // Initialize each entry of Interrupt Table as statically disable ED + OhciAddPeriodicEd(HcStruc, DescPtrs->PeriodicEd); + + // + // Allocate ED/TD for EDControl, TDControlSetup, TDControlData, + // TDControlStatus, EDBulk, TDBulkData, EDInterrupt and TDInterruptData + // + Ptr = USB_MemAlloc(GET_MEM_BLK_COUNT(2 * sizeof(OHCI_ED) + 4 * sizeof(OHCI_TD))); + ASSERT(Ptr); + if (!Ptr) return USB_ERROR; + + // + // Save the 8 ED/TD in their proper position. Note: fpHCStruc->stDescPtrs.fpEHCIDescPtrs + // is initialized earlier in OHCI_StartEDSchedule. + // + DescPtrs->fpEDControl = (OHCI_ED*)Ptr; + Ptr += sizeof (OHCI_ED); + + DescPtrs->fpTDControlSetup = (OHCI_TD*)Ptr; + Ptr += sizeof (OHCI_TD); + + DescPtrs->fpTDControlData = (OHCI_TD*)Ptr; + Ptr += sizeof (OHCI_TD); + + DescPtrs->fpTDControlStatus = (OHCI_TD*)Ptr; + Ptr += sizeof (OHCI_TD); + + DescPtrs->fpEDBulk = (OHCI_ED*)Ptr; + Ptr += sizeof (OHCI_ED); + + DescPtrs->fpTDBulkData = (OHCI_TD*)Ptr; + + if (HcStruc->dHCFlag & HC_STATE_EXTERNAL) { + return USB_SUCCESS; + } + + // Allocate a ED/TD for EDRepeat/TDRepeat + Ptr = USB_MemAlloc(GET_MEM_BLK_COUNT_STRUC(OHCI_ED)); + ASSERT(Ptr); + DescPtrs->fpEDRepeat = (OHCI_ED*)Ptr; + + Ptr = USB_MemAlloc(GET_MEM_BLK_COUNT_STRUC(OHCI_TD)); + ASSERT(Ptr); + DescPtrs->fpTDRepeat = (OHCI_TD*)Ptr; + + DescPtrs->fpEDRepeat->dControl = (DUMMY_DEVICE_ADDR | + ED_IN_PACKET | ED_SKIP_TDQ | (DEFAULT_PACKET_LENGTH << 16)); + DescPtrs->fpEDRepeat->fpHeadPointer = (UINT32)(UINTN)DescPtrs->fpTDRepeat; + DescPtrs->fpEDRepeat->fpEDLinkPointer = OHCI_TERMINATE; + DescPtrs->fpEDRepeat->fpTailPointer = OHCI_TERMINATE; + DescPtrs->fpEDRepeat->Interval = REPEAT_INTERVAL; + + DescPtrs->fpTDRepeat->dControlStatus = (UINT32)(GTD_BUFFER_ROUNDING | GTD_IN_PACKET | GTD_IntD | + GTD_TWO_ERRORS | (GTD_NOT_ACCESSED << 28)); + DescPtrs->fpTDRepeat->dCSReloadValue = (UINT32)(GTD_BUFFER_ROUNDING | GTD_IN_PACKET | GTD_IntD | + GTD_TWO_ERRORS | (GTD_NOT_ACCESSED << 28)); + + DescPtrs->fpTDRepeat->fpCurrentBufferPointer = + (UINT32)(UINTN)DescPtrs->fpTDRepeat->aSetupData; + DescPtrs->fpTDRepeat->fpBufferEnd = + (UINT32)(UINTN)DescPtrs->fpTDRepeat->aSetupData; + DescPtrs->fpTDRepeat->fpLinkPointer = OHCI_TERMINATE; + DescPtrs->fpTDRepeat->bCallBackIndex = USB_InstallCallBackFunction(OHCI_RepeatTDCallBack); + DescPtrs->fpTDRepeat->bActiveFlag = FALSE; + + OhciAddPeriodicEd(HcStruc, DescPtrs->fpEDRepeat); + + USBKeyRepeat(HcStruc, 0); + + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// FUNCTION: OHCI_ResetHC +// +// DESCRIPTION: This function resets the OHCI controller +// +// PARAMETERS: Pointer to the HCStruc structure +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 OHCI_ResetHC(HC_STRUC* fpHCStruc) +{ + UINT32 BaseAddr = (UINT32)fpHCStruc->BaseAddress; + UINT8 i; + // + // Issue a software reset and HC go to UsbSuspend state + // + DwordWriteMem(BaseAddr, OHCI_COMMAND_STATUS, HC_RESET); + + // The reset operation must be completed within 10 us + for (i = 0; i < 100; i++) { + FixedDelay(1); // 1 us delay + if (!(DwordReadMem(BaseAddr, OHCI_COMMAND_STATUS) & HC_RESET)) { + return USB_SUCCESS; + } + } + + return USB_ERROR; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// FUNCTION: OHCI_ProcessRootHubStatusChange +// +// DESCRIPTION: This function is called when TD1024ms 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. +// +// PARAMETERS: Pointer to HC Struc +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT32 OHCI_ProcessRootHubStatusChange(HC_STRUC* fpHCStruc) +{ + UINT8 bHCNumber, bPort;//, bPortStatus; //(EIP59663) + + // + // Check bEnumFlag before enumerating devices behind root hub + // + if (gUsbData->bEnumFlag == TRUE) return USB_ERROR; + gUsbData->bEnumFlag = TRUE; // Set enumeration flag and avoid hub port enumeration + // + // 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. + // + DwordWriteMem((UINT32)fpHCStruc->BaseAddress, OHCI_INTERRUPT_DISABLE, 0x80000000); + // + // Check all the ports on the root hub for any change in connect status. + // If the connect status has been changed on either or both of these ports, + // then call the routine UsbHubPortChange for each changed port. + // + bHCNumber = fpHCStruc->bHCNumber | BIT7; + + for (bPort = 1; bPort <= fpHCStruc->bNumPorts; bPort++) { + //(EIP59663)> + //bPortStatus = OHCI_GetRootHubStatus (fpHCStruc, bPort+1); + //DwordResetMem((UINT32)fpHCStruc->BaseAddress, OHCI_RH_PORT1_STATUS+bPort*4, 0xFFFF); + //if (bPortStatus & USB_PORT_STAT_DEV_CONNECT_CHANGED) { + USBCheckPortChange(fpHCStruc, bHCNumber, bPort); + //} + //DwordResetMem((UINT32)fpHCStruc->BaseAddress, OHCI_RH_PORT1_STATUS+bPort*4, 0xFFFF); + //<(EIP59663) + } + // + // Clear the RH_STATUS_CHANGE bit of the interrupt status register + // in the host controller: write 1 to bit to clear it + // + DwordWriteMem((UINT32)fpHCStruc->BaseAddress, OHCI_INTERRUPT_STATUS, RH_STATUS_CHANGE); + + // + // Renable interrupts from the host controller + // + DwordWriteMem((UINT32)fpHCStruc->BaseAddress, OHCI_INTERRUPT_ENABLE, MASTER_INTERRUPT_ENABLE); + + gUsbData->bEnumFlag = FALSE; + return USB_SUCCESS; +} + + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// FUNCTION: OHCIWaitForTransferComplete +// +// DESCRIPTION: This function executes a device request command transaction +// +// PARAMETERS: fpHCStruc Pointer to HCStruc of the host controller +// fpTD Pointer to the TD which has to be completed +// +// RETURN: USB_SUCCESS or USB_ERROR +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +OHCIWaitForTransferComplete( + HC_STRUC *fpHCStruc, + OHCI_ED *XferED, + OHCI_TD *LastTD, + DEV_INFO* fpDevInfo +) +{ + UINT32 Count ; + UINT32 Timeout = gUsbData->wTimeOutValue << 4; // *16, makes it number of 60mcs units + + // + // Check status change loop iteration + // + for(Count = 0; !Timeout || Count < Timeout; Count++) { + OHCI_ProcessInterrupt(fpHCStruc); + if(!LastTD->bActiveFlag ) + return USB_SUCCESS; + else if(!VALID_DEVINFO(fpDevInfo)){ + USB_DEBUG (DEBUG_LEVEL_3, "OHCI Abort: devinfo: %x\n",fpDevInfo ); + return USB_ERROR; + } + FixedDelay(60); // 60 microseconds + } + + XferED->dControl |= ED_SKIP_TDQ; + OHCI_ProcessInterrupt(fpHCStruc); + + if(!LastTD->bActiveFlag) { + return USB_SUCCESS; + } + + USB_DEBUG (DEBUG_LEVEL_3, "OHCI Time-Out\n"); + + return USB_ERROR; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// FUNCTION: OHCI__StopUnsupportedHC +// +// DESCRIPTION: This routine is called, from host controllers that supports +// OS handover functionality (currently from OHCI driver only), when OS +// wants the BIOS to hand-over the host controllers to the OS. This routine +// will stop HC that does not support this functionality. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +OHCI_StopUnsupportedHC( + HC_STRUC* HcStruc +) +{ + UINT8 i; + + if (!gUsbData->UsbEhciHandoff) { + return USB_SUCCESS; + } + +// +// Currently this host controller stops only the EHCI host controllers +// Find the EHCI host controller HCStruc +// + for (i = 0; i < gUsbData->HcTableCount; i++ ) { + if (gUsbData->HcTable[i] == NULL) { + continue; + } + if (!(gUsbData->HcTable[i]->dHCFlag & HC_STATE_USED)) { + continue; + } + if (!(gUsbData->HcTable[i]->dHCFlag & HC_STATE_RUNNING) || + (gUsbData->HcTable[i]->bHCType != USB_HC_EHCI) || + ((gUsbData->HcTable[i]->wBusDevFuncNum & ~0x7) != + (HcStruc->wBusDevFuncNum & ~0x7))) { + continue; + } + + gUsbData->bHandOverInProgress = TRUE; + (*gUsbData->aHCDriverTable[GET_HCD_INDEX( + gUsbData->HcTable[i]->bHCType)].pfnHCDStop)(gUsbData->HcTable[i]); + } + + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// FUNCTION: OHCI_GeneralTDCallback +// +// DESCRIPTION: This function is called when bulk data or interrupt data TD +// is completed. This routine just deactivates the TD. +// +// PARAMETERS: Pointer to the HCStruc structure +// Pointer to the TD that completed +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +OHCI_GeneralTDCallback( + HC_STRUC* HcStruc, + DEV_INFO* DevInfo, + UINT8* Td, + UINT8* Buffer, + UINT16 DataLength + ) +{ + ((OHCI_TD*)Td)->bActiveFlag = FALSE; + return USB_SUCCESS; +} + + +//<AMI_PHDR_START> +//--------------------------------------------------------------------------- +// +// FUNCTION: OHCI_ControlTDCallback +// +// DESCRIPTION: This function is called when the control transfer scheduled +// is completed. +// +// PARAMETERS: fpHCStruc Pointer to the HCStruc structure +// fpDevInfo NULL (pDevInfo is not valid) +// fpTD Pointer to the TD that completed +// fpBuffer Not used +// +// RETURN: USB_SUCCESS or USB_ERROR +// +//--------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +OHCI_ControlTDCallback( + HC_STRUC* HcStruc, + DEV_INFO* DevInfo, + UINT8* Td, + UINT8* Buffer, + UINT16 DataLength +) +{ + OHCI_DESC_PTRS *DescPtrs; + UINT8 *MemBlockEnd = gUsbData->fpMemBlockStart + (gUsbData->MemPages << 12); + + // + // Check to see if the TD that just completed has any error bits set. If + // any of the control TDs (Setup, Data, or Status) complete with an error, set + // ActiveFlag of the control status TD and copy the error information from the + // TD that just completed into the control status TD. + // + if ((UINT8)(((OHCI_TD*)Td)->dControlStatus >> 28)) { + DescPtrs = HcStruc->stDescPtrs.fpOHCIDescPtrs; + if (((UINT8*)DescPtrs < gUsbData->fpMemBlockStart) || + ((UINT8*)(DescPtrs + sizeof(OHCI_DESC_PTRS)) > MemBlockEnd)) { + return USB_ERROR; + } + if (((UINT8*)DescPtrs->fpTDControlStatus < gUsbData->fpMemBlockStart) || + ((UINT8*)(DescPtrs->fpTDControlStatus + sizeof(OHCI_TD)) > MemBlockEnd)) { + return USB_ERROR; + } + if (DescPtrs->fpTDControlStatus != (OHCI_TD*)Td) { + DescPtrs->fpTDControlStatus->dControlStatus = ((OHCI_TD*)Td)->dControlStatus; + DescPtrs->fpTDControlStatus->bActiveFlag = FALSE; + } + } + // + // Make the TD that just completed inactive. It may be the control setup TD, + // one of the control data TDs, or the control status TD. + // + ((OHCI_TD*)Td)->bActiveFlag = FALSE; + + return USB_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// FUNCTION: OHCI_ProcessTD +// +// DESCRIPTION: This function will check whether the TD is completed +// if so, it will call the call back routine associated with +// this TD. +// +// PARAMETERS: HCStruc structure, Pointer to the TD +// +// 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. +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +void OHCI_ProcessTD( + HC_STRUC *HcStruc, + OHCI_TD *Td +) +{ + if (!Td) { + return; // Check for NULL + } + if (Td->bActiveFlag != TRUE) { + return; // TD is not active + } + if ((Td->bCallBackIndex) && (Td->bCallBackIndex <= MAX_CALLBACK_FUNCTION)) { + if (gUsbData->aCallBackFunctionTable[Td->bCallBackIndex-1]) { + (*gUsbData->aCallBackFunctionTable[Td->bCallBackIndex-1])( + HcStruc, + 0, + (UINT8*)Td, + 0, + 0); + } + } +} + + //(EIP28707+)> +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// FUNCTION: OHCI_FreeAllStruc +// +// DESCRIPTION: This function is used to free the all the allocated TDs, +// QH and DescriptorPtr structure. This function only frees +// the entries in the DescriptorPtr and the descriptor pointer +// only. +// ; +// PARAMETERS: fpHCStruc Pointer to the HCStruc structure +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +VOID OHCI_FreeAllStruc(HC_STRUC* fpHCStruc) +{ + OHCI_DESC_PTRS *fpDescPtrs; + + fpDescPtrs = fpHCStruc->stDescPtrs.fpOHCIDescPtrs; + +// Free the EDs & TDs + USB_MemFree(fpDescPtrs->PeriodicEd, GET_MEM_BLK_COUNT_STRUC(OHCI_ED)); + if (fpDescPtrs->fpEDRepeat) { + USB_MemFree(fpDescPtrs->fpEDRepeat, GET_MEM_BLK_COUNT_STRUC(OHCI_ED)); + } + if (fpDescPtrs->fpTDRepeat) { + USB_MemFree(fpDescPtrs->fpTDRepeat, GET_MEM_BLK_COUNT_STRUC(OHCI_TD)); + } + + USB_MemFree(fpDescPtrs->fpEDControl, + GET_MEM_BLK_COUNT(2 * sizeof(OHCI_ED) + 4 * sizeof(OHCI_TD))); + +// Free descriptor structure (in BX) + USB_MemFree(fpDescPtrs, GET_MEM_BLK_COUNT_STRUC(OHCI_DESC_PTRS)); +} + //<(EIP28707+) + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: OhciIsHalted +// +// Description: This function check whether HC is halted. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +BOOLEAN +OhciIsHalted ( + HC_STRUC *HcStruc +) +{ + return (DwordReadMem((UINT32)HcStruc->BaseAddress, OHCI_CONTROL_REG) & HC_FUNCTION_STATE) != USBOPERATIONAL; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// +// Procedure: OhciTranslateInterval +// +// Description: This function calculates the polling rate. +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> + +UINT8 +OhciTranslateInterval( + 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)); +} + +//**************************************************************************** +//**************************************************************************** +//** ** +//** (C)Copyright 1985-2016, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Norcross, GA 30093 ** +//** ** +//** Phone (770)-246-8600 ** +//** ** +//**************************************************************************** +//**************************************************************************** |