#ifndef _IOKIT_AppleUSBEHCI_H
#define _IOKIT_AppleUSBEHCI_H
#include <libkern/c++/OSData.h>
#include <IOKit/IOService.h>
#include <IOKit/IOFilterInterruptEventSource.h>
#include <IOKit/IOBufferMemoryDescriptor.h>
#include <IOKit/IODMACommand.h>
#include <IOKit/pci/IOPCIBridge.h>
#include <IOKit/pci/IOPCIDevice.h>
#include <IOKit/usb/IOUSBControllerV2.h>
#include <IOKit/usb/IOUSBControllerListElement.h>
#include <IOKit/usb/USB.h>
#include <IOKit/usb/USBHub.h>
#include "USBEHCI.h"
#include "USBEHCIRootHub.h"
#define MICROSECOND (1)
#define MILLISECOND (1000)
#define EHCI_USE_KPRINTF 0
#if EHCI_USE_KPRINTF
#undef USBLog
#undef USBError
void kprintf(const char *format, ...)
__attribute__((format(printf, 1, 2)));
#define USBLog( LEVEL, FORMAT, ARGS... ) if ((LEVEL) <= 3) { kprintf( FORMAT "\n", ## ARGS ) ; }
#define USBError( LEVEL, FORMAT, ARGS... ) { kprintf( FORMAT "\n", ## ARGS ) ; }
#endif
#ifdef __ppc__
#define IOSync eieio
#else
#define IOSync() __asm__ __volatile__ ( "mfence" : : : "memory" )
#endif
struct InterruptTransaction {
IOMemoryDescriptor * buf;
UInt32 bufLen;
IOUSBCompletion completion;
};
#define kMaxOutstandingTrans 4
class IONaturalMemoryCursor;
class AppleEHCIedMemoryBlock;
class AppleEHCItdMemoryBlock;
class AppleEHCIitdMemoryBlock;
class AppleEHCIsitdMemoryBlock;
class AppleEHCIQueueHead;
class AppleEHCIIsochTransferDescriptor;
class AppleEHCISplitIsochTransferDescriptor;
typedef struct EHCIGeneralTransferDescriptor
EHCIGeneralTransferDescriptor,
*EHCIGeneralTransferDescriptorPtr;
#include "AppleEHCIListElement.h"
#include "AppleUSBEHCIHubInfo.h"
struct EHCIGeneralTransferDescriptor
{
EHCIGeneralTransferDescriptorSharedPtr pShared;
IOUSBCommand *command; UInt32 unused;
AppleEHCIQueueHead *pQH; UInt8 traceFlag;
UInt8 lastTDofTransaction;
IOPhysicalAddress pPhysical;
EHCIGeneralTransferDescriptorPtr pLogicalNext;
void* logicalBuffer; UInt32 lastFrame; UInt32 lastRemaining;
};
struct EHCIDoneQueueParams
{
EHCIGeneralTransferDescriptorPtr pHCDoneTD;
OSStatus forceErr;
IOUSBCompletionAction safeAction;
EHCIGeneralTransferDescriptorPtr stopAt;
};
enum{
kEHCIElementTypeBad = 0,
kEHCIElementTypeED,
kEHCIElementTypeiTD,
kEHCIElementTypeSiTD
};
enum
{
kEHCICheckForRootHubConnectionsPeriod = 5, kEHCICheckForRootHubInactivityPeriod = 2 };
enum
{
kUSBEHCIFSPeriodicOverhead = 10, kUSBEHCIMaxMicroframePeriodic = 180, kUSBEHCIMaxSSOUTsection = 188 };
enum{
kMaxPorts = 16
};
class AppleUSBEHCI : public IOUSBControllerV2
{
OSDeclareDefaultStructors(AppleUSBEHCI)
private:
virtual void initForPM (IOPCIDevice *provider);
unsigned long maxCapabilityForDomainState ( IOPMPowerFlags domainState );
unsigned long initialPowerStateForDomainState ( IOPMPowerFlags domainState );
virtual IOReturn setPowerState( unsigned long, IOService* );
static IOReturn PowerDownHandler(void *target, void *refCon, UInt32 messageType, IOService *service, void *messageArgument, vm_size_t argSize);
UInt32 ExpressCardPort( IOService * provider );
void showRegisters(char *s);
void printTD(EHCIGeneralTransferDescriptorPtr pTD, int level);
void printAsyncQueue(int level);
void AddIsocFramesToSchedule(AppleEHCIIsochEndpoint*);
IOReturn AbortIsochEP(AppleEHCIIsochEndpoint*);
IOReturn DeleteIsochEP(AppleEHCIIsochEndpoint*);
UInt8 LastScheduledSSMicroFrame(AppleEHCIIsochEndpoint* pEP);
UInt8 FirstScheduledSSMicroFrame(AppleEHCIIsochEndpoint* pEP);
protected:
IOPCIDevice * _device;
IOMemoryMap * _deviceBase;
UInt16 _vendorID;
UInt16 _deviceID;
UInt16 _revisionID;
UInt32 _errataBits; EHCICapRegistersPtr _pEHCICapRegisters; EHCIRegistersPtr _pEHCIRegisters; UInt32 _dataAllocationSize; SInt32 _greatestPeriod; EHCIGeneralTransferDescriptorPtr _pFreeTD; AppleEHCIIsochTransferDescriptor *_pFreeITD; AppleEHCISplitIsochTransferDescriptor *_pFreeSITD; AppleEHCIQueueHead *_pFreeQH; EHCIGeneralTransferDescriptorPtr _pLastFreeTD; AppleEHCIIsochTransferDescriptor *_pLastFreeITD; AppleEHCISplitIsochTransferDescriptor *_pLastFreeSITD; AppleEHCIQueueHead *_pLastFreeQH; IOBufferMemoryDescriptor *_periodicListBuffer; IOPhysicalAddress *_periodicList; IOUSBControllerListElement **_logicalPeriodicList; UInt16 _periodicBandwidth[kEHCIMaxPoll]; AppleUSBEHCIHubInfo *_hsHubs; IOFilterInterruptEventSource * _filterInterruptSource;
UInt32 _filterInterruptCount;
UInt8 _ehciBusState;
UInt8 _istKeepAwayFrames; IOLock * _intLock;
volatile IOUSBControllerIsochListElement *_savedDoneQueueHead; volatile UInt32 _producerCount; volatile UInt32 _consumerCount; volatile bool _filterInterruptActive; IOSimpleLock * _wdhLock;
IOSimpleLock * _isochScheduleLock;
UInt32 _asyncAdvanceInterrupt;
UInt32 _hostErrorInterrupt;
UInt32 _portChangeInterrupt;
UInt32 _errorInterrupt;
UInt32 _completeInterrupt;
UInt32 _controlBulkTransactionsOut;
const OSSymbol *usb_remote_wakeup;
bool _unloadUIMAcrossSleep;
bool _onCardBus;
bool _remote_wakeup_occurred;
bool _idleSuspend;
bool _uimInitialized;
bool _testModeEnabled;
bool _sleepRegistersSaved;
bool _hasPCIPwrMgmt;
bool _ehciAvailable;
bool _is64bit;
bool _inAbortIsochEP;
bool _wakingFromHibernation;
UInt8 _asynchScheduleUnsynchCount;
UInt8 _periodicScheduleUnsynchCount;
UInt32 _isochBandwidthAvail; UInt32 _periodicEDsInSchedule; UInt64 _frameNumber; UInt16 _rootHubFuncAddress; struct InterruptTransaction _outstandingTrans[kMaxOutstandingTrans];
struct {
volatile UInt32 hostSystemError; volatile UInt32 unrecoverableError; volatile UInt32 ownershipChange; UInt32 displayed;
} _errors;
UInt32 _frameListSize;
AppleEHCIQueueHead *_AsyncHead;
AppleEHCIedMemoryBlock *_edMBHead;
AppleEHCItdMemoryBlock *_tdMBHead;
AppleEHCIitdMemoryBlock *_itdMBHead;
AppleEHCIsitdMemoryBlock *_sitdMBHead;
AbsoluteTime _lastRootHubStatusChanged; UInt32 _savedUSBIntr; UInt32 _savedUSBCMD; UInt32 _savedPeriodicListBase; UInt32 _savedAsyncListAddr; UInt32 _savedSuspendedPortBitmap; UInt16 _outSlot;
AbsoluteTime _lastCheckedTime; UInt32 _rhPrevStatus[kMaxPorts]; UInt32 _rhChangeBits[kMaxPorts]; UInt32 _ExpressCardPort; IONotifier * _powerDownNotifier;
bool _needToCreateRootHub; bool _gangedOvercurrent; bool _badExpressCardAttached; thread_call_t _portDetectInterruptThread;
UInt32 _nextDoneQueue;
struct EHCIDoneQueueParams _doneQueueParams[20];
static void InterruptHandler(OSObject *owner, IOInterruptEventSource * source, int count);
static bool PrimaryInterruptFilter(OSObject *owner, IOFilterInterruptEventSource *source);
static void PortDetectInterruptThreadEntry(OSObject *target);
void PortDetectInterruptThread();
bool FilterInterrupt(int index);
void UIMRootHubStatusChange(void);
void UIMRootHubStatusChange( bool abort );
void SimulateRootHubInt(
UInt8 endpoint,
IOMemoryDescriptor * buf,
UInt32 bufLen,
IOUSBCompletion completion);
void SetVendorInfo(void);
AppleEHCIQueueHead *MakeEmptyEndPoint(
UInt8 functionAddress,
UInt8 endpointNumber,
UInt16 maxPacketSize,
UInt8 speed,
USBDeviceAddress highSpeedHub,
int highSpeedPort,
UInt8 direction);
AppleEHCIQueueHead *MakeEmptyIntEndPoint(
UInt8 functionAddress,
UInt8 endpointNumber,
UInt16 maxPacketSize,
UInt8 speed,
USBDeviceAddress highSpeedHub,
int highSpeedPort,
UInt8 direction);
void linkInterruptEndpoint(AppleEHCIQueueHead *pEHCIEndpointDescriptor);
void linkAsyncEndpoint(AppleEHCIQueueHead *CBED, AppleEHCIQueueHead *pEDHead);
void returnTransactions(AppleEHCIQueueHead *pED, EHCIGeneralTransferDescriptor *untilThisOne, IOReturn error);
AppleEHCIQueueHead *AddEmptyCBEndPoint(
UInt8 functionAddress,
UInt8 endpointNumber,
UInt16 maxPacketSize,
UInt8 speed,
USBDeviceAddress highSpeedHub,
int highSpeedPort,
UInt8 direction,
AppleEHCIQueueHead *pED);
AppleEHCIQueueHead *FindInterruptEndpoint(
short functionNumber,
short endpointNumber,
short direction,
IOUSBControllerListElement **pLEBack);
AppleEHCIQueueHead *AllocateQH(void);
EHCIGeneralTransferDescriptorPtr AllocateTD(void);
AppleEHCIIsochTransferDescriptor *AllocateITD(void);
AppleEHCISplitIsochTransferDescriptor *AllocateSITD(void);
IOReturn allocateTDs(
AppleEHCIQueueHead *pEDQueue,
IOUSBCommand* command,
IOMemoryDescriptor * CBP,
UInt32 bufferSize,
UInt16 direction,
Boolean controlTransaction);
AppleEHCIQueueHead *FindControlBulkEndpoint (
short functionNumber,
short endpointNumber,
AppleEHCIQueueHead **pEDBack,
short direction);
void scavengeCompletedTransactions(IOUSBCompletionAction safeAction);
IOReturn scavengeIsocTransactions(IOUSBCompletionAction safeAction, bool reQueueTransactions);
IOReturn scavengeAnIsocTD(IOUSBControllerIsochListElement *pTD, IOUSBCompletionAction safeAction);
IOReturn scavengeAnEndpointQueue(IOUSBControllerListElement *pEDQueue, IOUSBCompletionAction safeAction);
IOReturn EHCIUIMDoDoneQueueProcessing(EHCIGeneralTransferDescriptorPtr pHCDoneTD, OSStatus forceErr, IOUSBCompletionAction safeAction, EHCIGeneralTransferDescriptorPtr stopAt);
IOReturn DeallocateTD (EHCIGeneralTransferDescriptorPtr pTD);
IOReturn DeallocateED (AppleEHCIQueueHead *pED);
void doCallback(EHCIGeneralTransferDescriptorPtr nextTD,
UInt32 transferStatus,
UInt32 bufferSizeRemaining);
IOReturn AsyncInitialize (void);
IOReturn InterruptInitialize (void);
void unlinkIntEndpoint(AppleEHCIQueueHead *pED);
void unlinkAsyncEndpoint(AppleEHCIQueueHead *pED, AppleEHCIQueueHead *pEDQueueBack);
void HaltAsyncEndpoint(AppleEHCIQueueHead *pED, AppleEHCIQueueHead *pEDBack);
void HaltInterruptEndpoint(AppleEHCIQueueHead *pED);
void waitForSOF(EHCIRegistersPtr pEHCIRegisters);
UInt16 validatePollingRate(short rawPollingRate, short speed, int *offset, UInt16 *bytesAvailable);
IOReturn EnterTestMode(void);
IOReturn PlacePortInMode(UInt32 port, UInt32 mode);
IOReturn LeaveTestMode(void);
void ResumeUSBBus();
void SuspendUSBBus();
void StopUSBBus();
void RestartUSBBus();
IOReturn AcquireOSOwnership(void);
IOReturn CreateHSIsochTransfer(AppleEHCIIsochEndpoint *pEP, IOUSBIsocCommand *command);
IOReturn CreateSplitIsochTransfer(AppleEHCIIsochEndpoint *pEP, IOUSBIsocCommand *command);
void ReturnOneTransaction(EHCIGeneralTransferDescriptor *transaction,
AppleEHCIQueueHead *pED,
AppleEHCIQueueHead *pEDBack,
IOReturn err);
UInt32 findBufferRemaining(AppleEHCIQueueHead *pED);
void UIMCheckForTimeouts(void);
#if 0
void printED(AppleEHCIQueueHead * pED);
#endif
public:
virtual bool init(OSDictionary * propTable);
virtual bool start( IOService * provider );
virtual void free();
virtual IOReturn message( UInt32 type, IOService * provider, void * argument = 0 );
IOReturn UIMInitialize(IOService * provider);
IOReturn UIMFinalize();
IOReturn UIMFinalizeForPowerDown();
IOReturn UIMInitializeForPowerUp();
IOReturn DeallocateITD (AppleEHCIIsochTransferDescriptor *pTD);
IOReturn DeallocateSITD (AppleEHCISplitIsochTransferDescriptor *pTD);
virtual IOReturn UIMCreateControlEndpoint(UInt8 functionNumber,
UInt8 endpointNumber,
UInt16 maxPacketSize,
UInt8 speed);
virtual IOReturn UIMCreateControlEndpoint(UInt8 functionNumber,
UInt8 endpointNumber,
UInt16 maxPacketSize,
UInt8 speed,
USBDeviceAddress highSpeedHub,
int highSpeedPort);
virtual IOReturn UIMCreateControlTransfer(short functionNumber,
short endpointNumber,
IOUSBCompletion completion,
void *CBP,
bool bufferRounding,
UInt32 bufferSize,
short direction);
virtual IOReturn UIMCreateControlTransfer(short functionNumber,
short endpointNumber,
IOUSBCommand* command,
IOMemoryDescriptor *CBP,
bool bufferRounding,
UInt32 bufferSize,
short direction);
virtual IOReturn UIMCreateControlTransfer(short functionNumber,
short endpointNumber,
IOUSBCompletion completion,
IOMemoryDescriptor *CBP,
bool bufferRounding,
UInt32 bufferSize,
short direction);
virtual IOReturn UIMCreateControlTransfer(short functionNumber,
short endpointNumber,
IOUSBCommand *command,
void *CBP,
bool bufferRounding,
UInt32 bufferSize,
short direction);
virtual IOReturn UIMCreateBulkEndpoint(UInt8 functionNumber,
UInt8 endpointNumber,
UInt8 direction,
UInt8 speed,
UInt8 maxPacketSize);
virtual IOReturn UIMCreateBulkEndpoint(UInt8 functionNumber,
UInt8 endpointNumber,
UInt8 direction,
UInt8 speed,
UInt16 maxPacketSize,
USBDeviceAddress highSpeedHub,
int highSpeedPort);
virtual IOReturn UIMCreateBulkTransfer(short functionNumber,
short endpointNumber,
IOUSBCompletion completion,
IOMemoryDescriptor *CBP,
bool bufferRounding,
UInt32 bufferSize,
short direction);
virtual IOReturn UIMCreateBulkTransfer(IOUSBCommand* command);
virtual IOReturn UIMCreateInterruptEndpoint(short functionAddress,
short endpointNumber,
UInt8 direction,
short speed,
UInt16 maxPacketSize,
short pollingRate);
virtual IOReturn UIMCreateInterruptEndpoint(short functionAddress,
short endpointNumber,
UInt8 direction,
short speed,
UInt16 maxPacketSize,
short pollingRate,
USBDeviceAddress highSpeedHub,
int highSpeedPort);
virtual IOReturn UIMCreateInterruptTransfer(short functionNumber,
short endpointNumber,
IOUSBCompletion completion,
IOMemoryDescriptor *CBP,
bool bufferRounding,
UInt32 bufferSize,
short direction);
virtual IOReturn UIMCreateInterruptTransfer(IOUSBCommand* command);
virtual IOReturn UIMCreateIsochEndpoint(short functionAddress,
short endpointNumber,
UInt32 maxPacketSize,
UInt8 direction);
virtual IOReturn UIMCreateIsochEndpoint(short functionAddress,
short endpointNumber,
UInt32 maxPacketSize,
UInt8 direction,
USBDeviceAddress highSpeedHub,
int highSpeedPort);
virtual IOReturn UIMCreateIsochEndpoint(short functionAddress,
short endpointNumber,
UInt32 maxPacketSize,
UInt8 direction,
USBDeviceAddress highSpeedHub,
int highSpeedPort,
UInt8 interval);
virtual IOReturn UIMCreateIsochTransfer(short functionAddress,
short endpointNumber,
IOUSBIsocCompletion completion,
UInt8 direction,
UInt64 frameStart,
IOMemoryDescriptor *pBuffer,
UInt32 frameCount,
IOUSBIsocFrame *pFrames);
virtual IOReturn UIMAbortEndpoint(short functionNumber,
short endpointNumber,
short direction);
virtual IOReturn UIMDeleteEndpoint(short functionNumber,
short endpointNumber,
short direction);
virtual IOReturn UIMClearEndpointStall(short functionNumber,
short endpointNumber,
short direction);
IOReturn HandleEndpointAbort(short functionNumber, short endpointNumber, short direction, bool clearToggle);
IOReturn GetRootHubDeviceDescriptor(IOUSBDeviceDescriptor *desc);
IOReturn GetRootHubDescriptor(IOUSBHubDescriptor *desc);
IOReturn SetRootHubDescriptor(OSData *buffer);
IOReturn GetRootHubConfDescriptor(OSData *desc);
IOReturn GetRootHubStatus(IOUSBHubStatus *status);
IOReturn SetRootHubFeature(UInt16 wValue);
IOReturn ClearRootHubFeature(UInt16 wValue);
IOReturn GetRootHubPortStatus(IOUSBHubPortStatus *status, UInt16 port);
IOReturn SetRootHubPortFeature(UInt16 wValue, UInt16 port);
IOReturn ClearRootHubPortFeature(UInt16 wValue, UInt16 port);
IOReturn GetRootHubPortState(UInt8 *state, UInt16 port);
IOReturn SetHubAddress(UInt16 wValue);
virtual UInt32 GetBandwidthAvailable();
virtual UInt64 GetFrameNumber();
virtual UInt32 GetFrameNumber32();
virtual UInt64 GetMicroFrameNumber();
virtual void PollInterrupts(IOUSBCompletionAction safeAction=0);
virtual IOReturn callPlatformFunction(const OSSymbol *functionName,
bool waitForFunction,
void *param1, void *param2,
void *param3, void *param4);
IOReturn EHCIRootHubPower(bool on);
IOReturn EHCIRootHubResetChangeConnection(UInt16 port);
IOReturn EHCIRootHubResetResetChange(UInt16 port);
IOReturn EHCIRootHubResetSuspendChange(UInt16 port);
IOReturn EHCIRootHubResetEnableChange(UInt16 port);
IOReturn EHCIRootHubResetOverCurrentChange(UInt16 port);
IOReturn EHCIRootHubResetPort (UInt16 port);
IOReturn EHCIRootHubPortEnable(UInt16 port, bool on);
IOReturn EHCIRootHubPortSuspend(UInt16 port, bool on);
IOReturn EHCIRootHubPortPower(UInt16 port, bool on);
IOReturn SimulateEDDelete (short endpointNumber, short direction);
IOReturn SimulateEDAbort (short endpointNumber, short direction);
IOReturn GetRootHubStringDescriptor(UInt8 index, OSData *desc);
AbsoluteTime LastRootHubPortStatusChanged( bool reset );
virtual IOReturn UIMCreateIsochTransfer(short functionAddress,
short endpointNumber,
IOUSBIsocCompletion completion,
UInt8 direction,
UInt64 frameStart,
IOMemoryDescriptor * pBuffer,
UInt32 frameCount,
IOUSBLowLatencyIsocFrame *pFrames,
UInt32 updateFrequency);
virtual IOReturn UIMCreateIsochTransfer(IOUSBIsocCommand *command);
virtual IOReturn UIMHubMaintenance(USBDeviceAddress highSpeedHub, UInt32 highSpeedPort, UInt32 command, UInt32 flags);
virtual IOReturn UIMSetTestMode(UInt32 mode, UInt32 port);
IOReturn EnableAsyncSchedule(bool waitForON);
IOReturn DisableAsyncSchedule(bool waitForOFF);
IOReturn EnablePeriodicSchedule(bool waitForON);
IOReturn DisablePeriodicSchedule(bool waitForOFF);
void CheckEDListForTimeouts(AppleEHCIQueueHead *head);
bool RootHubAreAllPortsDisconnectedOrSuspended( void );
void GetNumberOfPorts(UInt8 *numPorts);
virtual IOUSBControllerIsochEndpoint* AllocateIsochEP();
virtual void ReturnIsochDoneQueue(IOUSBControllerIsochEndpoint*);
virtual IODMACommand *GetNewDMACommand();
};
enum
{
kEHCISetPowerLevelSuspend = 0,
kEHCISetPowerLevelRunning = 1,
kEHCISetPowerLevelIdleSuspend = 2
};
enum
{
kEHCIBusStateOff = 0,
kEHCIBusStateSuspended = 1,
kEHCIBusStateRunning = 2
};
#endif