AppleRS232Serial.h [plain text]
#ifndef __AppleRS232Serial__
#define __AppleRS232Serial__
#define LDEBUG 0 // for debugging
#define USE_ELG 0 // to event log - LDEBUG must also be set
#define LOG_DATA 0 // logs data to the IOLog - LDEBUG must also be set
#define DUMPALL 0 // Dumps all the data to the log - LOG_DATA must also be set
#define Sleep_Time 20
#if LDEBUG
#if USE_ELG
#include "XTrace.h"
#define XTRACE(x, y, msg) \
do \
{ \
if (gXTrace) \
{ \
static char *__xtrace = 0; \
if (__xtrace) \
gXTrace->LogAdd(gTraceID, (UInt32)(x), (UInt32)(y), __xtrace); \
else \
__xtrace = gXTrace->LogAdd(gTraceID, (UInt32)(x), (UInt32)(y), msg, false); \
} \
} while(0)
#define ELG(x, y, msg) XTRACE(x, y, msg)
#define XTRACE2(x, y, msg) XTRACE_HELPER(gXTrace, gTraceID, x, y, "AppleRS232Serial: " msg)
#else
#define ELG(A,B,STRING) {IOLog( "AppleRS232Serial: %8x %8x " STRING "\n", (unsigned int)(A), (unsigned int)(B) );IOSleep(Sleep_Time);}
#endif
#if LOG_DATA
#define LogData(D, C, b) SerialLogData((UInt8)D, (UInt32)C, (char *)b)
#else
#define LogData(D, C, b)
#endif
#else
#define ELG(A,B,S)
#define LogData(D, C, b)
#undef USE_ELG
#undef LOG_DATA
#endif
#define ALERT(A,B,STRING) IOLog( "AppleRS232Serial: %8x %8x " STRING "\n", (unsigned int)(A), (unsigned int)(B) )
#define getDebugFlags() (getDebugFlagsTable(getPropertyTable()))
#define NEWPHYS 1 // New is getPhysicalSegment (at the moment) as opposed to old pmap-extract
#include <IOKit/IOLib.h>
#include <IOKit/IOService.h>
#include <IOKit/IOTimerEventSource.h>
#include <IOKit/IOWorkLoop.h>
#include <IOKit/IOCommandGate.h>
#include <IOKit/IOConditionLock.h>
#include <IOKit/IOInterruptEventSource.h>
#include <IOKit/platform/AppleMacIODevice.h>
#include <IOKit/serial/IOSerialDriverSync.h>
#include <IOKit/serial/IORS232SerialStreamSync.h>
#include <IOKit/IOWorkLoop.h>
#include <IOKit/IOInterruptEventSource.h>
#include <IOKit/IOFilterInterruptEventSource.h>
#include <IOKit/IOBufferMemoryDescriptor.h>
#include <IOKit/ppc/IODBDMA.h>
#include "SccQueue.h"
#include "Z85C30.h"
#define MIN_BAUD (50 << 1)
enum
{
kSerialOut = 0,
kSerialIn = 1,
kSerialOther = 2
};
enum
{
R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, R15
};
#define USE_WORK_LOOPS 1
#define USE_FILTER_EVENT_SOURCES 0
#define BIGGEST_EVENT 3
#define BUFFER_SIZE_MINIMUM (BIGGEST_EVENT*6)
#define BUFFER_SIZE_DEFAULT (16*1024)
#define BUFFER_SIZE_MAXIMUM (256<<10)
#define TX_BUFFER_SIZE_KEY "TX Buffer Size"
#define RX_BUFFER_SIZE_KEY "RX Buffer Size"
#define CHIP_TYPE_KEY "Chip Type"
#define INSTANCE_KEY "Instance"
#define CHIP_CLOCK_KEY "Chip Clock"
#define CHIP_CLOCK_DEFAULT (1843200l)
#define HEART_BEAT_KEY "Heart Beat Interval"
#define HEART_BEAT_DEFAULT (11000l)
#define MSR_INTERRUPT_KEY "Enable MSR Interrupts"
#define BUS_TYPE_KEY "Bus Type"
#define BUS_EISA_VAL "EISA"
#define BUS_PCMCIA_VAL "PCMCIA"
#define SPECIAL_SHIFT (5)
#define SPECIAL_MASK ((1<<SPECIAL_SHIFT) - 1)
#define STATE_ALL (PD_RS232_S_MASK | PD_S_MASK )
#define FLOW_RX_AUTO (PD_RS232_A_RFR | PD_RS232_A_DTR | PD_RS232_A_RXO )
#define FLOW_TX_AUTO (PD_RS232_A_CTS | PD_RS232_A_DSR | PD_RS232_A_TXO | PD_RS232_A_DCD )
#define CAN_BE_AUTO (FLOW_RX_AUTO | FLOW_TX_AUTO )
#define CAN_NOTIFY (PD_RS232_N_MASK )
#define EXTERNAL_MASK (PD_S_MASK | (PD_RS232_S_MASK & ~PD_RS232_S_LOOP) )
#define INTERNAL_DELAY (PD_RS232_S_LOOP )
#define DEFAULT_AUTO (PD_RS232_A_DTR | PD_RS232_A_RFR | PD_RS232_A_CTS | PD_RS232_A_DSR )
#define DEFAULT_NOTIFY (0x00 )
#define DEFAULT_STATE (PD_S_TX_ENABLE | PD_S_RX_ENABLE | PD_RS232_A_TXO | PD_RS232_A_RXO )
#define IDLE_XO 0
#define NEEDS_XOFF 1
#define SENT_XOFF -1
#define NEEDS_XON 2
#define SENT_XON -2
#define CONTINUE_SEND 1
#define PAUSE_SEND 2
typedef UInt32 CalloutTime;
#define calloutEntryAllocate thread_call_allocate
#define calloutEntryRemove thread_call_cancel
#define calloutEntryFree thread_call_free
#define calloutEntryDispatch thread_call_enter
#define calloutEntryDispatchDelayed thread_call_enter_delayed
#define kX1UserClockMode 0x00 // for MIDI devices
#define kX16UserClockMode 0x0b
#define kX32UserClockMode 0x19
#define kX64UserClockMode 0x32
static inline void SynchronizeIO(void)
{
eieio();
}
typedef enum InterruptTypes
{
kSerialInterrupts = 0, kTxDMAInterrupts = 1, kRxDMAInterrupts = 2, kNoInterrupts = 3,
kTxInterrupts = 4, kRxInterrupts = 5,
kSccInterrupts = 6, kAllInterrupts = 7 } InterruptTypes;
typedef enum SCCInterruptSource
{
kSccTransmitInterrupt = 0, kSccExtStatusInterrupt = 1, kSccReceiveInterrupt = 2, kSccReceiveErrorInterrupt = 3, kSccInterruptSources = 4 } SCCInterruptSource;
typedef enum Machine_Type
{
kUnknownMachine = 0,
k5300Machine, k6100Machine, k7100Machine,
k8100Machine,
k7500Machine, k8500Machine,
k9500Machine,
ke407Machine } Machine_Type;
enum SerialOffsets
{
channelADataOffset = 6, channelAControlOffset = 2, channelBDataOffset = 4, channelBControlOffset = 0,
channelADataOffsetRISC = 0x30, channelAControlOffsetRISC = 0x20, channelBDataOffsetRISC = 0x10, channelBControlOffsetRISC = 0 };
#define channelDataOffsetRISC 0x010
#define channelControlOffsetRISC 0x000
#define channelDataOffset 4
#define channelControlOffset 0
enum InterruptAssignments
{
kIntChipSet = 0,
kIntTxDMA,
kIntRxDMA,
MaxInterrupts
};
#define DMABufferSize 4096
enum ParityType
{
NoParity = 0,
OddParity,
EvenParity,
MaxParity
};
enum SerialPortSelector
{
serialPortA = 0,
serialPortB = 1,
MaxPortsPerChip = 2
};
#define ChannelAName "ch-a"
#define ChannelBName "ch-b"
#define kDefaultBaudRate 9600
#define kMaxBaudRate 230400
#define kMaxCirBufferSize 4096
#define MAX_BLOCK_SIZE PAGE_SIZE
typedef struct SerialDBDMAStatusInfo
{
IODBDMAChannelRegisters *dmaBase;
IODBDMAChannelRegisters *dmaChannelAddress;
IODBDMADescriptor *dmaChannelCommandArea;
UInt32 dmaNumberOfDescriptors;
#if NEWPHYS
IOBufferMemoryDescriptor *dmaChannelCommandAreaMDP;
#endif
UInt8 *dmaTransferBuffer;
UInt32 dmaTransferSize;
#if NEWPHYS
IOBufferMemoryDescriptor *dmaTransferBufferMDP;
#endif
UInt32 lastPosition;
} SerialDBDMAStatusInfo;
typedef struct {
UInt32 ints;
UInt32 txInts;
UInt32 rxInts;
UInt32 mdmInts;
UInt32 txChars;
UInt32 rxChars;
} Stats_t;
typedef struct BufferMarks {
UInt32 BufferSize;
UInt32 HighWater;
UInt32 LowWater;
bool OverRun;
} BufferMarks;
typedef struct
{
UInt32 Instance;
unsigned const char *PortName;
UInt32 State;
UInt32 WatchStateMask;
OSObject *RS232;
CirQueue RX;
CirQueue TX;
BufferMarks RXStats;
BufferMarks TXStats;
IOLock *IODBDMARxLock;
IOLock *IODBDMATrLock;
IOLock *SCCAccessLock;
UInt32 Base;
UInt32 CharLength;
UInt32 StopBits;
UInt32 TX_Parity;
UInt32 RX_Parity;
UInt32 BreakLength;
UInt32 BaudRate;
unsigned short DLRimage;
UInt8 LCRimage;
UInt8 FCRimage;
UInt8 IERmask;
UInt8 RBRmask;
UInt32 MasterClock;
bool MinLatency;
bool WaitingForTXIdle;
UInt8 XONchar;
UInt8 XOFFchar;
UInt32 SWspecial[(0x100)>>SPECIAL_SHIFT];
UInt32 FlowControl; UInt32 FlowControlState;
bool DCDState;
bool CTSState;
int RXOstate; int TXOstate; UInt8 xOffSent;
UInt32 GlobalRecvChars;
UInt32 OverRunChars;
bool BreakState;
mach_timespec DataLatInterval;
mach_timespec CharLatInterval;
Stats_t Stats;
bool AreTransmitting;
bool GotTXInterrupt;
bool baudRateGeneratorEnable;
UInt8 baudRateGeneratorLo;
UInt8 baudRateGeneratorHi;
UInt32 rtxcFrequency;
UInt8 lastWR[kNumSCCWR];
UInt8 *ControlRegister;
UInt8 *DataRegister;
IOPhysicalAddress ChipBaseAddress;
UInt32 ConfigWriteRegister;
SerialPortSelector whichPort;
IOPhysicalAddress TxDMABase;
UInt32 TxDMALength;
IOPhysicalAddress RxDMABase;
UInt32 RxDMALength;
UInt8 InterruptNumbers[MaxInterrupts];
UInt8 ourReceiveBits;
UInt8 ourTransmitBits;
UInt8 ourClockSource;
bool haveQueuedRxSIH;
bool haveQueuedTxSIH;
SerialDBDMAStatusInfo TxDBDMAChannel;
SerialDBDMAStatusInfo RxDBDMAChannel;
bool DTRAsserted;
bool aboveRxHighWater;
bool lastCTSState;
UInt32 lastCTSTime;
UInt32 ctsTransitionCount;
IOTimerEventSource *rxTimer;
} PortInfo_t, SccChannel;
extern vm_map_t kernel_map;
static inline UInt32 tval2long(mach_timespec val)
{
return ((val.tv_sec *NSEC_PER_SEC) + val.tv_nsec);
}
static inline mach_timespec long2tval(UInt32 val)
{
mach_timespec tval;
tval.tv_sec = val / NSEC_PER_SEC;
tval.tv_nsec = val % NSEC_PER_SEC;
return tval;
}
#include "SccChip.h"
#if LOG_DATA
UInt8 Asciify(UInt8 i);
void SerialLogData(UInt8 Dir, UInt32 Count, char *buf);
#endif
class AppleRS232Serial : public IOSerialDriverSync
{
OSDeclareDefaultStructors(AppleRS232Serial)
protected:
bool portOpened;
AbsoluteTime startingTime;
public:
IOWorkLoop *fWorkLoop; IOCommandGate *fCommandGate; IOTimerEventSource *fTimer; UInt32 fCounter;
PortInfo_t fPort;
IOService *fProvider;
#if USE_WORK_LOOPS
IOInterruptEventSource *sccInterruptSource;
#if USE_FILTER_EVENT_SOURCES
IOFilterInterruptEventSource *txDMAInterruptSource;
IOFilterInterruptEventSource *rxDMAInterruptSource;
#else
IOInterruptEventSource *txDMAInterruptSource;
IOInterruptEventSource *rxDMAInterruptSource;
#endif
#endif
virtual IOReturn acquirePort(bool sleep, void *refCon);
virtual IOReturn releasePort(void *refCon);
virtual UInt32 getState(void *refCon);
virtual IOReturn setState(UInt32 state, UInt32 mask, void *refCon);
virtual IOReturn watchState(UInt32 *state, UInt32 mask, void *refCon);
virtual UInt32 nextEvent(void *refCon);
virtual IOReturn executeEvent(UInt32 event, UInt32 data, void *refCon);
virtual IOReturn requestEvent(UInt32 event, UInt32 *data, void *refCon);
virtual IOReturn enqueueEvent(UInt32 event, UInt32 data, bool sleep, void *refCon);
virtual IOReturn dequeueEvent(UInt32 *event, UInt32 *data, bool sleep, void *refCon);
virtual IOReturn enqueueData(UInt8 *buffer, UInt32 size, UInt32 *count, bool sleep, void *refCon);
virtual IOReturn dequeueData(UInt8 *buffer, UInt32 size, UInt32 *count, UInt32 min, void *refCon);
static IOReturn acquirePortAction(OSObject *owner, void *arg0, void *, void *, void *);
static IOReturn releasePortAction(OSObject *owner, void *, void *, void *, void *);
static IOReturn getStateAction(OSObject *owner, void *, void *, void *, void *);
static IOReturn setStateAction(OSObject *owner, void *arg0, void *arg1, void *, void *);
static IOReturn watchStateAction(OSObject *owner, void *arg0, void *arg1, void *, void *);
static IOReturn executeEventAction(OSObject *owner, void *arg0, void *arg1, void *, void *);
static IOReturn enqueueEventAction(OSObject *owner, void *arg0, void *arg1, void *, void *);
static IOReturn enqueueDataAction(OSObject *owner, void *arg0, void *arg1, void *arg2, void *arg3);
static IOReturn dequeueDataAction(OSObject *owner, void *arg0, void *arg1, void *arg2, void *arg3);
virtual IOReturn acquirePortGated(bool sleep);
virtual IOReturn releasePortGated(void);
virtual UInt32 getStateGated(void);
virtual IOReturn setStateGated(UInt32 state, UInt32 mask);
virtual IOReturn watchStateGated(UInt32 *state, UInt32 mask);
virtual IOReturn executeEventGated(UInt32 event, UInt32 data);
virtual IOReturn enqueueDataGated(UInt8 *buffer, UInt32 size, UInt32 *count, bool sleep);
virtual IOReturn dequeueDataGated(UInt8 *buffer, UInt32 size, UInt32 *count, UInt32 min);
virtual bool start(IOService *provider);
virtual void stop(IOService *provider);
void shutDown();
IOReturn sleepThread(void *event);
static void interruptOccurred(OSObject *obj, IOInterruptEventSource *src, int count);
bool createSerialStream(IOService *provider);
static bool allocateRingBuffer(CirQueue *Queue, size_t BufferSize);
static void freeRingBuffer(CirQueue *Queue);
bool initializePort(PortInfo_t *port);
static void setStructureDefaults(PortInfo_t *port);
void CheckQueues(PortInfo_t *port);
static void handleInterrupt(OSObject *target, void *refCon, IOService *nub, int source);
static void handleDBDMATxInterrupt(OSObject *target, void *refCon, IOService *nub, int source);
static void handleDBDMARxInterrupt(OSObject *target, void *refCon, IOService *nub, int source);
static void timeoutHandler(OSObject *owner, IOTimerEventSource *sender);
static bool interruptFilter(OSObject *owner, IOFilterInterruptEventSource *source);
static void interruptHandler(OSObject *owner, IOInterruptEventSource *source, int count);
};
#endif