#ifndef _IOKIT_AppleUSBUHCI_H
#define _IOKIT_AppleUSBUHCI_H
#if DEBUG_LEVEL != DEBUG_LEVEL_PRODUCTION
#define IOASSERT 1
#include <IOKit/assert.h>
#endif
#include <libkern/OSByteOrder.h>
extern "C" {
#include <kern/queue.h>
}
#include <IOKit/IOService.h>
#include <IOKit/IOInterruptEventSource.h>
#include <IOKit/IOFilterInterruptEventSource.h>
#include <IOKit/IOBufferMemoryDescriptor.h>
#include <IOKit/IOTimerEventSource.h>
#include <IOKit/pci/IOPCIBridge.h>
#include <IOKit/pci/IOPCIDevice.h>
#include <IOKit/IOReturn.h>
#include <IOKit/usb/USB.h>
#include <IOKit/usb/USBHub.h>
#include <IOKit/usb/IOUSBControllerV2.h>
#include "UHCI.h"
#define UHCI_USE_KPRINTF 0
#if UHCI_USE_KPRINTF
#undef USBLog
#undef USBError
void kprintf(const char *format, ...)
__attribute__((format(printf, 1, 2)));
#define USBLog( LEVEL, FORMAT, ARGS... ) if ((LEVEL) <= 5) { 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
#define UHCI_USE_VERTICAL_QUEUES 0
#if UHCI_USE_VERTICAL_QUEUES
#define kUHCI_VERTICAL_FLAG (kUHCI_TD_VF)
#else
#define kUHCI_VERTICAL_FLAG (0)
#endif
#define USB_CONSTANT16(x) (OSSwapHostToLittleConstInt16(x))
#define MICROSECOND (1)
#define MILLISECOND (1000)
#define NANOSECOND_TO_MILLISECOND (1000000)
#define kUHCI_RESET_DELAY 100
#define AUDIO_HACK 0
typedef struct AppleUHCIQH {
struct UHCIQH hw;
IOPhysicalAddress paddr;
int vframe;
struct AppleUHCIQH *hlink;
struct AppleUHCITD *elink;
struct AppleUHCIQH *qlink;
} QH;
typedef struct AppleUHCITD {
struct UHCITD hw;
IOPhysicalAddress paddr;
struct UHCIAlignmentBuffer *buffer;
IOUSBLowLatencyIsocFrame *fllp;
struct AppleUHCITD *link;
} TD;
#define kUHCI_NVFRAMES 1024
#define kUHCI_NINTR_QHS 11
#define kUHCI_NVFRAMES_MASK (kUHCI_NVFRAMES-1)
enum {
kUHCI_MIN_FRAME_OFFSET = 1
};
enum {
kUHCI_ISOC_SPAN_TD = (err_local|err_sub(0x99)|0x42)
};
struct VirtualFrame {
TD *td;
QH *first_qh;
QH *last_qh;
int numIntr;
};
enum {
kUHCI_TP_STATE_NULL,
kUHCI_TP_STATE_FREE,
kUHCI_TP_STATE_ACTIVE,
kUHCI_TP_STATE_COMPLETE,
kUHCI_TP_STATE_ABORTED
};
typedef struct UHCITransaction {
IOMemoryDescriptor * buf;
UInt32 bufLen;
int nCompletions;
IOUSBCompletion completion;
IOUSBCommand * command;
QH * qh;
TD * first_td;
TD * last_td;
int state;
int type;
AbsoluteTime timestamp;
UInt32 timeout;
IOUSBIsocCompletion isoc_completion;
bool isoc_low_latency;
bool isoc_unaligned;
void * isoc_frames;
UInt32 isoc_num_frames;
UInt32 isoc_start_frame;
IOMemoryMap * isoc_map;
UInt64 isoc_full_start_frame;
UInt64 isoc_request_received;
struct UHCIEndpoint * endpoint;
queue_chain_t active_chain; queue_chain_t endpoint_chain; } UHCITransaction;
#define kNTransactionChunk 30
typedef struct UHCIEndpoint {
UInt16 functionNumber;
UInt16 endpointNumber;
UInt16 direction;
UInt16 speed;
UInt16 maxPacketSize;
UInt16 pollingRate; UInt32 type; bool stalled;
bool lastDBit;
AbsoluteTime timestamp;
QH * head_qh;
TD ** isoc_tds;
UInt32 intr_queue;
TD * firstTD; TD * lastTD;
queue_head_t activeTransactions;
queue_head_t freeBuffers;
int buffersInUse;
UInt16 maxBufferSize; queue_head_t allocatedBuffers;
queue_chain_t chain; } UHCIEndpoint;
typedef struct UHCIAlignmentBuffer {
IOPhysicalAddress paddr;
IOVirtualAddress vaddr;
IOMemoryDescriptor * userBuffer;
IOByteCount userOffset;
IOVirtualAddress userAddr;
IOByteCount userLength;
UHCIAlignmentBuffer *next;
UInt32 frameNumber;
UInt32 copyAtInterruptTime;
queue_chain_t chain;
} UHCIAlignmentBuffer;
enum {
kUHCI_BUFFER_ALIGN = 4
};
enum
{
kUHCICheckForRootHubConnectionsPeriod = 30000, kUHCICheckForRootHubInactivityPeriod = 30000 };
enum
{
kUHCIPowerLevelSuspend = 0,
kUHCIPowerLevelRunning = 1,
kUHCIPowerLevelIdleSuspend = 2
};
enum
{
kUHCIResetAfterBabble = 1
};
class AppleUSBUHCI : public IOUSBControllerV2
{
OSDeclareDefaultStructors(AppleUSBUHCI)
private:
void ioWrite8(UInt16 offset, UInt8 value);
void ioWrite16(UInt16 offset, UInt16 value);
void ioWrite32(UInt16 offset, UInt32 value);
UInt8 ioRead8(UInt16 offset);
UInt16 ioRead16(UInt16 offset);
UInt32 ioRead32(UInt16 offset);
inline void Command(UInt16 cmd) {
ioWrite16(kUHCI_CMD, cmd);
}
inline UInt16 ReadPortStatus(int port) {
return ioRead16(kUHCI_PORTSC1 + (port * 2));
}
inline void WritePortStatus(int port, UInt16 value) {
ioWrite16(kUHCI_PORTSC1 + (port * 2), value);
}
inline UInt16 ReadFrameNumberRegister(void) {
return (ioRead16(kUHCI_FRNUM) & kUHCI_FRNUM_MASK);
}
inline UInt16 ReadFrameNumber(void) {
return (ioRead16(kUHCI_FRNUM) & kUHCI_FRNUM_FRAME_MASK);
}
void SetVendorInfo(void);
void SetDeviceName(void);
protected:
IOPCIDevice * _device;
IOMemoryMap * _ioMap;
IOPhysicalAddress _ioPhysAddress;
IOVirtualAddress _ioVirtAddress;
UInt16 _ioBase;
UInt16 _vendorID;
UInt16 _deviceID;
UInt16 _revisionID;
UInt32 _errataBits;
int _deviceNameLen;
const char * _deviceName;
IOFilterInterruptEventSource *_interruptSource;
bool _uimInitialized;
QH * _freeQHs;
TD * _freeTDs;
queue_head_t _allocatedBuffers;
AbsoluteTime _lastTime;
IOLock * _frameLock;
UInt32 _lastFrameNumberLow;
UInt32 _lastFrameNumberHigh;
AbsoluteTime _lastFrameNumberTime;
UInt64 _lastTimeoutFrameNumber;
UHCIAlignmentBuffer * _interruptAlignmentBuffers;
UInt32 _intrStatus;
UInt32 _isocBandwidth;
IOPhysicalAddress _framesPaddr; struct VirtualFrame _vframes[kUHCI_NVFRAMES];
QH * _lastQH;
QH * _bulkQHStart;
QH * _bulkQHEnd;
QH * _hsControlQHStart;
QH * _hsControlQHEnd;
QH * _lsControlQHStart;
QH * _lsControlQHEnd;
QH * _intrQH[kUHCI_NINTR_QHS];
queue_head_t _endpoints;
queue_head_t _freeTransactions;
queue_head_t _activeTransactions;
void StartTransaction(UHCITransaction *tp);
void RemoveTransaction(UHCITransaction *tp);
void CompleteTransaction(UHCITransaction *tp, IOReturn returnCode);
void FixEndpointDBits(UHCIEndpoint *ep);
IOReturn TDToUSBError(UInt32 error);
void CompleteIsoc(IOUSBIsocCompletion completion,
IOReturn status,
void * pFrames);
IOTimerEventSource * _rhTimer;
UInt16 _rootFunctionNumber;
UInt16 _lastPortStatus[kUHCI_NUM_PORTS];
bool _portWasReset[kUHCI_NUM_PORTS];
bool _portSuspendChange[kUHCI_NUM_PORTS];
queue_head_t _rhIntrTransactions;
UHCIEndpoint *_rhEndpoint;
AbsoluteTime _rhChangeTime;
IOReturn RHAbortEndpoint (short endpointNumber, short direction);
IOReturn RHDeleteEndpoint (short endpointNumber, short direction);
IOReturn RHCreateInterruptTransfer(IOUSBCommand * command);
IOReturn RHCreateInterruptEndpoint(
short endpointNumber,
UInt8 direction,
short speed,
UInt16 maxPacketSize,
short pollingRate);
static void RHTimerFired(OSObject *owner, IOTimerEventSource *sender);
AbsoluteTime RHLastPortStatusChanged(void);
bool RHAreAllPortsDisconnected(void);
void RHCheckStatus(void);
void RHEnablePort(int port, bool enable);
IOReturn RHSuspendPort(int port, bool suspend);
IOReturn RHResetPort(int port);
void RHDumpPortStatus(int port); void RHDumpHubPortStatus(IOUSBHubPortStatus *status);
virtual IOReturn GetRootHubStringDescriptor(UInt8 index, OSData *desc);
void StopEndpoint(UHCIEndpoint *ep);
void ReturnEndpointTransactions(UHCIEndpoint *ep, IOReturn status);
void UIMProcessDoneQueue(IOUSBCompletionAction safeAction=0);
void UIMRootHubStatusChange( void );
void UIMRootHubStatusChange(bool abort);
UHCIEndpoint * FindEndpoint(IOUSBCommand *command);
UHCIEndpoint * FindEndpoint(short functionNumber, short endpointNumber, UInt8 direction);
IOReturn DeleteEndpoint(short functionNumber, short endpointNumber, UInt8 direction);
static void InterruptHandler(OSObject *owner,
IOInterruptEventSource * ,
int );
static bool PrimaryInterruptFilter(OSObject *owner, IOFilterInterruptEventSource *source);
bool FilterInterrupt(void);
void HandleInterrupt(void);
bool HandleShortPacket(UHCITransaction *tp, TD *td);
bool IsTransactionComplete(UHCITransaction *tp);
int ProcessCompletedTransactions(void);
void GlobalReset(void);
IOReturn Reset(bool enableInterrupts = false);
IOReturn HardwareInit(void);
IOReturn Run(bool);
struct AppleUHCITD * AllocTD(void);
void FreeTD(struct AppleUHCITD *);
struct AppleUHCIQH * AllocQH(void);
void FreeQH(struct AppleUHCIQH *);
UHCITransaction * AllocTransaction(UHCIEndpoint *);
void FreeTransaction(UHCITransaction *);
UHCIEndpoint * AllocEndpoint(void);
UHCIEndpoint * AllocEndpoint(UInt16 functionNumber,
UInt16 endpointNumber,
UInt16 direction,
UInt16 speed,
UInt16 maxPacketSize,
UInt32 type);
void FreeEndpoint(UHCIEndpoint *);
UHCIAlignmentBuffer * EndpointAllocBuffer(UHCIEndpoint *ep);
void EndpointFreeBuffer(UHCIEndpoint *ep, UHCIAlignmentBuffer *bp);
IOReturn EndpointFreeAllBuffers(UHCIEndpoint *ep);
IOReturn AllocTDChain(UHCIEndpoint *ep,
IOMemoryDescriptor *mp,
IOByteCount len,
bool shortOK,
short direction,
TD **start_p, TD **end_p,
bool setVFlag = false,
bool isControlTranser = false);
void FreeTDChain(TD *td);
void DumpTransaction(UHCITransaction *tp, int level = 7);
void DumpTD(TD *td, int level = 7);
void DumpTDChain(TD *td, bool qhOK = false, int level = 7);
void DumpQH(QH *, int level = 7);
void DumpQHChain(QH *, int level = 7);
void DumpFrame(UInt16 frame = 0, int level = 7);
void DumpEndpoint(UHCIEndpoint *ep, int level = 7);
void SingleStep(int count, bool runAfter);
IOReturn CreateIsochTransfer(
short functionAddress,
short endpointNumber,
IOUSBIsocCompletion completion,
UInt8 direction,
UInt64 frameStart,
IOMemoryDescriptor * pBuffer,
UInt32 frameCount,
void * pFrames,
UInt32 updateFrequency,
bool isLowLatency);
IOReturn StartIsochTransfer(
UHCITransaction *tp
);
bool _unloadUIMAcrossSleep;
UInt32 _saveFrameAddress;
UInt16 _saveFrameNumber;
bool _remoteWakeupOccurred;
int _powerLevel;
IONotifier *_powerDownNotifier;
virtual void initForPM (IOPCIDevice *provider);
unsigned long maxCapabilityForDomainState ( IOPMPowerFlags domainState );
unsigned long initialPowerStateForDomainState ( IOPMPowerFlags domainState );
static IOReturn PowerDownHandler(void *target, void *refCon, UInt32 messageType, IOService *service,
void *messageArgument, vm_size_t argSize);
virtual IOReturn setPowerState( unsigned long powerStateOrdinal, IOService* whatDevice );
void ResumeController(void);
void SuspendController(void);
void StopController(void);
void RestartController(void);
void EnableUSBInterrupt(bool enableInterrupt);
public:
virtual bool init(OSDictionary * propTable);
virtual bool start( IOService * provider );
virtual void stop( IOService * provider );
virtual bool finalize(IOOptionBits options);
virtual IOReturn message( UInt32 type, IOService * provider, void * argument = 0 );
IOReturn UIMInitialize(IOService * provider);
IOReturn UIMFinalize();
IOReturn UIMInitializeForPowerUp();
IOReturn UIMFinalizeForPowerDown();
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,
void * 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,
IOMemoryDescriptor * 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 UIMCreateIsochTransfer(
short functionAddress,
short endpointNumber,
IOUSBIsocCompletion completion,
UInt8 direction,
UInt64 frameStart,
IOMemoryDescriptor * pBuffer,
UInt32 frameCount,
IOUSBIsocFrame *pFrames);
virtual IOReturn
UIMCreateIsochTransfer(
short functionAddress,
short endpointNumber,
IOUSBIsocCompletion completion,
UInt8 direction,
UInt64 frameNumberStart,
IOMemoryDescriptor * pBuffer,
UInt32 frameCount,
IOUSBLowLatencyIsocFrame *pFrames,
UInt32 updateFrequency);
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 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 void PollInterrupts(IOUSBCompletionAction safeAction=0);
virtual IOReturn callPlatformFunction(const OSSymbol *functionName,
bool waitForFunction,
void *param1, void *param2,
void *param3, void *param4);
virtual void UIMCheckForTimeouts(void);
};
#endif