#include <machine/limits.h>
#include <IOKit/assert.h>
#include <sys/kdebug.h>
#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/IORS232SerialStreamSync.h>
#include <IOKit/serial/IOSerialKeys.h>
#include <IOKit/IORegistryEntry.h>
#include "PPCSerialPort.h"
#include "SccChipPrimatives.h"
#define IOSS_HALFBIT_BRD 1
#ifdef SHOW_DEBUG_STRINGS
#define DLOG(fmt, args...) IOLog(fmt, ## args)
#else
#define DLOG(fmt, args...)
#endif
extern void flush_dcache(vm_offset_t addr, unsigned count, int phys);
extern UInt32 gTimerCanceled;
#include <pexpert/pexpert.h>
class AppleSCCRS232SerialStreamSync : public IORS232SerialStreamSync
{
OSDeclareDefaultStructors(AppleSCCRS232SerialStreamSync)
public:
virtual bool compareName(OSString *name, OSString **matched = 0) const;
};
OSDefineMetaClassAndStructors
(AppleSCCRS232SerialStreamSync, IORS232SerialStreamSync)
bool AppleSCCRS232SerialStreamSync::
compareName(OSString *name, OSString ** matched) const
{
return IODTCompareNubName(this, name, matched)
|| IORegistryEntry::compareName(name, matched);
}
OSDefineMetaClassAndStructors(AppleSCCSerial, IOSerialDriverSync)
#define super IOSerialDriverSync
bool AppleSCCSerial::start(IOService *provider)
{
IOMemoryMap *map;
if (!super::start(provider))
return false;
fProvider = OSDynamicCast(AppleMacIODevice, provider);
if (!fProvider)
return false;
myWorkLoop = getWorkLoop();
#if USE_TIMER_EVENT_SOURCE_DEBUGGING
myTimer = IOTimerEventSource::timerEventSource( this, (IOTimerEventSource::Action)&AppleSCCSerial::timeoutHandler );
if( !myTimer )
{
result = false;
return result;
}
if(!myWorkLoop || (myWorkLoop->addEventSource(myTimer) != kIOReturnSuccess) )
{
result = false;
return result;
}
counter = 0; #endif;
{
UInt32 debugFlags;
if (!PE_parse_boot_arg("debug", &debugFlags))
debugFlags = 0;
if (debugFlags & 8)
return NULL;
}
{
IORegistryEntry *parentEntry = provider->getParentEntry(gIODTPlane);
if (!parentEntry || IODTMatchNubWithKeys(parentEntry, "'escc-legacy'"))
return false;
}
{
OSString *matched = (OSString *) getProperty(gIONameMatchedKey);
if (matched->isEqualTo("ch-a"))
Port.whichPort = serialPortA;
else if (matched->isEqualTo("ch-b"))
Port.whichPort = serialPortB;
else
return false;
}
if (Port.whichPort == serialPortA)
{
Port.gDCPModemFound = LookForInternalModem (kDCPModem);
}
setPortName(provider);
OSString *name = OSDynamicCast(OSString, getProperty(kIOTTYBaseNameKey));
if ((name != NULL) && (name->isEqualTo("none")))
return false;
Port.IODBDMARxLock = IOLockAlloc();
Port.IODBDMATrLock = IOLockAlloc();
Port.DTRAsserted = true; Port.aboveRxHighWater = false;
Port.SCCAccessLock = IOLockAlloc();
Port.WatchLock = IOLockAlloc();
if (!Port.WatchLock)
return false;
if (!(Port.serialRequestLock = IORecursiveLockAlloc()))
return false;
SetStructureDefaults(&Port, true);
Port.Instance = Port.whichPort;
if (!(map = provider->mapDeviceMemoryWithIndex(0))) return false;
Port.Base = map->getVirtualAddress();
Port.ChipBaseAddress = Port.Base;
SccSetDMARegisters(&Port, provider);
if ((Port.TxDBDMAChannel.dmaChannelAddress == NULL) ||
(Port.TxDBDMAChannel.dmaBase == NULL) ||
(Port.RxDBDMAChannel.dmaChannelAddress == NULL) ||
(Port.RxDBDMAChannel.dmaBase == NULL))
return false;
Port.TXStats.BufferSize= BUFFER_SIZE_DEFAULT;
Port.RXStats.BufferSize= BUFFER_SIZE_DEFAULT;
initChip(&Port);
Port.fAppleSCCSerialInstance = (void *)this;
#if USE_WORK_LOOPS
sccInterruptSource = IOInterruptEventSource::interruptEventSource(
this,
(IOInterruptEventAction)&AppleSCCSerial::interruptHandler,
provider,
kIntChipSet);
if (!sccInterruptSource)
{
return false;
}
if (myWorkLoop->addEventSource(sccInterruptSource) != kIOReturnSuccess)
{
return false;
}
#if USE_FILTER_EVENT_SOURCES
txDMAInterruptSource = IOFilterInterruptEventSource::filterInterruptEventSource(this,
(IOInterruptEventAction) &AppleSCCSerial::interruptHandler,
(IOFilterInterruptAction) &AppleSCCSerial::interruptFilter,
provider,
kIntTxDMA);
#else
txDMAInterruptSource = IOInterruptEventSource::interruptEventSource(
this,
(IOInterruptEventAction)&AppleSCCSerial::interruptHandler,
provider,
kIntTxDMA);
#endif
if (!txDMAInterruptSource)
{
return false;
}
if (myWorkLoop->addEventSource(txDMAInterruptSource) != kIOReturnSuccess)
{
return false;
}
#if USE_FILTER_EVENT_SOURCES
rxDMAInterruptSource = IOFilterInterruptEventSource::filterInterruptEventSource(this,
(IOInterruptEventAction) &AppleSCCSerial::interruptHandler,
(IOFilterInterruptAction) &AppleSCCSerial::interruptFilter,
provider,
kIntRxDMA);
#else
rxDMAInterruptSource = IOInterruptEventSource::interruptEventSource(
this,
(IOInterruptEventAction)&AppleSCCSerial::interruptHandler,
provider,
kIntRxDMA);
#endif
if (!rxDMAInterruptSource)
{
return false;
}
if (myWorkLoop->addEventSource(rxDMAInterruptSource) != kIOReturnSuccess)
{
return false;
}
portPtr()->rxTimer = IOTimerEventSource::timerEventSource( this, rxTimeoutHandler );
if( !portPtr()->rxTimer )
{
return false;
}
if(!myWorkLoop || (myWorkLoop->addEventSource(portPtr()->rxTimer) != kIOReturnSuccess) )
{
return false;
}
if (OSCompareAndSwap(1,0,&gTimerCanceled) ) IOLog("%s: gTimerCanceled set to Zero\n", getName());
#else
if (provider->registerInterrupt(kIntChipSet, this, handleInterrupt, 0) != kIOReturnSuccess) {
return false;
}
if (provider->registerInterrupt(kIntTxDMA, this, handleDBDMATxInterrupt, 0) != kIOReturnSuccess) {
DLOG("AppleSCCSerial: Didn't register kIntTxDMA\n");
return false;
}
if (provider->registerInterrupt(kIntRxDMA, this, handleDBDMARxInterrupt, 0) != kIOReturnSuccess) {
DLOG("AppleSCCSerial: Didn't register kIntRxDMA\n");
return false;
}
#endif
callPlatformFunction("EnableSCC", false, (void *)true, 0, 0, 0);
fPollingThread = thread_call_allocate (
&AppleSCCSerial::callCarrierhack, ( thread_call_param_t ) this);
if ( fPollingThread == NULL )
{
return false;
}
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;
}
return createSerialStream();
}
#if USE_TIMER_EVENT_SOURCE_DEBUGGING
void AppleSCCSerial::timeoutHandler(OSObject *owner, IOTimerEventSource *sender)
{
AppleSCCSerial* serialPortPtr;
serialPortPtr = OSDynamicCast( AppleSCCSerial, owner );
if( serialPortPtr ) {
serialPortPtr->counter++;
HandleRxIntTimeout(serialPortPtr->portPtr());
sender->setTimeoutMS( kTimerTimeout );
}
}
#endif
void AppleSCCSerial::stop(IOService *provider)
{
SccFreeReceptionChannel(portPtr());
SccFreeTansmissionChannel(portPtr());
#if USE_WORK_LOOPS
if (txDMAInterruptSource)
{
myWorkLoop->removeEventSource(txDMAInterruptSource);
txDMAInterruptSource->release();
txDMAInterruptSource = 0;
}
if (rxDMAInterruptSource)
{
myWorkLoop->removeEventSource(rxDMAInterruptSource);
rxDMAInterruptSource->release();
rxDMAInterruptSource = 0;
}
if (sccInterruptSource)
{
myWorkLoop->removeEventSource(sccInterruptSource);
sccInterruptSource->release();
sccInterruptSource = 0;
}
if( portPtr()->rxTimer )
{
if (OSCompareAndSwap(1,0,&gTimerCanceled) )
OSIncrementAtomic((SInt32 *) &gTimerCanceled);
portPtr()->rxTimer->cancelTimeout(); portPtr()->rxTimer->disable(); myWorkLoop->removeEventSource( portPtr()->rxTimer ); portPtr()->rxTimer->release(); portPtr()->rxTimer = NULL; }
#else
provider->unregisterInterrupt(kIntChipSet);
provider->unregisterInterrupt(kIntTxDMA);
provider->unregisterInterrupt(kIntRxDMA);
#endif
#if USE_TIMER_EVENT_SOURCE_DEBUGGING
if( myTimer )
{
myTimer->cancelTimeout(); myWorkLoop->removeEventSource( myTimer ); myTimer->release(); myTimer = NULL; }
#endif
deactivatePort(&Port);
if ( fPollingThread != NULL)
{
while (fCarrierHackCount > 0) {
if (thread_call_cancel(fPollingThread))
break;
else
IOSleep(1);
}
thread_call_free ( fPollingThread );
fPollingThread = NULL;
}
if (fdmaStartTransmissionThread != NULL)
{
while (fTransmissionCount > 0) {
if (thread_call_cancel(fdmaStartTransmissionThread))
break;
else
IOSleep(1);
}
thread_call_free(fdmaStartTransmissionThread);
fdmaStartTransmissionThread = NULL;
}
if (dmaRxHandleCurrentPositionThread != NULL)
{
while (fCurrentPositionCount > 0) {
if (thread_call_cancel(dmaRxHandleCurrentPositionThread))
break;
else
IOSleep(1);
}
thread_call_free(dmaRxHandleCurrentPositionThread);
dmaRxHandleCurrentPositionThread = NULL;
}
if (Port.ControlRegister != NULL)
SccCloseChannel(&Port);
if (Port.FrameTOEntry != NULL) {
}
if (Port.DataLatTOEntry != NULL) {
}
if (Port.DelayTOEntry != NULL) {
}
if (Port.HeartBeatTOEntry != NULL) {
}
IOLockFree (Port.IODBDMARxLock);
IOLockFree (Port.IODBDMATrLock);
IOLockFree (Port.SCCAccessLock);
IOLockFree (Port.WatchLock); IORecursiveLockFree (Port.serialRequestLock);
super::stop(provider);
}
void AppleSCCSerial::setPortName(IOService *provider)
{
IOService *topProvider = NULL;
IOService *myProvider;
OSData *s;
if (provider == NULL)
provider = getProvider();
myProvider = provider;
s = OSDynamicCast(OSData, myProvider->getProperty("AAPL,connector"));
if (s) {
char *tmpName = (char *) s->getBytesNoCopy();
setProperty(kIOTTYBaseNameKey, tmpName);
return;
}
while (provider) {
topProvider = provider;
provider = topProvider->getProvider();
}
s = OSDynamicCast(OSData, myProvider->getProperty("slot-names"));
if (s != NULL) {
UInt32 *nWords = (UInt32*)s->getBytesNoCopy();
if (*nWords > 0) {
char *tmpPtr, *tmpName;
tmpName = (char *) s->getBytesNoCopy() + sizeof(UInt32);
for (tmpPtr = tmpName; *tmpPtr != 0; tmpPtr++)
*tmpPtr |= 32;
if (IODTMatchNubWithKeys(myProvider, "'ch-b'"))
{
if (topProvider != NULL)
{
if (IODTMatchNubWithKeys(topProvider, "'PowerMac1,1'")) {
setProperty(kIOTTYBaseNameKey, "none");
return;
}
}
}
setProperty(kIOTTYBaseNameKey, tmpName);
return;
}
}
if (topProvider != NULL) {
if (IODTMatchNubWithKeys(topProvider, "'AAPL,9500'")
|| IODTMatchNubWithKeys(topProvider, "'AAPL,Gossamer'")
|| IODTMatchNubWithKeys(topProvider, "'AAPL,PowerBook1998'")
|| IODTMatchNubWithKeys(topProvider, "'AAPL,PowerMac G3'")) {
s = OSDynamicCast(OSData, myProvider->getProperty("name"));
if (s != NULL) {
char *tmpName = (char*)s->getBytesNoCopy();
setProperty(kIOTTYBaseNameKey, tmpName);
return;
}
}
}
if (IODTMatchNubWithKeys(myProvider, "'ch-a'"))
{
if (topProvider != NULL)
{
if (IODTMatchNubWithKeys(topProvider, "'PowerMac1,1'")) {
setProperty(kIOTTYBaseNameKey, "modem");
}
else
{
OSString *tmpName = OSDynamicCast(OSString, getProperty("kSCCDebugKey"));
if (tmpName != NULL)
setProperty(kIOTTYBaseNameKey, "serial");
else
setProperty(kIOTTYBaseNameKey, "none");
}
}
else
setProperty(kIOTTYBaseNameKey, "none");
}
else if (IODTMatchNubWithKeys(myProvider, "'ch-b'"))
setProperty(kIOTTYBaseNameKey, "none");
}
bool AppleSCCSerial::createSerialStream()
{
AppleSCCRS232SerialStreamSync *rs232Stream;
OSObject *dtProperty;
bool ret;
rs232Stream = new AppleSCCRS232SerialStreamSync;
if (!rs232Stream)
return false;
ret = (rs232Stream->init(0, &Port) && rs232Stream->attach(this));
rs232Stream->release();
if (!ret)
return false;
dtProperty = fProvider->getProperty("device_type");
if (dtProperty)
rs232Stream->setProperty("device_type", dtProperty);
dtProperty = fProvider->getProperty("compatible");
if (dtProperty)
rs232Stream->setProperty("compatible", dtProperty);
dtProperty = fProvider->getProperty("slot-names");
if (dtProperty)
rs232Stream->setProperty("slot-names", dtProperty);
dtProperty = fProvider->getProperty("AAPL,connector");
if (dtProperty)
rs232Stream->setProperty("AAPL,connector", dtProperty);
dtProperty = getProperty(gIOTTYBaseNameKey);
if (dtProperty)
rs232Stream->setProperty(gIOTTYBaseNameKey, dtProperty);
rs232Stream->registerService();
return true;
}
void AppleSCCSerial::
handleInterrupt(OSObject *target, void *refCon, IOService *nub, int source)
{
AppleSCCSerial *serialPortPtr = (AppleSCCSerial*)target;
if (serialPortPtr != NULL) {
#if ! USE_WORK_LOOPS
serialPortPtr->fProvider->disableInterrupt(kIntChipSet);
#endif
PPCSerialISR(target, refCon, serialPortPtr->portPtr());
#if ! USE_WORK_LOOPS
serialPortPtr->fProvider->enableInterrupt(kIntChipSet);
#endif
}
}
void AppleSCCSerial::
handleDBDMATxInterrupt(OSObject *target, void *refCon, IOService *nub, int source)
{
AppleSCCSerial *serialPortPtr = OSDynamicCast(AppleSCCSerial, target);
if (serialPortPtr != NULL) {
#if ! USE_WORK_LOOPS
serialPortPtr->fProvider->disableInterrupt(kIntTxDMA);
#endif
PPCSerialTxDMAISR(serialPortPtr, NULL, serialPortPtr->portPtr());
#if ! USE_WORK_LOOPS
serialPortPtr->fProvider->enableInterrupt(kIntTxDMA);
#endif
}
}
void AppleSCCSerial::
handleDBDMARxInterrupt(OSObject *target, void *refCon, IOService *nub, int source)
{
AppleSCCSerial *serialPortPtr = OSDynamicCast(AppleSCCSerial, target);
if (serialPortPtr != NULL) {
#if USE_TIMER_EVENT_SOURCE_DEBUGGING
serialPortPtr->myTimer->cancelTimeout(); serialPortPtr->myTimer->setTimeoutMS( kTimerTimeout ); #endif
#if ! USE_WORK_LOOPS
serialPortPtr->fProvider->disableInterrupt(kIntRxDMA);
#endif
PPCSerialRxDMAISR(serialPortPtr, NULL, serialPortPtr->portPtr());
#if ! USE_WORK_LOOPS
serialPortPtr->fProvider->enableInterrupt(kIntRxDMA);
#endif
}
}
IOReturn AppleSCCSerial::acquirePort(bool sleep, void *refCon)
{
PortInfo_t *port = (PortInfo_t *) refCon;
UInt32 busyState = 0;
IOReturn rtn = kIOReturnSuccess;
if (OSCompareAndSwap(1,0,&gTimerCanceled) ) IOLog("%s: gTimerCanceled set to Zero\n", getName());
DLOG("[acquirePort ");
for (;;) {
busyState = (readPortState(port) & PD_S_ACQUIRED);
if (!busyState) {
changeState(port, PD_S_ACQUIRED | DEFAULT_STATE, STATE_ALL);
break;
} else if (!sleep) {
DLOG("Busy!]");
return kIOReturnExclusiveAccess;
} else {
busyState = 0;
rtn = watchState(&busyState, PD_S_ACQUIRED, 0);
if ((rtn == kIOReturnIOError) || (rtn == kIOReturnSuccess)) {
continue;
} else {
DLOG("Interrupted!]");
return rtn;
}
}
}
do {
if (!fProvider->open(this)) {
rtn = kIOReturnBusy;
break;
}
if (!allocateRingBuffer(&(port->TX), port->TXStats.BufferSize)
|| !allocateRingBuffer(&(port->RX), port->RXStats.BufferSize)) {
rtn = kIOReturnNoMemory;
break;
}
if ((port->whichPort == serialPortA) && (port->gDCPModemFound))
{
port->DCPModemSupportPtr = NULL;
void *tmp = NULL;
tmp = (void *) callPlatformFunction("GetDCPObject", false, 0, 0, 0, 0);
if (tmp != NULL)
{
port->gDCPUserClientSet = true;
port->DCPModemSupportPtr = (DCPModemSupport *) tmp;
}
else
{
port->gDCPUserClientSet = false;
}
if ((port->gDCPModemFound) && (port->gDCPUserClientSet))
{
port->DCPModemSupportPtr->setDCPBufferSize (port->RXStats.BufferSize);
}
}
SetStructureDefaults(port, FALSE);
OpenScc(port);
SccSetupReceptionChannel(port);
SccdbdmaDefineReceptionCommands(port);
SccSetupTansmissionChannel(port);
SccdbdmaDefineTansmissionCommands(port);
#if USE_WORK_LOOPS
sccInterruptSource->enable();
txDMAInterruptSource->enable();
rxDMAInterruptSource->enable();
#else
rtn = fProvider->enableInterrupt(kIntChipSet);
if (rtn != kIOReturnSuccess)
break;
rtn = fProvider->enableInterrupt(kIntTxDMA);
if (rtn != kIOReturnSuccess) {
break;
}
rtn = fProvider->enableInterrupt(kIntRxDMA);
if (rtn != kIOReturnSuccess) {
break;
}
#endif
SccdbdmaStartReception(port);
DLOG("Early]\n");
return kIOReturnSuccess;
} while (0);
freeRingBuffer(&(port->TX));
freeRingBuffer(&(port->RX));
fProvider->close(this);
changeState(port, 0, STATE_ALL);
return rtn;
}
IOReturn AppleSCCSerial::releasePort(void *refCon)
{
PortInfo_t *port = (PortInfo_t *) refCon;
UInt32 busyState = 0;
int i;
OSIncrementAtomic((SInt32 *) &gTimerCanceled);
DLOG("[release ");
busyState = (readPortState(port) & PD_S_ACQUIRED);
if (!busyState) {
DLOG("NOT OPEN]");
return kIOReturnNotOpen;
}
if (port->whichPort == serialPortA)
{
if (port->gDCPModemFound)
{
if (port->gDCPUserClientSet)
Port.DCPModemSupportPtr->callDCPModemSupportFunctions (DCPFunction_QuitDCP, NULL, NULL, NULL);
}
}
for (i=0; i<(256>>SPECIAL_SHIFT); i++)
port->SWspecial[i] = 0;
port->CharLength = 8;
port->BreakLength = 1;
port->XONchar = '\x11';
port->XOFFchar = '\x13';
port->StopBits = 1<<1;
port->TX_Parity = PD_RS232_PARITY_NONE;
port->RX_Parity = PD_RS232_PARITY_DEFAULT;
port->RXOstate = IDLE_XO;
port->BaudRate = kDefaultBaudRate;
port->FlowControl = DEFAULT_NOTIFY;
port->FlowControlState = CONTINUE_SEND;
port->DCDState = false;
fModemObject = 0;
deactivatePort(port);
#if USE_WORK_LOOPS
sccInterruptSource->disable();
txDMAInterruptSource->disable();
rxDMAInterruptSource->disable();
#else
fProvider->disableInterrupt(kIntChipSet);
fProvider->disableInterrupt(kIntTxDMA);
fProvider->disableInterrupt(kIntRxDMA);
#endif
freeRingBuffer(&(port->TX));
freeRingBuffer(&(port->RX));
DLOG("OK]\n");
fProvider->close(this);
changeState(port, 0, STATE_ALL);
return kIOReturnSuccess;
}
IOReturn AppleSCCSerial::setState(UInt32 state, UInt32 mask, void *refCon)
{
PortInfo_t *port = (PortInfo_t *) refCon;
DLOG("++>setState %d %x\n",(int)state, (int)mask);
if (mask & (PD_S_ACQUIRED | PD_S_ACTIVE | (~EXTERNAL_MASK)))
return kIOReturnBadArgument;
if ((readPortState(port) & PD_S_ACQUIRED) != 0) {
mask &= (~port->FlowControl & PD_RS232_A_MASK) | PD_S_MASK;
if (mask != 0)
changeState(port, state, mask);
DLOG("-->setState\n");
return kIOReturnSuccess;
}
return kIOReturnNotOpen;
}
UInt32 AppleSCCSerial::getState(void *refCon)
{
PortInfo_t *port = (PortInfo_t *) refCon;
CheckQueues(port);
return (readPortState(port) & EXTERNAL_MASK);
}
IOReturn AppleSCCSerial::watchState(UInt32 *state, UInt32 mask, void *refCon)
{
PortInfo_t *port = (PortInfo_t *) refCon;
IOReturn ret = kIOReturnNotOpen;
DLOG("watchState\n");
if ((readPortState(port) & PD_S_ACQUIRED) != 0) {
ret = kIOReturnSuccess;
mask &= EXTERNAL_MASK;
ret = watchState(port, state, mask);
(*state) &= EXTERNAL_MASK;
}
return ret;
}
UInt32 AppleSCCSerial::nextEvent(void *refCon)
{
UInt32 ret = kIOReturnSuccess;
DLOG("nextEvent\n");
return ret;
}
IOReturn AppleSCCSerial::executeEvent(UInt32 event, UInt32 data, void *refCon)
{
PortInfo_t *port = (PortInfo_t *) refCon;
IOReturn ret = kIOReturnSuccess;
UInt32 state, delta;
DLOG("executeEvent\n");
if ((readPortState(port) & PD_S_ACQUIRED) != 0) {
switch (event) {
case PD_E_FLOW_CONTROL:
UInt32 tmp;
tmp = FLOW_RX_AUTO & (data ^ port->FlowControl);
port->FlowControl = data & (CAN_BE_AUTO | CAN_NOTIFY);
if (tmp) {
if (tmp & PD_RS232_A_RXO)
{
port->RXOstate = NEEDS_XOFF;
}
}
break;
case PD_E_DELAY:
port->CharLatInterval = long2tval(data *1000);
break;
case PD_E_RXQ_SIZE:
#ifdef IntelTest
if (readPortState(port) & PD_S_ACTIVE) {
ret = IO_R_BUSY;
}
else {
port->RX.Size = validateRingBufferSize(data, &(port->RX));
if (port->RX.HighWater > (port->RX.Size - BIGGEST_EVENT))
port->RX.HighWater = (port->RX.Size - BIGGEST_EVENT);
if (port->RX.LowWater > (port->RX.HighWater - BIGGEST_EVENT))
port->RX.LowWater = (port->RX.HighWater - BIGGEST_EVENT);
}
#endif
break;
case PD_E_TXQ_SIZE:
#ifdef IntelTest
if (readPortState(port) & PD_S_ACTIVE) {
ret = IO_R_BUSY;
}
else {
port->TX.Size = validateRingBufferSize(data, &(port->RX));
if (port->TX.HighWater > (port->TX.Size - BIGGEST_EVENT))
port->TX.HighWater = (port->TX.Size - BIGGEST_EVENT);
if (port->TX.LowWater > (port->TX.HighWater - BIGGEST_EVENT))
port->TX.LowWater = (port->TX.HighWater - BIGGEST_EVENT);
}
#endif
break;
default:
delta = 0;
state = readPortState(port);
ret = executeEvent(port, event, data, &state, &delta);
changeState(port, state, delta);
break;
}
}
return ret;
}
IOReturn AppleSCCSerial::requestEvent(UInt32 event, UInt32 *data, void *refCon)
{
PortInfo_t *port = (PortInfo_t *) refCon;
IOReturn returnValue = kIOReturnSuccess;
DLOG("call requestEvent %ld\n", event);
if (data == NULL)
returnValue = kIOReturnBadArgument;
else {
switch (event) {
case PD_E_ACTIVE : *data = bool(readPortState(port)&PD_S_ACTIVE); break;
case PD_E_FLOW_CONTROL : *data = port->FlowControl; break;
case PD_E_DELAY : *data = tval2long(port->CharLatInterval)/1000; break;
case PD_E_DATA_LATENCY : *data = tval2long(port->DataLatInterval)/1000; break;
case PD_E_TXQ_SIZE : *data = GetQueueSize(&(port->TX)); break;
case PD_E_RXQ_SIZE : *data = GetQueueSize(&(port->RX)); break;
#if 0
case PD_E_TXQ_LOW_WATER : *data = port->TX.LowWater; break;
case PD_E_RXQ_LOW_WATER : *data = port->RX.LowWater; break;
case PD_E_TXQ_HIGH_WATER : *data = port->TX.HighWater; break;
case PD_E_RXQ_HIGH_WATER : *data = port->RX.HighWater; break;
#else
case PD_E_TXQ_LOW_WATER :
case PD_E_RXQ_LOW_WATER :
case PD_E_TXQ_HIGH_WATER :
case PD_E_RXQ_HIGH_WATER : *data = 0; returnValue = kIOReturnBadArgument; break;
#endif
case PD_E_TXQ_AVAILABLE : *data = FreeSpaceinQueue(&(port->TX)); break;
case PD_E_RXQ_AVAILABLE : *data = UsedSpaceinQueue(&(port->RX)); break;
case PD_E_DATA_RATE : *data = port->BaudRate << 1; break;
case PD_E_RX_DATA_RATE : *data = 0x00; break;
case PD_E_DATA_SIZE : *data = port->CharLength << 1; break;
case PD_E_RX_DATA_SIZE : *data = 0x00; break;
case PD_E_DATA_INTEGRITY : *data = port->TX_Parity; break;
case PD_E_RX_DATA_INTEGRITY : *data = port->RX_Parity; break;
case PD_RS232_E_STOP_BITS : *data = port->StopBits << 1; break;
case PD_RS232_E_RX_STOP_BITS : *data = 0x00; break;
case PD_RS232_E_XON_BYTE : *data = port->XONchar; break;
case PD_RS232_E_XOFF_BYTE : *data = port->XOFFchar; break;
case PD_RS232_E_LINE_BREAK : *data = bool(readPortState(port)&PD_RS232_S_BRK); break;
case PD_RS232_E_MIN_LATENCY : *data = bool(port->MinLatency); break;
default : returnValue = kIOReturnBadArgument; break;
}
}
DLOG("end requestEvent %ld\n", event);
return kIOReturnSuccess;
}
IOReturn AppleSCCSerial::
enqueueEvent(UInt32 event, UInt32 data, bool sleep, void *refCon)
{
PortInfo_t *port = (PortInfo_t *) refCon;
DLOG("enqueueEvent (write)\n");
if (readPortState(port) & PD_S_ACTIVE != 0) {
#ifdef IntelTest
if ((rtn == kIOReturnSuccess) && (!((readPortState(port))&PD_S_TX_BUSY)))
calloutEntryDispatch(port->FrameTOEntry); #endif
return kIOReturnSuccess;
}
return kIOReturnNotOpen;
}
IOReturn AppleSCCSerial::
dequeueEvent(UInt32 *event, UInt32 *data, bool sleep, void *refCon)
{
PortInfo_t *port = (PortInfo_t *) refCon;
DLOG("dequeueEvent (read)\n");
if ((event == NULL) || (data == NULL))
return kIOReturnBadArgument;
if (readPortState(port) & PD_S_ACTIVE !=0) {
return kIOReturnSuccess;
}
return kIOReturnNotOpen;
}
IOReturn AppleSCCSerial::
enqueueData(UInt8 *buffer, UInt32 size, UInt32 *count, bool sleep, void *refCon)
{
PortInfo_t *port = (PortInfo_t *) refCon;
UInt32 state = PD_S_TXQ_LOW_WATER;
IOReturn rtn = kIOReturnSuccess;
DLOG("++>In Enqueue %d %d sleep-%d\n", size, *count, sleep);
if (count == NULL || buffer == NULL)
return kIOReturnBadArgument;
(*count) = 0;
if (!(readPortState(port) & PD_S_ACTIVE)) {
return kIOReturnNotOpen;
}
#ifdef TRACE
KERNEL_DEBUG_CONSTANT((DRVDBG_CODE(DBG_DRVSERIAL, 2)) | DBG_FUNC_START, size, sleep, 0, 0, 0); #endif
*count = AddtoQueue(&(port->TX), buffer, size);
CheckQueues(port);
if (port->FlowControlState == PAUSE_SEND)
{
return kIOReturnSuccess;
}
SetUpTransmit(port);
while ((*count < size) && sleep) {
state = PD_S_TXQ_LOW_WATER;
rtn = watchState(&state, PD_S_TXQ_LOW_WATER, 0);
if (rtn != kIOReturnSuccess) {
DLOG("Interrupted!]");
#ifdef TRACE
KERNEL_DEBUG_CONSTANT((DRVDBG_CODE(DBG_DRVSERIAL, 2)) | DBG_FUNC_END, size, sleep, *count, -1, 0); #endif
return rtn;
}
DLOG("Adding More to Queue %d\n", size - *count);
*count += AddtoQueue(&(port->TX), buffer + *count, size - *count);
CheckQueues(port);
SetUpTransmit(port);
}
DLOG("Enqueue Check %x\n",(int)UsedSpaceinQueue(&(port->TX)));
DLOG("chars sent = %d of %d\n", *count,size);
DLOG("-->Out Enqueue\n");
#ifdef TRACE
KERNEL_DEBUG_CONSTANT((DRVDBG_CODE(DBG_DRVSERIAL, 2)) | DBG_FUNC_END, size, sleep, *count, -2, 0); #endif
return kIOReturnSuccess;
}
IOReturn AppleSCCSerial::
dequeueData(UInt8 *buffer, UInt32 size, UInt32 *count, UInt32 min, void *refCon)
{
PortInfo_t *port = (PortInfo_t *) refCon;
IOReturn rtn = kIOReturnSuccess;
UInt32 state = 0;
DLOG("++>In Dequeue buf %x bufSize %d txCount %d minCount %d\n",(int)buffer, size, *count, min);
if ((count == NULL) || (buffer == NULL) || (min > size))
return kIOReturnBadArgument;
*count = 0;
if (!(readPortState(port) & PD_S_ACTIVE))
return(kIOReturnNotOpen);
#ifdef TRACE
KERNEL_DEBUG_CONSTANT((DRVDBG_CODE(DBG_DRVSERIAL, 1)) | DBG_FUNC_START, size, min, 0, 0, 0); #endif
*count = RemovefromQueue(&(port->RX), buffer, size);
CheckQueues(port);
DLOG("-->chars receivedA = %d of needed %d\n", *count, size);
#if 1
while ((min > 0) && (*count < min)) {
#ifdef CHAR_DELAY
UInt32 bitInterval = 1000000L/port->BaudRate; UInt32 delay = (100L*bitInterval)/1000L; IOSleep(delay);
#endif
state = 0;
rtn = watchState(port, &state, PD_S_RXQ_EMPTY);
if (rtn == kIOReturnSuccess) {
} else {
DLOG("Interrupted!]");
#ifdef TRACE
KERNEL_DEBUG_CONSTANT((DRVDBG_CODE(DBG_DRVSERIAL, 1)) | DBG_FUNC_END, size, min, *count, -1, 0); #endif
return rtn;
}
*count += RemovefromQueue(&(port->RX), buffer + *count, (size - *count));
CheckQueues(port);
DLOG("-->chars receivedB = %d of needed %d\n", *count, size);
}
#endif
#ifdef TRACE
KERNEL_DEBUG_CONSTANT((DRVDBG_CODE(DBG_DRVSERIAL, 1)) | DBG_FUNC_END, size, min, *count, -2, 0); #endif
return rtn;
}
IOReturn AppleSCCSerial::activatePort(PortInfo_t *port) {
DLOG(" activatePort\n");
if (readPortState(port) & PD_S_ACTIVE)
return kIOReturnSuccess;
SetStructureDefaults(port, FALSE);
#ifdef IntelTest
if ((port->Type) > NS16550)
outb(FIFO_CTRL, ((port->FCRimage) | TX_FIFO_RESET | RX_FIFO_RESET));
#endif
changeState(port, PD_S_ACTIVE, PD_S_ACTIVE);
#ifdef IntelTest
if (!(readPortState(port) & PD_S_TX_BUSY)) calloutEntryDispatch(port->FrameTOEntry);
outb(IRQ_ENABLE, (port->IERmask) & (RX_DATA_AVAIL_IRQ_EN | TX_DATA_EMPTY_IRQ_EN
| LINE_STAT_IRQ_EN | MODEM_STAT_IRQ_EN));
#endif
DLOG("End Act State %x\n", (int)readPortState(port));
return kIOReturnSuccess;
}
void AppleSCCSerial::deactivatePort(PortInfo_t *port)
{
DLOG("deactivatePort");
if (readPortState(port) & PD_S_ACTIVE) {
changeState(port, 0, PD_S_ACTIVE);
SccCloseChannel(port);
#ifdef DEBUG
DLOG("%s: Ints=%ld TXInts=%ld RXInts=%ld mdmInts=%ld\n",
port->PortName, port->Stats.ints, port->Stats.txInts,
port->Stats.rxInts, port->Stats.mdmInts);
DLOG("%s: txChars=%ld rxChars=%ld\n",
port->PortName, port->Stats.txChars, port->Stats.rxChars);
#endif
}
}
void AppleSCCSerial::CheckQueues(PortInfo_t *port)
{
UInt32 Used;
UInt32 Free;
UInt32 OldState;
UInt32 DeltaState;
IORecursiveLockLock(port->serialRequestLock);
OldState = readPortState(port);
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;
}
UInt32 SW_FlowControl = port->FlowControl & PD_RS232_A_RXO;
UInt32 CTS_FlowControl = port->FlowControl & PD_RS232_A_CTS;
UInt32 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);
}
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 (CTS_FlowControl)
{
}
if (DTR_FlowControl && port->DTRAsserted)
{
DLOG("Deassert DTR\n");
port->DTRAsserted = false;
SccSetDTR(port, false);
}
}
else
{
if (DTR_FlowControl && !port->DTRAsserted)
{
DLOG("Assert DTR\n");
port->DTRAsserted = true;
SccSetDTR(port, true);
}
OldState &= ~PD_S_RXQ_HIGH_WATER;
if (port->aboveRxHighWater)
{
port->aboveRxHighWater = false;
}
}
DeltaState = OldState ^ readPortState(port);
changeState(port, OldState, DeltaState);
IORecursiveLockUnlock(port->serialRequestLock);
}
void AppleSCCSerial::SetStructureDefaults(PortInfo_t *port, bool Init)
{
UInt32 tmp;
if (Init) {
SerialDBDMAStatusInfo *dmaInfo = &port->TxDBDMAChannel;
dmaInfo->dmaTransferSize = 0;
dmaInfo->dmaTransferBufferMDP = IOBufferMemoryDescriptor::withOptions(0, PAGE_SIZE, PAGE_SIZE);
if (dmaInfo->dmaTransferBufferMDP == NULL)
return;
dmaInfo->dmaTransferBufferMDP->prepare();
dmaInfo->dmaTransferBuffer = (UInt8 *)dmaInfo->dmaTransferBufferMDP->getBytesNoCopy();
bzero(dmaInfo->dmaTransferBuffer, PAGE_SIZE);
dmaInfo->dmaNumberOfDescriptors = 2;
dmaInfo->dmaChannelCommandAreaMDP = IOBufferMemoryDescriptor::withOptions(0, PAGE_SIZE, PAGE_SIZE);
if (dmaInfo->dmaChannelCommandAreaMDP == NULL)
{
dmaInfo->dmaNumberOfDescriptors = 0;
return;
}
dmaInfo->dmaChannelCommandAreaMDP->prepare();
dmaInfo->dmaChannelCommandArea = (IODBDMADescriptor *)dmaInfo->dmaChannelCommandAreaMDP->getBytesNoCopy();
bzero(dmaInfo->dmaChannelCommandArea, sizeof(IODBDMADescriptor) * dmaInfo->dmaNumberOfDescriptors);
dmaInfo = &port->RxDBDMAChannel;
dmaInfo->dmaNumberOfDescriptors = PAGE_SIZE / sizeof(IODBDMADescriptor);
dmaInfo->dmaChannelCommandAreaMDP = IOBufferMemoryDescriptor::withOptions(0, sizeof(IODBDMADescriptor) * dmaInfo->dmaNumberOfDescriptors, PAGE_SIZE);
if (dmaInfo->dmaChannelCommandAreaMDP == NULL)
{
dmaInfo->dmaNumberOfDescriptors = 0;
return;
}
dmaInfo->dmaChannelCommandAreaMDP->prepare();
dmaInfo->dmaChannelCommandArea = (IODBDMADescriptor *)dmaInfo->dmaChannelCommandAreaMDP->getBytesNoCopy();
bzero(dmaInfo->dmaChannelCommandArea, sizeof(IODBDMADescriptor) * dmaInfo->dmaNumberOfDescriptors);
dmaInfo->dmaTransferSize = dmaInfo->dmaNumberOfDescriptors;
dmaInfo->dmaTransferBufferMDP = IOBufferMemoryDescriptor::withOptions(0, dmaInfo->dmaNumberOfDescriptors, PAGE_SIZE);
if (dmaInfo->dmaTransferBufferMDP == NULL)
{
return;
}
dmaInfo->dmaTransferBufferMDP->prepare();
dmaInfo->dmaTransferBuffer = (UInt8 *)dmaInfo->dmaTransferBufferMDP->getBytesNoCopy();
bzero(dmaInfo->dmaTransferBuffer, dmaInfo->dmaNumberOfDescriptors);
port->Instance = 0;
port->PortName = NULL;
port->MasterClock = CHIP_CLOCK_DEFAULT;
port->DLRimage = 0x0000;
port->LCRimage = 0x00;
port->FCRimage = 0x00;
port->IERmask = 0x00;
port->RBRmask = 0x00;
port->Base = 0x0000;
port->DataLatInterval.tv_sec = 0;
port->DataLatInterval.tv_nsec = 0;
port->CharLatInterval.tv_sec = 0;
port->CharLatInterval.tv_nsec = 0;
port->HeartBeatInterval.tv_sec = 0;
port->HeartBeatInterval.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;
}
port->BreakLength = 0;
port->BaudRate = 0;
port->CharLength = 0;
port->BreakLength = 0;
port->StopBits = 0;
port->TX_Parity = 0;
port->RX_Parity = 0;
port->WaitingForTXIdle = false;
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->FrameTOEntry = NULL;
port->DataLatTOEntry = NULL;
port->FrameInterval.tv_sec = 0;
port->FrameInterval.tv_nsec = 0;
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->Stats.ints = 0;
port->Stats.txInts = 0;
port->Stats.rxInts = 0;
port->Stats.mdmInts = 0;
port->Stats.txChars = 0;
port->Stats.rxChars = 0;
port->DCDState = false;
port->lastCTSTime = 0;
port->ctsTransitionCount = 0;
}
void AppleSCCSerial::dataLatTOHandler(PortInfo_t *port)
{
DLOG("dataLatTOHandler\n");
}
void AppleSCCSerial::frameTOHandler(PortInfo_t *port)
{
DLOG("frameToHandler\n");
port->WaitingForTXIdle = false;
PPCSerialISR(NULL, NULL, port);
}
void AppleSCCSerial::delayTOHandler(PortInfo_t *port)
{
UInt32 currentState = readPortState(port);
DLOG("delayTOHandler\n");
assert (currentState & INTERNAL_DELAY);
currentState &= ~INTERNAL_DELAY;
changeState(port, currentState, currentState);
PPCSerialISR(NULL, NULL, port);
}
void AppleSCCSerial::heartBeatTOHandler(PortInfo_t *port)
{
DLOG("heartBeatTOHandler\n");
assert (tval2long(port->HeartBeatInterval) > 0);
PPCSerialISR(NULL, NULL, port);
}
IOReturn AppleSCCSerial::
executeEvent(PortInfo_t *port, UInt32 event, UInt32 data, UInt32 *state, UInt32 *delta)
{
IOReturn ret = kIOReturnSuccess;
UInt32 tmp;
unsigned char clockMode;
DLOG("ExecuteEvent %d %d\n",(int)event,(int)data);
if ((readPortState(port) & PD_S_ACQUIRED) == 0)
return kIOReturnNotOpen;
switch (event) {
case PD_RS232_E_XON_BYTE:
port->XONchar = data;
break;
case PD_RS232_E_XOFF_BYTE:
port->XOFFchar = data;
break;
case PD_E_SPECIAL_BYTE:
port->SWspecial[data>>SPECIAL_SHIFT] |= (1 << (data & SPECIAL_MASK));
break;
case PD_E_VALID_DATA_BYTE:
port->SWspecial[data>>SPECIAL_SHIFT] &= ~(1 << (data & SPECIAL_MASK));
break;
case PD_E_FLOW_CONTROL :
DLOG("-ExecuteEvent PD_E_FLOW_CONTROL\n");
tmp = data & (PD_RS232_D_RFR | PD_RS232_D_DTR | PD_RS232_D_RXO);
tmp >>= PD_RS232_D_SHIFT;
tmp &= ~(port->FlowControl);
*delta |= tmp;
*state &= ~tmp;
*state |= (tmp & data);
if (tmp & PD_RS232_S_RXO) {
if (data & PD_RS232_S_RXO)
{
port->RXOstate = NEEDS_XON;
}
else
{
port->RXOstate = NEEDS_XOFF;
}
}
#if 0
programMCR(port, *state);
#endif
break;
case PD_E_ACTIVE:
DLOG("-ExecuteEvent PD_E_ACTIVE\n");
if ((bool)data)
ret = activatePort(port);
else
deactivatePort(port);
break;
case PD_E_DATA_LATENCY:
port->DataLatInterval = long2tval(data *1000);
break;
case PD_RS232_E_MIN_LATENCY:
port->MinLatency = bool(data);
port->DLRimage = 0x0000;
programChip(port);
break;
case PD_E_DATA_INTEGRITY:
DLOG("-ExecuteEvent PD_E_DATA_INTEGRITY\n");
if ((data < PD_RS232_PARITY_NONE) || (data > PD_RS232_PARITY_SPACE)) {
ret = kIOReturnBadArgument;
}
else {
port->TX_Parity = data;
port->RX_Parity = PD_RS232_PARITY_DEFAULT;
if (!SccSetParity(port, (ParityType)data))
ret = kIOReturnBadArgument;
}
break;
case PD_E_DATA_RATE:
data >>=1;
DLOG("-ExecuteEvent PD_E_DATA_RATE %d\n",(int)data);
if ((data < MIN_BAUD) || (data > kMaxBaudRate))
ret = kIOReturnBadArgument;
else {
port->BaudRate = data;
if ((port->whichPort == serialPortA) && (port->gDCPModemFound))
{ if (!SccSetBaud(port, 115200))
{
ret = kIOReturnBadArgument;
}
} else
{
if (!SccSetBaud(port, data))
ret = kIOReturnBadArgument;
}
}
break;
case PD_E_EXTERNAL_CLOCK_MODE:
DLOG("-ExecuteEvent PD_E_EXTERNAL_CLOCK_MODE data = %d\n", data);
switch (data) {
case kX1UserClockMode: clockMode = kX1ClockMode; break;
case kX16UserClockMode:
clockMode = kX16ClockMode;
break;
case kX32UserClockMode:
clockMode = kX32ClockMode;
break;
case kX64UserClockMode:
clockMode = kX64ClockMode;
break;
default :
clockMode = kX32ClockMode;
break;
}
if (!SccConfigureForMIDI(port, clockMode))
ret = kIOReturnBadArgument;
break;
case PD_E_DATA_SIZE:
data >>=1;
DLOG("-ExecuteEvent PD_E_DATA_SIZE data = %d\n", data);
if ((data < 5) || (data > 8))
ret = kIOReturnBadArgument;
else {
port->CharLength = data;
if (!SccSetDataBits(port, data))
ret = kIOReturnBadArgument;
}
break;
case PD_RS232_E_STOP_BITS:
DLOG("-ExecuteEvent PD_RS232_E_STOP_BITS\n");
if ((data < 0) || (data > 20))
ret = kIOReturnBadArgument;
else {
port->StopBits = data;
if (!SccSetStopBits(port, data))
ret = kIOReturnBadArgument;
}
break;
case PD_E_RXQ_FLUSH:
#ifdef IntelTest
port->RX.Input = port->RX.Output = port->RX.Base;
port->RX.Count = port->RX.OverRun = 0;
if ((port->Type) > NS16550)
outb(FIFO_CTRL, ((port->FCRimage) | RX_FIFO_RESET));
*state &= ~(PD_S_RXQ_MASK | FLOW_RX_AUTO);
*delta |= PD_S_RXQ_MASK | FLOW_RX_AUTO;
#endif
break;
case PD_E_RX_DATA_INTEGRITY:
if ((data != PD_RS232_PARITY_DEFAULT) && (data != PD_RS232_PARITY_ANY))
ret = kIOReturnBadArgument;
else
port->RX_Parity = data;
break;
case PD_E_RX_DATA_RATE:
if (data != 0)
ret = kIOReturnBadArgument;
break;
case PD_E_RX_DATA_SIZE:
if (data != 0)
ret = kIOReturnBadArgument;
break;
case PD_RS232_E_RX_STOP_BITS:
if (data != 0)
ret = kIOReturnBadArgument;
break;
case PD_E_TXQ_FLUSH:
#ifdef IntelTest
port->TX.Input = port->TX.Output = port->TX.Base;
port->TX.Count = 0;
if ((port->Type) > NS16550)
outb(FIFO_CTRL, ((port->FCRimage) | TX_FIFO_RESET));
*state &= ~PD_S_TXQ_MASK;
*state |= generateTXQState(port);
*delta |= PD_S_TXQ_MASK;
#endif
break;
case PD_RS232_E_LINE_BREAK :
*state &= ~PD_RS232_S_BRK;
*delta |= PD_RS232_S_BRK;
break;
case PD_E_DELAY:
assert(!((*state) & INTERNAL_DELAY));
if (data > 0) {
if (data > (UINT_MAX/1000))
data = (UINT_MAX/1000);
*state |= INTERNAL_DELAY;
}
break;
case PD_E_RXQ_HIGH_WATER:
#if 0
port->RX.HighWater = data;
if ((port->RX.HighWater) > ((port->RX.Size) - BIGGEST_EVENT))
(port->RX.HighWater) = ((port->RX.Size) - BIGGEST_EVENT);
if ((port->RX.HighWater) < (BIGGEST_EVENT *2))
(port->RX.HighWater) = (BIGGEST_EVENT *2);
if ((port->RX.LowWater) > ((port->RX.HighWater) - BIGGEST_EVENT))
(port->RX.LowWater) = ((port->RX.HighWater) - BIGGEST_EVENT);
*state &= ~(PD_S_RXQ_MASK | FLOW_RX_AUTO);
*delta |= PD_S_RXQ_MASK | FLOW_RX_AUTO;
#endif
break;
case PD_E_RXQ_LOW_WATER:
#if 0
port->RX.LowWater = data;
if ((port->RX.LowWater) > ((port->RX.HighWater) - BIGGEST_EVENT))
(port->RX.LowWater) = ((port->RX.HighWater) - BIGGEST_EVENT);
if ((port->RX.LowWater) < BIGGEST_EVENT)
(port->RX.LowWater) = BIGGEST_EVENT;
*state &= ~(PD_S_RXQ_MASK | FLOW_RX_AUTO);
*delta |= PD_S_RXQ_MASK | FLOW_RX_AUTO;
#endif
break;
case PD_E_TXQ_HIGH_WATER:
#if 0
port->RX.HighWater = data;
if ((port->TX.HighWater) > ((port->TX.Size) - BIGGEST_EVENT))
(port->TX.HighWater) = ((port->TX.Size) - BIGGEST_EVENT);
if ((port->TX.HighWater) < (BIGGEST_EVENT *2))
(port->TX.HighWater) = (BIGGEST_EVENT *2);
if ((port->TX.LowWater) > ((port->TX.HighWater) - BIGGEST_EVENT))
(port->TX.LowWater) = ((port->TX.HighWater) - BIGGEST_EVENT);
*state &= ~PD_S_TXQ_MASK;
*delta |= PD_S_TXQ_MASK;
#endif
break;
case PD_E_TXQ_LOW_WATER:
#if 0
port->TX.LowWater = data;
if ((port->TX.LowWater) > ((port->TX.HighWater) - BIGGEST_EVENT))
(port->TX.LowWater) = ((port->TX.HighWater) - BIGGEST_EVENT);
if ((port->TX.LowWater) < BIGGEST_EVENT)
(port->TX.LowWater) = BIGGEST_EVENT;
*state &= ~PD_S_TXQ_MASK;
*delta |= PD_S_TXQ_MASK;
#endif
break;
default:
ret = kIOReturnBadArgument;
break;
}
*state |= *state;
return ret;
}
void AppleSCCSerial::freeRingBuffer(CirQueue *Queue)
{
DLOG("In freeRingBuffer\n");
if (Queue->Start) {
IOFree(Queue->Start, Queue->Size);
CloseQueue(Queue);
}
}
bool AppleSCCSerial::allocateRingBuffer(CirQueue *Queue, size_t BufferSize)
{
u_char *Buffer;
DLOG("In allocateRingBuffer\n");
Buffer = (u_char *)IOMalloc(BufferSize);
InitQueue(Queue, Buffer, BufferSize);
if (Buffer)
return true;
else
return false;
}
UInt32 AppleSCCSerial::readPortState(PortInfo_t *port)
{
IORecursiveLockLock(port->serialRequestLock);
UInt32 returnState = port->State;
IORecursiveLockUnlock(port->serialRequestLock);
return returnState;
}
void AppleSCCSerial::changeState(PortInfo_t *port, UInt32 state, UInt32 mask)
{
UInt32 delta;
if (port && port->serialRequestLock)
{
IORecursiveLockLock(port->serialRequestLock);
if ((mask & PD_RS232_S_DTR) && ((port->FlowControl & PD_RS232_A_DTR) != PD_RS232_A_DTR))
{
if ((state & PD_RS232_S_DTR) != (port->State & PD_RS232_S_DTR))
{
if (state & PD_RS232_S_DTR)
{
DLOG("*** DTR ON\n");
SccSetDTR(port, true);
}
else
{
DLOG("*** DTR OFF\n");
SccSetDTR(port, false);
}
}
}
state = (port->State & ~mask) | (state & mask); delta = (state ^ port->State); port->State = state;
if (delta & port->WatchStateMask) {
thread_wakeup_with_result (&port->WatchStateMask, THREAD_RESTART);
}
IORecursiveLockUnlock(port->serialRequestLock);
}
}
IOReturn AppleSCCSerial::watchState(PortInfo_t *port, UInt32 *state, UInt32 mask)
{
unsigned watchState, foundStates;
bool autoActiveBit = false;
IOReturn rtn = kIOReturnSuccess;
DLOG("[WatchState..");
watchState = *state;
IORecursiveLockLock(port->serialRequestLock);
if (!(mask & (PD_S_ACQUIRED | PD_S_ACTIVE))) {
watchState &= ~PD_S_ACTIVE; mask |= PD_S_ACTIVE; autoActiveBit = true;
}
for (;;) {
foundStates = (watchState ^ ~(port->State)) & mask;
if (foundStates) {
*state = port->State;
if (autoActiveBit && (foundStates & PD_S_ACTIVE))
rtn = kIOReturnIOError;
else
rtn = kIOReturnSuccess;
break;
}
IOLockLock(port->WatchLock);
port->WatchStateMask |= mask;
assert_wait(&port->WatchStateMask, true);
IOLockUnlock(port->WatchLock);
IORecursiveLockUnlock(port->serialRequestLock);
rtn = thread_block(THREAD_CONTINUE_NULL);
IORecursiveLockLock(port->serialRequestLock);
if (rtn == THREAD_RESTART) {
continue;
}
else {
rtn = kIOReturnIPCError;
break;
}
}
DLOG("]\n");
IOLockLock(port->WatchLock);
port->WatchStateMask = 0;
IOLockUnlock(port->WatchLock);
thread_wakeup_with_result(&port->WatchStateMask, THREAD_RESTART);
IORecursiveLockUnlock(port->serialRequestLock);
return rtn;
}
#if USE_WORK_LOOPS
bool AppleSCCSerial::interruptFilter(OSObject* obj, IOFilterInterruptEventSource * source)
{
int interruptIndex = source->getIntIndex();
if (interruptIndex == kIntRxDMA)
{
return true; }
if (interruptIndex == kIntTxDMA)
{
return true; }
return false;
}
void AppleSCCSerial::interruptHandler(OSObject* obj, IOInterruptEventSource * source, int count)
{
int interruptIndex = source->getIntIndex();
if (interruptIndex == kIntChipSet)
{
handleInterrupt(obj, 0, NULL, 0);
return;
}
if (interruptIndex == kIntRxDMA)
{
handleDBDMARxInterrupt(obj, 0, NULL, 0);
return;
}
if (interruptIndex == kIntTxDMA)
{
handleDBDMATxInterrupt(obj, 0, NULL, 0);
}
}
#endif
void AppleSCCSerial::callCarrierhack(thread_call_param_t whichDevice, thread_call_param_t carrier)
{
AppleSCCSerial *self = (AppleSCCSerial *) whichDevice;
if (self->modemDCDStateChangeCallback)
(*self->modemDCDStateChangeCallback)(self->fModemObject, (bool) carrier);
OSDecrementAtomic(&self->fCarrierHackCount);
}
void AppleSCCSerial::setCarrierHack(OSObject *target, SCCCarrierHack action)
{
modemDCDStateChangeCallback = action;
fModemObject = target;
}
bool AppleSCCSerial::NonSCCModem()
{
IORegistryEntry * next;
IORegistryIterator * iter;
bool stopWhile = false;
bool found = false;
iter = IORegistryIterator::iterateOver( gIODTPlane );
assert( iter );
iter->reset();
while ((stopWhile == false) && (next = iter->getNextObjectRecursive()))
{
if (0 == strcmp ("i2c-modem", next->getName()))
{
stopWhile = true;
OSData *s2 = OSDynamicCast(OSData, next->getProperty("modem-id"));
if (s2)
{
char *tmpID = (char *) s2->getBytesNoCopy();
tmpID++; switch (*tmpID)
{
case 0x04 :
case 0x05 :
case 0x07 :
case 0x08 :
case 0x0b :
case 0x0c :
found = true;
break;
}
}
}
}
iter->release();
return found;
}
UInt32 SCC_GetSystemTime(void)
{
AbsoluteTime atTime;
UInt64 nsTime;
clock_get_uptime(&atTime);
absolutetime_to_nanoseconds( atTime, &nsTime);
return (UInt32)(nsTime/1000000);
}
void SCC_TRACEMSG(char *msg)
{
UInt32 dwTime = SCC_GetSystemTime();
IOLog("%07ld.%03ld: ", dwTime/1000, dwTime%1000);
IOLog (msg);
}
bool AppleSCCSerial::LookForInternalModem(UInt8 modemID = 0)
{
IORegistryEntry * next;
IORegistryIterator * iter;
bool found = false;
iter = IORegistryIterator::iterateOver( gIODTPlane );
assert( iter );
iter->reset();
found = false;
while ((found == false) && (next = iter->getNextObjectRecursive()))
{
if (0 == strcmp ("i2c-modem", next->getName()))
{
OSData *s2 = OSDynamicCast(OSData, next->getProperty("modem-id"));
if (s2)
{
char *tmpID = (char *) s2->getBytesNoCopy();
tmpID++; if (*tmpID == modemID)
{
found = true;
}
}
}
}
iter->release();
return found;
}