AppleRS232Serial.cpp [plain text]
#include <libkern/OSByteOrder.h>
#include <IOKit/IOLib.h>
#include <IOKit/IOReturn.h>
#include <IOKit/IOKitKeys.h>
#include <IOKit/IOPlatformExpert.h>
#include <IOKit/IODeviceTreeSupport.h>
#include <IOKit/serial/IOSerialKeys.h>
#include "AppleRS232Serial.h"
#if USE_ELG
com_apple_iokit_XTrace *gXTrace = 0;
UInt32 gTraceID;
#endif
#define super IOSerialDriverSync
OSDefineMetaClassAndStructors(AppleRS232Serial, IOSerialDriverSync);
#if USE_ELG
#define DEBUG_NAME "AppleRS232Serial"
IOReturn KernelDebugFindKernelLogger()
{
OSIterator *iterator = NULL;
OSDictionary *matchingDictionary = NULL;
IOReturn error = 0;
matchingDictionary = IOService::serviceMatching("com_apple_iokit_XTrace");
if (!matchingDictionary)
{
error = kIOReturnError;
IOLog(DEBUG_NAME "[FindKernelLogger] Couldn't create a matching dictionary.\n");
goto exit;
}
iterator = IOService::getMatchingServices(matchingDictionary);
if (!iterator)
{
error = kIOReturnError;
IOLog(DEBUG_NAME "[FindKernelLogger] No XTrace logger found.\n");
goto exit;
}
gXTrace = (com_apple_iokit_XTrace*)iterator->getNextObject();
if (gXTrace)
{
IOLog(DEBUG_NAME "[FindKernelLogger] Found XTrace logger at %p.\n", gXTrace);
}
exit:
if (error != kIOReturnSuccess)
{
gXTrace = NULL;
IOLog(DEBUG_NAME "[FindKernelLogger] Could not find a logger instance. Error = %X.\n", error);
}
if (matchingDictionary)
matchingDictionary->release();
if (iterator)
iterator->release();
return error;
}
#endif
#if LOG_DATA
#define dumplen 32 // Set this to the number of bytes to dump and the rest should work out correct
#define buflen ((dumplen*2)+dumplen)+3
#define Asciistart (dumplen*2)+3
UInt8 Asciify(UInt8 i)
{
i &= 0xF;
if ( i < 10 )
return( '0' + i );
else return( 55 + i );
}
void SerialLogData(UInt8 Dir, UInt32 Count, char *buf)
{
SInt32 wlen;
#if USE_ELG
UInt8 *b;
UInt8 w[8];
#else
UInt32 llen, rlen;
UInt16 i, Aspnt, Hxpnt;
UInt8 wchr;
char LocBuf[buflen+1];
#endif
switch (Dir)
{
case kSerialIn:
#if USE_ELG
XTRACE2(buf, Count, "SerialLogData - Read Complete, address, size");
#else
IOLog( "AppleRS232Serial: SerialLogData - Read Complete, address = %8x, size = %8d\n", (UInt)buf, (UInt)Count );
#endif
break;
case kSerialOut:
#if USE_ELG
XTRACE2(buf, Count, "SerialLogData - Write, address, size");
#else
IOLog( "AppleRS232Serial: SerialLogData - Write, address = %8x, size = %8d\n", (UInt)buf, (UInt)Count );
#endif
break;
case kSerialOther:
#if USE_ELG
XTRACE2(buf, Count, "SerialLogData - Other, address, size");
#else
IOLog( "AppleRS232Serial: SerialLogData - Other, address = %8x, size = %8d\n", (UInt)buf, (UInt)Count );
#endif
break;
}
#if DUMPALL
wlen = Count;
#else
if (Count > dumplen)
{
wlen = dumplen;
} else {
wlen = Count;
}
#endif
if (wlen == 0)
{
#if USE_ELG
XTRACE2(0, Count, "SerialLogData - No data, Count=0");
#else
IOLog( "AppleRS232Serial: SerialLogData - No data, Count=0\n" );
#endif
return;
}
#if (USE_ELG)
b = (UInt8 *)buf;
while (wlen > 0) {
bzero(w, sizeof(w)); bcopy(b, w, min(wlen, 8));
switch (Dir)
{
case kSerialIn:
XTRACE2((w[0] << 24 | w[1] << 16 | w[2] << 8 | w[3]), (w[4] << 24 | w[5] << 16 | w[6] << 8 | w[7]), "SerialLogData - Rx buffer dump");
break;
case kSerialOut:
XTRACE2((w[0] << 24 | w[1] << 16 | w[2] << 8 | w[3]), (w[4] << 24 | w[5] << 16 | w[6] << 8 | w[7]), "SerialLogData - Tx buffer dump");
break;
case kSerialOther:
XTRACE2((w[0] << 24 | w[1] << 16 | w[2] << 8 | w[3]), (w[4] << 24 | w[5] << 16 | w[6] << 8 | w[7]), "SerialLogData - Misc buffer dump");
break;
}
wlen -= 8; b += 8;
}
#else
rlen = 0;
do
{
for (i=0; i<=buflen; i++)
{
LocBuf[i] = 0x20;
}
LocBuf[i] = 0x00;
if (wlen > dumplen)
{
llen = dumplen;
wlen -= dumplen;
} else {
llen = wlen;
wlen = 0;
}
Aspnt = Asciistart;
Hxpnt = 0;
for (i=1; i<=llen; i++)
{
wchr = buf[i-1];
LocBuf[Hxpnt++] = Asciify(wchr >> 4);
LocBuf[Hxpnt++] = Asciify(wchr);
if ((wchr < 0x20) || (wchr > 0x7F)) {
LocBuf[Aspnt++] = 0x2E; } else {
LocBuf[Aspnt++] = wchr;
}
}
LocBuf[(llen + Asciistart) + 1] = 0x00;
IOLog(LocBuf);
IOLog("\n");
IOSleep(Sleep_Time);
rlen += llen;
buf = &buf[rlen];
} while (wlen != 0);
#endif
}
#endif
static inline UInt64 getDebugFlagsTable(OSDictionary *props)
{
OSNumber *debugProp;
UInt64 debugFlags = gIOKitDebug;
debugProp = OSDynamicCast(OSNumber, props->getObject(gIOKitDebugKey));
if (debugProp)
debugFlags = debugProp->unsigned64BitValue();
return debugFlags;
}
bool AppleRS232Serial::start(IOService *provider)
{
IOMemoryMap *map;
IOByteCount temp;
#if USE_ELG
XTraceLogInfo *logInfo;
KernelDebugFindKernelLogger();
if (gXTrace)
{
gXTrace->retain(); gTraceID = gXTrace->GetNewId();
ELG((UInt32)this, 0xbeefbeef, "AppleRS232Serial: Hello from start");
logInfo = gXTrace->LogGetInfo();
IOLog("AppleRS232Serial::start - Log is at %x\n", (unsigned int)logInfo);
} else {
return false;
}
#endif
ELG(this, provider, "AppleRS232Serial::start - this, provider");
if (!super::start(provider))
{
ALERT(0, 0, "AppleRS232Serial::start - super failed");
return false;
}
fProvider = OSDynamicCast(AppleMacIODevice, provider);
if (!fProvider)
{
ALERT(0, 0, "AppleRS232Serial::start - provider invalid");
return false;
}
{
UInt32 debugFlags;
if (!PE_parse_boot_arg("debug", &debugFlags))
debugFlags = 0;
if (debugFlags & 8)
{
ALERT(0, 0, "AppleRS232Serial::start - returning false early, Serial debugging is enabled");
return false;
}
}
fPort.whichPort = serialPortA;
fWorkLoop = getWorkLoop();
if (!fWorkLoop)
{
ALERT(0, 0, "AppleRS232Serial::start - getWorkLoop failed");
return false;
}
fWorkLoop->retain();
fCommandGate = IOCommandGate::commandGate(this);
if (!fCommandGate)
{
ALERT(0, 0, "AppleRS232Serial::start - commandGate failed");
shutDown();
return false;
}
if (fWorkLoop->addEventSource(fCommandGate) != kIOReturnSuccess)
{
ALERT(0, 0, "AppleRS232Serial::start - addEventSource(commandGate) failed");
shutDown();
return false;
}
fCommandGate->enable();
fPort.DTRAsserted = true; fPort.xOffSent = false; fPort.RTSAsserted = true; fPort.aboveRxHighWater = false;
if (!initializePort(&fPort)) {
ALERT(0, 0, "AppleRS232Serial::start - Initialize port failed");
shutDown();
return false;
}
setStructureDefaults(&fPort);
fPort.RS232 = this;
map = provider->mapDeviceMemoryWithIndex(0);
if (!map)
{
ALERT(0, 0, "AppleRS232Serial::start - Mapping device memory failed");
shutDown();
return false;
}
fPort.ChipBaseAddress = map->getVirtualAddress(); fPort.ChipBaseAddressPhysical = map->getPhysicalSegment(0, &temp);
ALERT(fPort.ChipBaseAddress, fPort.ChipBaseAddressPhysical, "chip base, virtual, physical");
if (!SccSetDMARegisters(&fPort, provider))
{
ALERT(0, 0, "AppleRS232Serial::start - DMA setup failed");
shutDown();
return false;
}
fPort.TXStats.BufferSize = BUFFER_SIZE_DEFAULT;
fPort.RXStats.BufferSize = BUFFER_SIZE_DEFAULT;
initChip(&fPort);
sccInterruptSource = IOInterruptEventSource::interruptEventSource(this, (IOInterruptEventAction)&AppleRS232Serial::interruptHandler,
provider, kIntChipSet);
if (!sccInterruptSource)
{
ALERT(0, 0, "AppleRS232Serial::start - Interrupt event source failed");
shutDown();
return false;
}
if (fWorkLoop->addEventSource(sccInterruptSource) != kIOReturnSuccess)
{
ALERT(0, 0, "AppleRS232Serial::start - Add interrupt source to work loop failed");
shutDown();
}
#if USE_FILTER_EVENT_SOURCES
txDMAInterruptSource = IOFilterInterruptEventSource::filterInterruptEventSource(this, (IOInterruptEventAction) &AppleRS232Serial::interruptHandler,
(IOFilterInterruptAction) &AppleRS232Serial::interruptFilter, provider, kIntTxDMA);
#else
txDMAInterruptSource = IOInterruptEventSource::interruptEventSource(this, (IOInterruptEventAction)&AppleRS232Serial::interruptHandler, provider, kIntTxDMA);
#endif
if (!txDMAInterruptSource)
{
ALERT(0, 0, "AppleRS232Serial::start - TX DMA interrupt event source failed");
shutDown();
return false;
}
if (fWorkLoop->addEventSource(txDMAInterruptSource) != kIOReturnSuccess)
{
ALERT(0, 0, "AppleRS232Serial::start - Add TX DMA interrupt event source to work loop failed");
shutDown();
return false;
}
#if USE_FILTER_EVENT_SOURCES
rxDMAInterruptSource = IOFilterInterruptEventSource::filterInterruptEventSource(this, (IOInterruptEventAction) &AppleRS232Serial::interruptHandler,
(IOFilterInterruptAction) &AppleRS232Serial::interruptFilter, provider, kIntRxDMA);
#else
rxDMAInterruptSource = IOInterruptEventSource::interruptEventSource(this, (IOInterruptEventAction)&AppleRS232Serial::interruptHandler, provider, kIntRxDMA);
#endif
if (!rxDMAInterruptSource)
{
ALERT(0, 0, "AppleRS232Serial::start - RX DMA interrupt event source failed");
shutDown();
return false;
}
if (fWorkLoop->addEventSource(rxDMAInterruptSource) != kIOReturnSuccess)
{
ALERT(0, 0, "AppleRS232Serial::start - Add RX DMA interrupt event source to work loop failed");
shutDown();
return false;
}
fPort.rxTimer = IOTimerEventSource::timerEventSource(this, rxTimeoutHandler);
if( !fPort.rxTimer )
{
ALERT(0, 0, "AppleRS232Serial::start - Timer event source failed");
shutDown();
return false;
}
if (fWorkLoop->addEventSource(fPort.rxTimer) != kIOReturnSuccess)
{
ALERT(0, 0, "AppleRS232Serial::start - Add timer event source to work loop failed");
shutDown();
return false;
}
if (!allocateRingBuffer(&(fPort.TX), fPort.TXStats.BufferSize, fWorkLoop) ||
!allocateRingBuffer(&(fPort.RX), fPort.RXStats.BufferSize, fWorkLoop))
{
ELG(0, 0, "AppleRS232Serial::start - Allocate for ring buffers failed");
shutDown();
return false;
}
callPlatformFunction("EnableSCC", false, (void *)true, 0, 0, 0);
fdmaStartTransmissionThread = thread_call_allocate (
&SccStartTransmissionDelayedHandler, ( thread_call_param_t ) this);
if ( fdmaStartTransmissionThread == NULL )
{
return false;
}
dmaRxHandleCurrentPositionThread = thread_call_allocate (
&SccCurrentPositionDelayedHandler, ( thread_call_param_t ) this);
if ( dmaRxHandleCurrentPositionThread == NULL )
{
return false;
}
if (!createSerialStream(provider))
{
ALERT(0, 0, "AppleRS232Serial::start - Create serial stream failed");
shutDown();
return false;
}
fCurrentPowerState = 1; if (!initForPM(provider)) {
ALERT(0, 0, "AppleRS232Serial::start - failed to init for power management");
shutDown();
return false;
}
ELG(0, 0, "AppleRS232Serial::start - Successful");
return true;
}
void AppleRS232Serial::stop(IOService *provider)
{
ELG(0, 0, "AppleRS232Serial::stop");
PMstop();
shutDown();
super::stop(provider);
}
IOWorkLoop* AppleRS232Serial::getWorkLoop() const
{
IOWorkLoop *w;
if (fWorkLoop) w = fWorkLoop;
else w = IOWorkLoop::workLoop();
ELG(0, w, "get workloop, workloop=");
return w;
}
IOReturn AppleRS232Serial::acquirePort(bool sleep, void *refCon)
{
IOReturn ret;
ELG(0, sleep, "AppleRS232Serial::acquirePort");
retain();
ret = fCommandGate->runAction(acquirePortAction, (void *)sleep);
release();
return ret;
}
IOReturn AppleRS232Serial::acquirePortAction(OSObject *owner, void *arg0, void *, void *, void *)
{
ELG(owner, arg0, "acquirePortAction");
return ((AppleRS232Serial *)owner)->acquirePortGated((bool)arg0);
}
IOReturn AppleRS232Serial::acquirePortGated(bool sleep)
{
UInt32 busyState = 0;
IOReturn rtn = kIOReturnSuccess;
ELG(0, sleep, "AppleRS232Serial::acquirePortGated");
retain(); while (true)
{
busyState = fPort.State & PD_S_ACQUIRED;
if (!busyState)
{
setStateGated((UInt32)PD_S_ACQUIRED | DEFAULT_STATE, (UInt32)STATE_ALL);
break;
} else {
if (!sleep)
{
ELG(0, 0, "AppleRS232Serial::acquirePortGated - Busy exclusive access");
release();
return kIOReturnExclusiveAccess;
} else {
busyState = 0;
rtn = watchStateGated(&busyState, PD_S_ACQUIRED);
if ((rtn == kIOReturnIOError) || (rtn == kIOReturnSuccess))
{
continue;
} else {
ELG( 0, 0, "AppleRS232Serial::acquirePortGated - Interrupted!" );
release();
return rtn;
}
}
}
}
do
{
if (!fProvider->open(this))
{
rtn = kIOReturnBusy;
ELG(0, rtn, "AppleRS232Serial::acquirePortGated - Open for provider failed");
break;
}
setStructureDefaults(&fPort);
ResetQueue(&fPort.TX);
ResetQueue(&fPort.RX);
OpenScc(&fPort);
SccSetupReceptionChannel(&fPort, 0);
SccSetupReceptionChannel(&fPort, 1);
SccSetupTansmissionChannel(&fPort);
SccdbdmaDefineTansmissionCommands(&fPort);
sccInterruptSource->enable();
txDMAInterruptSource->enable();
rxDMAInterruptSource->enable();
SccdbdmaStartReception(&fPort, fPort.activeRxChannelIndex, true);
portOpened = true;
clock_get_uptime(&startingTime);
ELG(0, 0, "AppleRS232Serial::acquirePortGated - Successful");
return kIOReturnSuccess;
} while (0);
fProvider->close(this);
setStateGated(0, STATE_ALL); release();
ELG(0, rtn, "AppleRS232Serial::acquirePortGated - failed");
return rtn;
}
IOReturn AppleRS232Serial::releasePort(void *refCon)
{
IOReturn ret;
ELG(0, 0, "AppleRS232Serial::releasePort");
retain();
ret = fCommandGate->runAction(releasePortAction);
release();
return ret;
}
IOReturn AppleRS232Serial::releasePortAction(OSObject *owner, void *, void *, void *, void *)
{
ELG(0, 0, "releasePortAction");
return ((AppleRS232Serial *)owner)->releasePortGated();
}
IOReturn AppleRS232Serial::releasePortGated()
{
UInt32 busyState = 0;
int i;
ELG(0, 0, "AppleRS232Serial::releasePortGated");
busyState = fPort.State & PD_S_ACQUIRED;
if (!busyState)
{
ELG( 0, 0, "AppleRS232Serial::releasePortGated - NOT OPEN" );
return kIOReturnNotOpen;
}
for (i=0; i<(256>>SPECIAL_SHIFT); i++)
{
fPort.SWspecial[i] = 0;
}
fPort.CharLength = 8;
fPort.XONchar = '\x11';
fPort.XOFFchar = '\x13';
fPort.StopBits = 1<<1;
fPort.TX_Parity = PD_RS232_PARITY_NONE;
fPort.RX_Parity = PD_RS232_PARITY_DEFAULT;
fPort.RXOstate = IDLE_XO;
fPort.BaudRate = kDefaultBaudRate;
fPort.FlowControl = DEFAULT_NOTIFY;
fPort.FlowControlState = CONTINUE_SEND;
fPort.DCDState = false;
fPort.BreakState = false;
fPort.xOffSent = false;
fPort.RTSAsserted = true;
fPort.DTRAsserted = true;
SccCloseChannel(&fPort);
sccInterruptSource->disable();
txDMAInterruptSource->disable();
rxDMAInterruptSource->disable();
fProvider->close(this);
setStateGated(0, STATE_ALL);
portOpened = false;
release();
ELG( 0, 0, "AppleRS232Serial::releasePortGated - OK" );
return kIOReturnSuccess;
}
UInt32 AppleRS232Serial::getState(void *refCon)
{
UInt32 currState;
ELG(0, 0, "AppleRS232Serial::getState");
retain();
currState = fCommandGate->runAction(getStateAction);
release();
return currState;
}
IOReturn AppleRS232Serial::getStateAction(OSObject *owner, void *, void *, void *, void *)
{
UInt32 newState;
ELG(0, 0, "getStateAction");
newState = ((AppleRS232Serial *)owner)->getStateGated();
return newState;
}
UInt32 AppleRS232Serial::getStateGated()
{
UInt32 state;
ELG(0, 0, "AppleRS232Serial::getStateGated");
CheckQueues(&fPort);
state = fPort.State;
ELG(0, state, "AppleRS232Serial::getStateGated - Exit");
return state;
}
IOReturn AppleRS232Serial::setState(UInt32 state, UInt32 mask, void *refCon)
{
IOReturn ret;
ELG(state, mask, "AppleRS232Serial::setState");
if (mask & (PD_S_ACQUIRED | PD_S_ACTIVE | (~EXTERNAL_MASK)))
{
return kIOReturnBadArgument;
}
mask &= (~fPort.FlowControl & PD_RS232_A_MASK) | PD_S_MASK;
if (mask)
{
retain();
ret = fCommandGate->runAction(setStateAction, (void *)state, (void *)mask);
release();
return ret;
}
return kIOReturnSuccess;
}
IOReturn AppleRS232Serial::setStateAction(OSObject *owner, void *arg0, void *arg1, void *, void *)
{
ELG(0, 0, "setStateAction");
return ((AppleRS232Serial *)owner)->setStateGated((UInt32)arg0, (UInt32)arg1);
}
IOReturn AppleRS232Serial::setStateGated(UInt32 state, UInt32 mask)
{
UInt32 delta;
ELG(state, mask, "AppleRS232Serial::setStateGated");
if ((state & PD_S_ACQUIRED) || (fPort.State & PD_S_ACQUIRED))
{
if ((mask & PD_RS232_S_DTR) && ((fPort.FlowControl & PD_RS232_A_DTR) != PD_RS232_A_DTR))
{
if ((state & PD_RS232_S_DTR) != (fPort.State & PD_RS232_S_DTR))
{
if (state & PD_RS232_S_DTR)
{
SccSetDTR(&fPort, true);
} else {
SccSetDTR(&fPort, false);
}
}
}
state = (fPort.State & ~mask) | (state & mask); delta = state ^ fPort.State; fPort.State = state;
if (delta & fPort.WatchStateMask)
{
fCommandGate->commandWakeup((void *)&fPort.State);
}
return kIOReturnSuccess;
}
return kIOReturnNotOpen;
}
IOReturn AppleRS232Serial::watchState(UInt32 *state, UInt32 mask, void *refCon)
{
IOReturn ret;
ELG(*state, mask, "AppleRS232Serial::watchState");
if (!state)
return kIOReturnBadArgument;
if (!mask)
return kIOReturnSuccess;
retain();
ret = fCommandGate->runAction(watchStateAction, (void *)state, (void *)mask);
release();
return ret;
}
IOReturn AppleRS232Serial::watchStateAction(OSObject *owner, void *arg0, void *arg1, void *, void *)
{
ELG(0, 0, "watchStateAction");
return ((AppleRS232Serial *)owner)->watchStateGated((UInt32 *)arg0, (UInt32)arg1);
}
IOReturn AppleRS232Serial::watchStateGated(UInt32 *state, UInt32 mask)
{
unsigned watchState, foundStates;
bool autoActiveBit = false;
IOReturn ret = kIOReturnNotOpen;
ELG(*state, mask, "AppleRS232Serial::watchStateGated");
if (fPort.State & PD_S_ACQUIRED)
{
ret = kIOReturnSuccess;
mask &= EXTERNAL_MASK;
watchState = *state;
if (!(mask & (PD_S_ACQUIRED | PD_S_ACTIVE)))
{
watchState &= ~PD_S_ACTIVE; mask |= PD_S_ACTIVE; autoActiveBit = true;
}
while (true)
{
foundStates = (watchState ^ ~fPort.State) & mask;
if (foundStates)
{
*state = fPort.State;
if (autoActiveBit && (foundStates & PD_S_ACTIVE))
{
ret = kIOReturnIOError;
} else {
ret = kIOReturnSuccess;
}
break;
}
fPort.WatchStateMask |= mask;
retain(); fCommandGate->retain();
ret = fCommandGate->commandSleep((void *)&fPort.State);
fCommandGate->retain();
if (ret == THREAD_TIMED_OUT)
{
ret = kIOReturnTimeout;
break;
} else {
if (ret == THREAD_INTERRUPTED)
{
ret = kIOReturnAborted;
break;
}
}
release();
}
fPort.WatchStateMask = 0;
fCommandGate->commandWakeup((void *)&fPort.State);
*state &= EXTERNAL_MASK;
}
ELG(0, ret, "AppleRS232Serial::watchStateGated - Return code on exit" );
return ret;
}
UInt32 AppleRS232Serial::nextEvent(void *refCon)
{
UInt32 ret = kIOReturnSuccess;
ELG( 0, 0, "AppleRS232Serial::nextEvent" );
return ret;
}
IOReturn AppleRS232Serial::executeEvent(UInt32 event, UInt32 data, void *refCon)
{
IOReturn ret;
ELG(event, data, "AppleRS232Serial::executeEvent");
retain();
ret = fCommandGate->runAction(executeEventAction, (void *)event, (void *)data);
release();
return ret;
}
IOReturn AppleRS232Serial::executeEventAction(OSObject *owner, void *arg0, void *arg1, void *, void *)
{
ELG(0, 0, "executeEventAction");
return ((AppleRS232Serial *)owner)->executeEventGated((UInt32)arg0, (UInt32)arg1);
}
IOReturn AppleRS232Serial::executeEventGated(UInt32 event, UInt32 data)
{
IOReturn ret = kIOReturnSuccess;
UInt32 state, delta, old;
delta = 0;
state = fPort.State;
ELG(0, state, "AppleRS232Serial::executeEventGated");
if ((state & PD_S_ACQUIRED) == 0)
return kIOReturnNotOpen;
switch ( event )
{
case PD_RS232_E_XON_BYTE:
ELG(data, event, "AppleRS232Serial::executeEventGated - PD_RS232_E_XON_BYTE");
fPort.XONchar = data;
break;
case PD_RS232_E_XOFF_BYTE:
ELG(data, event, "AppleRS232Serial::executeEventGated - PD_RS232_E_XOFF_BYTE");
fPort.XOFFchar = data;
break;
case PD_E_SPECIAL_BYTE:
ELG(data, event, "AppleRS232Serial::executeEventGated - PD_E_SPECIAL_BYTE");
fPort.SWspecial[data >> SPECIAL_SHIFT] |= (1 << (data & SPECIAL_MASK));
break;
case PD_E_VALID_DATA_BYTE:
ELG(data, event, "AppleRS232Serial::executeEventGated - PD_E_VALID_DATA_BYTE");
fPort.SWspecial[data >> SPECIAL_SHIFT] &= ~(1 << (data & SPECIAL_MASK));
break;
case PD_E_FLOW_CONTROL:
ELG(data, event, "AppleRS232Serial::executeEventGated - PD_E_FLOW_CONTROL");
old = fPort.FlowControl; fPort.FlowControl = data & (CAN_BE_AUTO | CAN_NOTIFY);
if (portOpened && old && (old ^ fPort.FlowControl)) {
#define SwitchingAwayFrom(flag) ((old & flag) && !(fPort.FlowControl & flag))
if (SwitchingAwayFrom(PD_RS232_A_RXO) && fPort.xOffSent)
{
AddBytetoQueue(&(fPort.TX), fPort.XONchar);
fPort.xOffSent = false;
SetUpTransmit(&fPort);
}
if (SwitchingAwayFrom(PD_RS232_A_RTS) && !fPort.RTSAsserted)
{
fPort.RTSAsserted = true;
SccSetRTS(&fPort, true); }
if (SwitchingAwayFrom(PD_RS232_A_DTR) && !fPort.DTRAsserted)
{
fPort.DTRAsserted = true;
SccSetDTR(&fPort, true); }
if (SwitchingAwayFrom(PD_RS232_S_CTS) && fPort.FlowControlState != CONTINUE_SEND)
{
fPort.FlowControlState = CONTINUE_SEND;
IODBDMAContinue(fPort.TxDBDMAChannel.dmaBase); }
if (SwitchingAwayFrom(PD_RS232_S_TXO) && fPort.RXOstate == NEEDS_XON)
{
fPort.RXOstate = NEEDS_XOFF;
fPort.FlowControlState = CONTINUE_SEND;
IODBDMAContinue(fPort.TxDBDMAChannel.dmaBase); }
}
break;
case PD_E_ACTIVE:
ELG( data, event, "AppleRS232Serial::executeEventGated - PD_E_ACTIVE");
if ((bool)data)
{
if (!(fPort.State & PD_S_ACTIVE))
{
setStructureDefaults(&fPort);
setStateGated(PD_S_ACTIVE, PD_S_ACTIVE);
}
} else {
setStateGated(0, PD_S_ACTIVE); SccCloseChannel(&fPort); }
break;
case PD_E_DATA_LATENCY:
ELG(data, event, "AppleRS232Serial::executeEventGated - PD_E_DATA_LATENCY");
fPort.DataLatInterval = long2tval(data * 1000);
break;
case PD_RS232_E_MIN_LATENCY:
ELG(data, event, "AppleRS232Serial::executeEventGated - PD_RS232_E_MIN_LATENCY");
fPort.MinLatency = bool(data);
break;
case PD_E_DATA_INTEGRITY:
ELG(data, event, "AppleRS232Serial::executeEventGated - PD_E_DATA_INTEGRITY");
if ((data < PD_RS232_PARITY_NONE) || (data > PD_RS232_PARITY_SPACE))
{
ret = kIOReturnBadArgument;
} else {
fPort.TX_Parity = data;
fPort.RX_Parity = PD_RS232_PARITY_DEFAULT;
if (!SccSetParity(&fPort, (ParityType)data))
{
ret = kIOReturnBadArgument;
ELG(0, 0, "AppleRS232Serial::executeEventGated - SccSetParity failed");
}
}
break;
case PD_E_DATA_RATE:
ELG(data, event, "AppleRS232Serial::executeEventGated - PD_E_DATA_RATE");
data >>= 1; ELG(0, data, "AppleRS232Serial::executeEventGated - actual data rate");
if ((data < MIN_BAUD) || (data > kMaxBaudRate))
{
ret = kIOReturnBadArgument;
} else {
fPort.BaudRate = data;
if (!SccSetBaud(&fPort, data))
{
ret = kIOReturnBadArgument;
ELG(0, 0, "AppleRS232Serial::executeEventGated - SccSetBaud failed");
}
}
break;
case PD_E_DATA_SIZE:
ELG(data, event, "AppleRS232Serial::executeEventGated - PD_E_DATA_SIZE");
data >>= 1; ELG(0, data, "AppleRS232Serial::executeEventGated - actual data size");
if ((data < 5) || (data > 8))
{
ret = kIOReturnBadArgument;
} else {
fPort.CharLength = data;
if (!SccSetDataBits(&fPort, data))
{
ret = kIOReturnBadArgument;
ELG(0, 0, "AppleRS232Serial::executeEventGated - SccSetDataBits failed");
}
}
break;
case PD_RS232_E_STOP_BITS:
ELG(data, event, "AppleRS232Serial::executeEventGated - PD_RS232_E_STOP_BITS");
if ((data < 0) || (data > 20))
{
ret = kIOReturnBadArgument;
} else {
fPort.StopBits = data;
if (!SccSetStopBits(&fPort, data))
{
ret = kIOReturnBadArgument;
ELG(0, 0, "AppleRS232Serial::executeEventGated - SccSetStopBits failed");
}
}
break;
case PD_E_RXQ_FLUSH:
ELG(data, event, "AppleRS232Serial::executeEventGated - PD_E_RXQ_FLUSH");
break;
case PD_E_RX_DATA_INTEGRITY:
ELG(data, event, "AppleRS232Serial::executeEventGated - PD_E_RX_DATA_INTEGRITY");
if ((data != PD_RS232_PARITY_DEFAULT) && (data != PD_RS232_PARITY_ANY))
{
ret = kIOReturnBadArgument;
} else {
fPort.RX_Parity = data;
}
break;
case PD_E_RX_DATA_RATE:
ELG(data, event, "AppleRS232Serial::executeEventGated - PD_E_RX_DATA_RATE");
if (data)
{
ret = kIOReturnBadArgument;
}
break;
case PD_E_RX_DATA_SIZE:
ELG(data, event, "AppleRS232Serial::executeEventGated - PD_E_RX_DATA_SIZE");
if (data)
{
ret = kIOReturnBadArgument;
}
break;
case PD_RS232_E_RX_STOP_BITS:
ELG(data, event, "AppleRS232Serial::executeEventGated - PD_RS232_E_RX_STOP_BITS");
if (data)
{
ret = kIOReturnBadArgument;
}
break;
case PD_E_TXQ_FLUSH:
ELG(data, event, "AppleRS232Serial::executeEventGated - PD_E_TXQ_FLUSH");
break;
case PD_RS232_E_LINE_BREAK:
ELG(data, event, "AppleRS232Serial::executeEventGated - PD_RS232_E_LINE_BREAK");
state &= ~PD_RS232_S_BRK;
delta |= PD_RS232_S_BRK;
if (data)
{
fPort.BreakState = true;
} else {
fPort.BreakState = false;
}
SccSetBreak(&fPort, data);
setStateGated(state, delta);
break;
case PD_E_DELAY:
ELG(data, event, "AppleRS232Serial::executeEventGated - PD_E_DELAY");
if (fPort.BreakState) {
IOSleep(data/1000);
} else {
fPort.CharLatInterval = long2tval(data * 1000);
}
break;
case PD_E_RXQ_SIZE:
ELG( 0, event, "AppleRS232Serial::executeEventGated - PD_E_RXQ_SIZE" );
break;
case PD_E_TXQ_SIZE:
ELG( 0, event, "AppleRS232Serial::executeEventGated - PD_E_TXQ_SIZE" );
break;
case PD_E_RXQ_HIGH_WATER:
ELG( data, event, "AppleRS232Serial::executeEventGated - PD_E_RXQ_HIGH_WATER" );
break;
case PD_E_RXQ_LOW_WATER:
ELG( data, event, "AppleRS232Serial::executeEventGated - PD_E_RXQ_LOW_WATER" );
break;
case PD_E_TXQ_HIGH_WATER:
ELG( data, event, "AppleRS232Serial::executeEventGated - PD_E_TXQ_HIGH_WATER" );
break;
case PD_E_TXQ_LOW_WATER:
ELG( data, event, "AppleRS232Serial::executeEventGated - PD_E_TXQ_LOW_WATER" );
break;
default:
ELG( data, event, "AppleRS232Serial::executeEventGated - unrecognized event" );
ret = kIOReturnBadArgument;
break;
}
return ret;
}
IOReturn AppleRS232Serial::requestEvent(UInt32 event, UInt32 *data, void *refCon)
{
IOReturn ret;
ELG(event, data, "AppleRS232Serial::requestEvent");
retain();
ret = fCommandGate->runAction(requestEventAction, (void *)event, (void *)data);
release();
return ret;
}
IOReturn AppleRS232Serial::requestEventAction(OSObject *owner, void *arg0, void *arg1, void *, void *)
{
ELG(0, 0, "requestEventAction");
return ((AppleRS232Serial *)owner)->requestEventGated((UInt32)arg0, (UInt32 *)arg1);
}
IOReturn AppleRS232Serial::requestEventGated(UInt32 event, UInt32 *data)
{
IOReturn returnValue = kIOReturnSuccess;
ELG(0, 0, "AppleRS232Serial::requestEventGated");
if (data == NULL)
{
ELG(0, event, "AppleRS232Serial::requestEvent - Invalid parameter, data is null");
returnValue = kIOReturnBadArgument;
} else {
switch (event)
{
case PD_E_ACTIVE:
ELG(0, event, "AppleRS232Serial::requestEvent - PD_E_ACTIVE");
*data = bool(getState(&fPort) & PD_S_ACTIVE);
break;
case PD_E_FLOW_CONTROL:
ELG(fPort.FlowControl, event, "AppleRS232Serial::requestEvent - PD_E_FLOW_CONTROL");
*data = fPort.FlowControl;
break;
case PD_E_DELAY:
ELG(0, event, "AppleRS232Serial::requestEvent - PD_E_DELAY");
*data = tval2long(fPort.CharLatInterval) / 1000;
break;
case PD_E_DATA_LATENCY:
ELG(0, event, "AppleRS232Serial::requestEvent - PD_E_DATA_LATENCY");
*data = tval2long(fPort.DataLatInterval) / 1000;
break;
case PD_E_TXQ_SIZE:
ELG(0, event, "AppleRS232Serial::requestEvent - PD_E_TXQ_SIZE");
*data = GetQueueSize(&fPort.TX);
break;
case PD_E_RXQ_SIZE:
ELG(0, event, "AppleRS232Serial::requestEvent - PD_E_RXQ_SIZE");
*data = GetQueueSize(&fPort.RX);
break;
case PD_E_TXQ_LOW_WATER:
ELG(0, event, "AppleRS232Serial::requestEvent - PD_E_TXQ_LOW_WATER");
*data = 0;
returnValue = kIOReturnBadArgument;
break;
case PD_E_RXQ_LOW_WATER:
ELG(0, event, "AppleRS232Serial::requestEvent - PD_E_RXQ_LOW_WATER");
*data = 0;
returnValue = kIOReturnBadArgument;
break;
case PD_E_TXQ_HIGH_WATER:
ELG(0, event, "AppleRS232Serial::requestEvent - PD_E_TXQ_HIGH_WATER");
*data = 0;
returnValue = kIOReturnBadArgument;
break;
case PD_E_RXQ_HIGH_WATER:
ELG(0, event, "AppleRS232Serial::requestEvent - PD_E_RXQ_HIGH_WATER");
*data = 0;
returnValue = kIOReturnBadArgument;
break;
case PD_E_TXQ_AVAILABLE:
ELG(0, event, "AppleRS232Serial::requestEvent - PD_E_TXQ_AVAILABLE");
*data = FreeSpaceinQueue(&fPort.TX);
break;
case PD_E_RXQ_AVAILABLE:
ELG(0, event, "AppleRS232Serial::requestEvent - PD_E_RXQ_AVAILABLE");
*data = UsedSpaceinQueue(&fPort.RX);
break;
case PD_E_DATA_RATE:
ELG(0, event, "AppleRS232Serial::requestEvent - PD_E_DATA_RATE");
*data = fPort.BaudRate << 1;
break;
case PD_E_RX_DATA_RATE:
ELG(0, event, "AppleRS232Serial::requestEvent - PD_E_RX_DATA_RATE");
*data = 0x00;
break;
case PD_E_DATA_SIZE:
ELG(0, event, "AppleRS232Serial::requestEvent - PD_E_DATA_SIZE");
*data = fPort.CharLength << 1;
break;
case PD_E_RX_DATA_SIZE:
ELG(0, event, "AppleRS232Serial::requestEvent - PD_E_RX_DATA_SIZE");
*data = 0x00;
break;
case PD_E_DATA_INTEGRITY:
ELG(0, event, "AppleRS232Serial::requestEvent - PD_E_DATA_INTEGRITY");
*data = fPort.TX_Parity;
break;
case PD_E_RX_DATA_INTEGRITY:
ELG(0, event, "AppleRS232Serial::requestEvent - PD_E_RX_DATA_INTEGRITY");
*data = fPort.RX_Parity;
break;
case PD_RS232_E_STOP_BITS:
ELG(0, event, "AppleRS232Serial::requestEvent - PD_RS232_E_STOP_BITS");
*data = fPort.StopBits << 1;
break;
case PD_RS232_E_RX_STOP_BITS:
ELG(0, event, "AppleRS232Serial::requestEvent - PD_RS232_E_RX_STOP_BITS");
*data = 0x00;
break;
case PD_RS232_E_XON_BYTE:
ELG(0, event, "AppleRS232Serial::requestEvent - PD_RS232_E_XON_BYTE");
*data = fPort.XONchar;
break;
case PD_RS232_E_XOFF_BYTE:
ELG(0, event, "AppleRS232Serial::requestEvent - PD_RS232_E_XOFF_BYTE");
*data = fPort.XOFFchar;
break;
case PD_RS232_E_LINE_BREAK:
ELG(0, event, "AppleRS232Serial::requestEvent - PD_RS232_E_LINE_BREAK");
*data = bool(getState(&fPort) & PD_RS232_S_BRK);
break;
case PD_RS232_E_MIN_LATENCY:
ELG(0, event, "AppleRS232Serial::requestEvent - PD_RS232_E_MIN_LATENCY");
*data = bool(fPort.MinLatency);
break;
default:
ELG(0, event, "AppleRS232Serial::requestEvent - unrecognized event");
returnValue = kIOReturnBadArgument;
break;
}
}
return kIOReturnSuccess;
}
IOReturn AppleRS232Serial::enqueueEvent(UInt32 event, UInt32 data, bool sleep, void *refCon)
{
IOReturn ret;
ELG(data, event, "AppleRS232Serial::enqueueEvent");
retain();
ret = fCommandGate->runAction(enqueueEventAction, (void *)event, (void *)data);
release();
return ret;
}
IOReturn AppleRS232Serial::enqueueEventAction(OSObject *owner, void *arg0, void *arg1, void *, void *)
{
ELG(0, 0, "enqueueEventAction");
return ((AppleRS232Serial *)owner)->executeEventGated((UInt32)arg0, (UInt32)arg1);
}
IOReturn AppleRS232Serial::dequeueEvent(UInt32 *event, UInt32 *data, bool sleep, void *refCon)
{
ELG(0, 0, "AppleRS232Serial::dequeueEvent");
if ((event == NULL) || (data == NULL))
return kIOReturnBadArgument;
return kIOReturnSuccess;
}
IOReturn AppleRS232Serial::enqueueData(UInt8 *buffer, UInt32 size, UInt32 *count, bool sleep, void *refCon)
{
IOReturn ret;
ELG(0, sleep, "AppleRS232Serial::enqueueData");
if (count == NULL || buffer == NULL)
return kIOReturnBadArgument;
retain();
ret = fCommandGate->runAction(enqueueDataAction, (void *)buffer, (void *)size, (void *)count, (void *)sleep);
release();
return ret;
}
IOReturn AppleRS232Serial::enqueueDataAction(OSObject *owner, void *arg0, void *arg1, void *arg2, void *arg3)
{
ELG(0, 0, "enqueueDataAction");
return ((AppleRS232Serial *)owner)->enqueueDataGated((UInt8 *)arg0, (UInt32)arg1, (UInt32 *)arg2, (bool)arg3);
}
IOReturn AppleRS232Serial::enqueueDataGated(UInt8 *buffer, UInt32 size, UInt32 *count, bool sleep)
{
UInt32 state = PD_S_TXQ_LOW_WATER;
IOReturn rtn = kIOReturnSuccess;
ELG(0, sleep, "AppleRS232Serial::enqueueDataGated");
*count = 0;
if (!(fPort.State & PD_S_ACTIVE))
return kIOReturnNotOpen;
*count = AddtoQueue(&fPort.TX, buffer, size);
CheckQueues(&fPort);
if (fPort.FlowControlState == PAUSE_SEND)
{
return kIOReturnSuccess;
}
SetUpTransmit(&fPort);
while ((*count < size) && sleep)
{
state = PD_S_TXQ_LOW_WATER;
rtn = watchStateGated(&state, PD_S_TXQ_LOW_WATER);
if ( rtn != kIOReturnSuccess )
{
ELG( 0, rtn, "AppleRS232Serial::enqueueDataGated - interrupted" );
return rtn;
}
*count += AddtoQueue(&fPort.TX, buffer + *count, size - *count);
CheckQueues(&fPort);
SetUpTransmit(&fPort);
}
ELG(*count, size, "AppleRS232Serial::enqueueDataGated - Count on exit");
return kIOReturnSuccess;
}
IOReturn AppleRS232Serial::dequeueData(UInt8 *buffer, UInt32 size, UInt32 *count, UInt32 min, void *refCon)
{
IOReturn ret;
ELG(0, 0, "AppleRS232Serial::dequeueData");
if ((count == NULL) || (buffer == NULL) || (min > size))
return kIOReturnBadArgument;
retain();
ret = fCommandGate->runAction(dequeueDataAction, (void *)buffer, (void *)size, (void *)count, (void *)min);
release();
return ret;
}
IOReturn AppleRS232Serial::dequeueDataAction(OSObject *owner, void *arg0, void *arg1, void *arg2, void *arg3)
{
ELG(0, 0, "dequeueDataAction");
return ((AppleRS232Serial *)owner)->dequeueDataGated((UInt8 *)arg0, (UInt32)arg1, (UInt32 *)arg2, (UInt32)arg3);
}
IOReturn AppleRS232Serial::dequeueDataGated(UInt8 *buffer, UInt32 size, UInt32 *count, UInt32 min)
{
IOReturn rtn = kIOReturnSuccess;
UInt32 state = 0;
ELG(size, min, "AppleRS232Serial::dequeueDataGated");
*count = 0;
if (!(fPort.State & PD_S_ACTIVE))
return kIOReturnNotOpen;
*count = RemovefromQueue(&fPort.RX, buffer, size);
CheckQueues(&fPort);
while ((min > 0) && (*count < min))
{
state = 0;
rtn = watchStateGated(&state, PD_S_RXQ_EMPTY);
if (rtn != kIOReturnSuccess)
{
ELG(0, rtn, "AppleRS232Serial::dequeueData - Interrupted!");
return rtn;
}
*count += RemovefromQueue(&fPort.RX, buffer + *count, (size - *count));
CheckQueues(&fPort);
}
LogData(kSerialIn, *count, buffer);
ELG(*count, size, "AppleRS232Serial::dequeueData - Count on exit");
return rtn;
}
void AppleRS232Serial::CheckQueues(PortInfo_t *port)
{
UInt32 Used;
UInt32 Free;
UInt32 OldState;
UInt32 DeltaState;
UInt32 SW_FlowControl;
UInt32 RTS_FlowControl;
UInt32 DTR_FlowControl;
ELG(0, 0, "CheckQueues");
OldState = port->State;
Used = UsedSpaceinQueue(&(port->TX));
Free = FreeSpaceinQueue(&(port->TX));
if (Free == 0) {
OldState |= PD_S_TXQ_FULL;
OldState &= ~PD_S_TXQ_EMPTY;
} else {
if (Used == 0)
{
OldState &= ~PD_S_TXQ_FULL;
OldState |= PD_S_TXQ_EMPTY;
} else {
OldState &= ~PD_S_TXQ_FULL;
OldState &= ~PD_S_TXQ_EMPTY;
}
}
if (Used < port->TXStats.LowWater)
{
OldState |= PD_S_TXQ_LOW_WATER;
} else {
OldState &= ~PD_S_TXQ_LOW_WATER;
}
if (Used > port->TXStats.HighWater)
{
OldState |= PD_S_TXQ_HIGH_WATER;
} else {
OldState &= ~PD_S_TXQ_HIGH_WATER;
}
Used = UsedSpaceinQueue(&(port->RX));
Free = FreeSpaceinQueue(&(port->RX));
if (Free == 0)
{
OldState |= PD_S_RXQ_FULL;
OldState &= ~PD_S_RXQ_EMPTY;
} else {
if (Used == 0)
{
OldState &= ~PD_S_RXQ_FULL;
OldState |= PD_S_RXQ_EMPTY;
} else {
OldState &= ~PD_S_RXQ_FULL;
OldState &= ~PD_S_RXQ_EMPTY;
}
}
SW_FlowControl = port->FlowControl & PD_RS232_A_RXO;
RTS_FlowControl = port->FlowControl & PD_RS232_A_RTS;
DTR_FlowControl = port->FlowControl & PD_RS232_A_DTR;
if (Used < port->RXStats.LowWater) {
if ((SW_FlowControl) && (port->xOffSent)) {
port->xOffSent = false;
AddBytetoQueue(&(port->TX), port->XONchar);
SetUpTransmit(port);
}
if (RTS_FlowControl && !port->RTSAsserted) {
port->RTSAsserted = true;
SccSetRTS(port, true);
}
if (DTR_FlowControl && !port->DTRAsserted) {
port->DTRAsserted = true;
SccSetDTR(port, true);
}
OldState |= PD_S_RXQ_LOW_WATER;
} else {
OldState &= ~PD_S_RXQ_LOW_WATER;
}
if (Used > port->RXStats.HighWater) {
if ((SW_FlowControl) && (!port->xOffSent))
{
port->xOffSent = true;
AddBytetoQueue(&(port->TX), port->XOFFchar);
SetUpTransmit(port);
}
if (RTS_FlowControl && port->RTSAsserted)
{
port->RTSAsserted = false;
SccSetRTS(port, false); }
if (DTR_FlowControl && port->DTRAsserted)
{
port->DTRAsserted = false;
SccSetDTR(port, false);
}
OldState |= PD_S_RXQ_HIGH_WATER;
} else {
OldState &= ~PD_S_RXQ_HIGH_WATER;
port->aboveRxHighWater = false;
}
DeltaState = OldState ^ port->State;
setStateGated(OldState, DeltaState);
}
bool AppleRS232Serial::createSerialStream(IOService *provider)
{
IORS232SerialStreamSync *pNub = new IORS232SerialStreamSync;
bool ret;
ELG(0, 0, "AppleRS232Serial::createSerialStream");
if (!pNub)
{
ELG( 0, 0, "AppleRS232Serial::createSerialStream - Create nub failed" );
return false;
}
ret = (pNub->init(0, &fPort) && pNub->attach(this));
pNub->release();
if (!ret)
{
ALERT( ret, 0, "AppleRS232Serial::createSerialStream - Didn't attach to the nub properly" );
return false;
}
pNub->setProperty(kIOTTYBaseNameKey, "serial");
pNub->registerService();
return true;
}
bool AppleRS232Serial::initializePort(PortInfo_t *port)
{
SerialDBDMAStatusInfo *dmaInfo;
IODBDMADescriptor *poolBase;
IODBDMADescriptor *poolPhysical;
IOByteCount temp;
int i;
ELG(0, sizeof(IODBDMADescriptor), "AppleRS232Serial::initializePort");
{
UInt32 bytes_needed = sizeof(IODBDMADescriptor) * (2*kNumberOfRxDBDMACommands + kNumberOfTxDBDMACommands);
port->dmaChannelCommandAreaMDP = IOBufferMemoryDescriptor::withOptions(kIOMemoryPhysicallyContiguous, bytes_needed, sizeof(IODBDMADescriptor)); if (port->dmaChannelCommandAreaMDP == NULL)
{
ALERT(0, 0, "AppleRS232Serial::initializePort - DBDMA command descriptor pool not allocated");
return false;
}
port->dmaChannelCommandAreaMDP->prepare();
poolBase = (IODBDMADescriptor *)port->dmaChannelCommandAreaMDP->getBytesNoCopy();
poolPhysical = (IODBDMADescriptor *)port->dmaChannelCommandAreaMDP->getPhysicalSegment(0, &temp);
if (temp < bytes_needed) return false;
bzero(poolBase, bytes_needed);
}
dmaInfo = &port->TxDBDMAChannel;
ELG(0, dmaInfo, "AppleRS232Serial::initializePort - dmaInfo for TX");
dmaInfo->dmaChannelCommandArea = poolBase;
dmaInfo->dmaChannelCommandAreaPhysical = poolPhysical;
dmaInfo->dmaNumberOfDescriptors = kNumberOfTxDBDMACommands;
poolBase += dmaInfo->dmaNumberOfDescriptors;
poolPhysical += dmaInfo->dmaNumberOfDescriptors;
ELG(dmaInfo->dmaChannelCommandArea, kNumberOfTxDBDMACommands, "AppleRS232Serial::initializePort - TX DMA Channel Command address, count");
dmaInfo->dmaTransferBufferMDP = IOBufferMemoryDescriptor::withOptions(kIOMemoryPhysicallyContiguous, kTxDBDMABufferSize, 1);
if (dmaInfo->dmaTransferBufferMDP == NULL)
{
ALERT(0, kTxDBDMABufferSize, "AppleRS232Serial::initializePort - TX DMA Transfer buffer descriptor not allocated");
return false;
}
dmaInfo->dmaTransferBufferMDP->prepare();
dmaInfo->dmaTransferBuffer = (UInt8 *)dmaInfo->dmaTransferBufferMDP->getBytesNoCopy();
bzero(dmaInfo->dmaTransferBuffer, kTxDBDMABufferSize);
dmaInfo->dmaTransferSize = 0;
ELG(0, dmaInfo->dmaTransferBufferMDP, "AppleRS232Serial::initializePort - TX DMA transfer buffer MDP");
ELG(dmaInfo->dmaTransferBuffer, kTxDBDMABufferSize, "AppleRS232Serial::initializePort - TX DMA transfer buffer and size");
for (i = 0; i < 2; i++) {
dmaInfo = &port->rxDBDMAChannels[i];
ELG(i, dmaInfo, "AppleRS232Serial::initializePort - dmaInfo for RX");
dmaInfo->dmaChannelCommandArea = poolBase;
dmaInfo->dmaChannelCommandAreaPhysical = poolPhysical;
dmaInfo->dmaNumberOfDescriptors = kNumberOfRxDBDMACommands;
poolBase += dmaInfo->dmaNumberOfDescriptors;
poolPhysical += dmaInfo->dmaNumberOfDescriptors;
ELG(dmaInfo->dmaChannelCommandArea, kNumberOfRxDBDMACommands, "AppleRS232Serial::initializePort - RX DMA Channel Command address, count");
dmaInfo->dmaTransferBufferMDP = IOBufferMemoryDescriptor::withOptions(kIOMemoryPhysicallyContiguous, kRxDBDMABufferSize, 1);
if (dmaInfo->dmaTransferBufferMDP == NULL)
{
ALERT(0, i, "AppleRS232Serial::initializePort - RX DMA Transfer buffer descriptor not allocated");
return false;
}
dmaInfo->dmaTransferBufferMDP->prepare();
dmaInfo->dmaTransferBuffer = (UInt8 *)dmaInfo->dmaTransferBufferMDP->getBytesNoCopy();
bzero(dmaInfo->dmaTransferBuffer, kRxDBDMABufferSize);
dmaInfo->dmaTransferSize = 0;
ELG(i, dmaInfo->dmaTransferBufferMDP, "AppleRS232Serial::initializePort - RX DMA transfer buffer MDP");
ELG(dmaInfo->dmaTransferBuffer, dmaInfo->dmaNumberOfDescriptors, "AppleRS232Serial::initializePort - RX DMA transfer buffer and size");
}
port->activeRxChannelIndex = 0;
port->DataLatInterval.tv_sec = 0;
port->DataLatInterval.tv_nsec = 0;
port->CharLatInterval.tv_sec = 0;
port->CharLatInterval.tv_nsec = 0;
port->State = (PD_S_TXQ_EMPTY | PD_S_TXQ_LOW_WATER | PD_S_RXQ_EMPTY | PD_S_RXQ_LOW_WATER);
port->WatchStateMask = 0x00000000;
return true;
}
void AppleRS232Serial::setStructureDefaults(PortInfo_t *port)
{
UInt32 tmp;
ELG(0, 0, "AppleRS232Serial::setStructureDefaults");
port->BaudRate = 0;
port->CharLength = 0;
port->StopBits = 0;
port->TX_Parity = 0;
port->RX_Parity = 0;
port->MinLatency = false;
port->XONchar = '\x11';
port->XOFFchar = '\x13';
port->FlowControl = 0x00000000;
port->FlowControlState = CONTINUE_SEND;
port->RXOstate = IDLE_XO;
port->TXOstate = IDLE_XO;
port->xOffSent = false;
port->RTSAsserted = true;
port->DTRAsserted = true;
port->RXStats.BufferSize = BUFFER_SIZE_DEFAULT;
port->RXStats.HighWater = (port->RXStats.BufferSize << 1) / 3;
port->RXStats.LowWater = port->RXStats.HighWater >> 1;
port->TXStats.BufferSize = BUFFER_SIZE_DEFAULT;
port->TXStats.HighWater = (port->RXStats.BufferSize << 1) / 3;
port->TXStats.LowWater = port->RXStats.HighWater >> 1;
port->FlowControl = DEFAULT_NOTIFY;
port->AreTransmitting = FALSE;
for (tmp=0; tmp<(256>>SPECIAL_SHIFT); tmp++)
{
port->SWspecial[tmp] = 0;
}
port->DCDState = false;
port->BreakState = false;
port->lastCTSTime = 0;
port->ctsTransitionCount = 0;
}
void AppleRS232Serial::freeRingBuffer(CirQueue *Queue)
{
ELG(0, Queue, "AppleRS232Serial::freeRingBuffer");
if (Queue->Start)
{
IOFree(Queue->Start, Queue->Size);
CloseQueue(Queue);
}
}
bool AppleRS232Serial::allocateRingBuffer(CirQueue *Queue, size_t BufferSize, IOWorkLoop *workloop)
{
UInt8 *Buffer;
ELG(0, BufferSize, "AppleRS232Serial::allocateRingBuffer");
Buffer = (UInt8*)IOMalloc(BufferSize);
InitQueue(Queue, Buffer, BufferSize, workloop);
if (Buffer)
return true;
return false;
}
void AppleRS232Serial::shutDown()
{
ELG(0, 0, "AppleRS232Serial::shutDown");
SccFreeReceptionChannel(&fPort, 0);
SccFreeReceptionChannel(&fPort, 1);
SccFreeTansmissionChannel(&fPort);
if (fPort.dmaChannelCommandAreaMDP != NULL)
{
fPort.dmaChannelCommandAreaMDP->complete();
fPort.dmaChannelCommandAreaMDP->release();
fPort.dmaChannelCommandAreaMDP = NULL;
}
if (txDMAInterruptSource)
{
fWorkLoop->removeEventSource(txDMAInterruptSource);
txDMAInterruptSource->release();
txDMAInterruptSource = 0;
}
if (rxDMAInterruptSource)
{
fWorkLoop->removeEventSource(rxDMAInterruptSource);
rxDMAInterruptSource->release();
rxDMAInterruptSource = 0;
}
if (sccInterruptSource)
{
fWorkLoop->removeEventSource(sccInterruptSource);
sccInterruptSource->release();
sccInterruptSource = 0;
}
if(fPort.rxTimer)
{
fPort.rxTimer->cancelTimeout(); fWorkLoop->removeEventSource(fPort.rxTimer ); fPort.rxTimer->release(); fPort.rxTimer = NULL;
}
if (fPort.ControlRegister != NULL)
{
SccCloseChannel(&fPort);
}
freeRingBuffer(&(fPort.TX));
freeRingBuffer(&(fPort.RX));
if (fCommandGate)
{
fCommandGate->release();
fCommandGate = NULL;
}
if (fWorkLoop)
{
fWorkLoop->release();
fWorkLoop = NULL;
}
if (fdmaStartTransmissionThread != NULL)
{
thread_call_free(fdmaStartTransmissionThread);
fdmaStartTransmissionThread = NULL;
}
if (dmaRxHandleCurrentPositionThread != NULL)
{
thread_call_free(dmaRxHandleCurrentPositionThread);
dmaRxHandleCurrentPositionThread = NULL;
}
}
bool AppleRS232Serial::interruptFilter(OSObject* obj, IOFilterInterruptEventSource *source)
{
UInt16 interruptIndex;
interruptIndex = source->getIntIndex();
if (interruptIndex == kIntRxDMA)
{
return true; }
if (interruptIndex == kIntTxDMA)
{
return true; }
return false;
}
void AppleRS232Serial::interruptHandler(OSObject* obj, IOInterruptEventSource *source, int count)
{
UInt16 interruptIndex;
ELG(0, obj, "AppleRS232Serial::interruptHandler");
interruptIndex = source->getIntIndex();
if (interruptIndex == kIntChipSet)
{
ELG(0, 0, "AppleRS232Serial::interruptHandler - SCC interrupt");
handleInterrupt(obj, 0, NULL, 0);
}
if (interruptIndex == kIntRxDMA)
{
ELG(0, 0, "AppleRS232Serial::interruptHandler - RX DMA interrupt");
handleDBDMARxInterrupt(obj, 0, NULL, 0);
}
if (interruptIndex == kIntTxDMA)
{
ELG(0, 0, "AppleRS232Serial::interruptHandler - TX DMA interrupt");
handleDBDMATxInterrupt(obj, 0, NULL, 0);
}
}
void AppleRS232Serial::handleInterrupt(OSObject *target, void *refCon, IOService *nub, int source)
{
AppleRS232Serial *serialPortPtr = (AppleRS232Serial *)target;
ELG(0, serialPortPtr->fWorkLoop->inGate(), "AppleRS232Serial::handleInterrupt, inGate");
if (serialPortPtr != NULL)
{
PPCSerialISR(target, refCon, &serialPortPtr->fPort);
}
}
void AppleRS232Serial::handleDBDMATxInterrupt(OSObject *target, void *refCon, IOService *nub, int source)
{
AppleRS232Serial *serialPortPtr = OSDynamicCast(AppleRS232Serial, target);
ELG(serialPortPtr, serialPortPtr->fWorkLoop->inGate(), "AppleRS232Serial::handleDBDMATxInterrupt, obj, inGate");
if (serialPortPtr != NULL)
{
PPCSerialTxDMAISR(serialPortPtr, NULL, &serialPortPtr->fPort);
}
}
void AppleRS232Serial::handleDBDMARxInterrupt(OSObject *target, void *refCon, IOService *nub, int source)
{
AppleRS232Serial *serialPortPtr = OSDynamicCast(AppleRS232Serial, target);
ELG(serialPortPtr, serialPortPtr->fWorkLoop->inGate(), "AppleRS232Serial::handleDBDMARxInterrupt, obj, inGate");
if (serialPortPtr != NULL)
{
PPCSerialRxDMAISR(serialPortPtr, NULL, &serialPortPtr->fPort);
}
}