Apple16X50UARTSync.cpp [plain text]
#include "Apple16X50UARTSync.h"
#include <IOKit/IOLib.h>
#include <IOKit/serial/IOSerialKeys.h>
#define bits <<1
#define kMinBaud ((UInt32)(50 bits))
#define kOneMS (1000) // 1 ms expressed in microseconds
#define kTwoMS (2*kOneMS) // 2 ms expressed in microseconds
#define kTenMS (10*kOneMS) // 10 ms expressed in microseconds
#define kXOnChar '\x11'
#define kXOffChar '\x13'
#define k1xMasterClock (1843200)
#define kRxAutoFlow ((UInt32)( PD_RS232_A_RFR | PD_RS232_A_DTR | PD_RS232_A_RXO ))
#define kTxAutoFlow ((UInt32)( PD_RS232_A_CTS | PD_RS232_A_DSR | PD_RS232_A_TXO | PD_RS232_A_DCD ))
#define kMSR_StateMask ((UInt32)( PD_RS232_S_CTS | PD_RS232_S_DSR | PD_RS232_S_CAR | PD_RS232_S_RI ))
#define super IORS232SerialStreamSync
OSDefineMetaClassAndStructors(com_apple_driver_16X50UARTSync, IORS232SerialStreamSync);
inline UInt32 Apple16X50UARTSync::msrState()
{
register UInt32 stat=0;
register UInt8 msr=(OffLine)?0:inb(kREG_ModemStatus);
if (msr & kMSR_CTS) stat |= PD_RS232_S_CTS;
if (msr & kMSR_DSR) stat |= PD_RS232_S_DSR;
if (msr & kMSR_RI) stat |= PD_RS232_S_RI;
if (msr & kMSR_DCD) stat |= PD_RS232_S_CAR;
return stat;
}
IOReturn Apple16X50UARTSync::acquirePort(bool sleep)
{
IOReturn ret;
retain();
ret=CommandGate->runAction(acquirePortAction, (void*)sleep);
release();
return ret;
}
IOReturn Apple16X50UARTSync::
acquirePortAction(OSObject *owner, void*arg0, void*, void*, void*)
{ return ((Apple16X50UARTSync *)owner)->acquirePortGated((bool)arg0); }
IOReturn Apple16X50UARTSync::acquirePortGated(bool sleep)
{
IOReturn rtn = kIOReturnExclusiveAccess;
DEBUG_IOLog("%s::acquirePortGated(%s)\n", Name, BOOLSTR(sleep));
assert((Stage==kReleased) || (Stage==kStarted));
if (OffLine || (Stage<kStarted) || (Stage>=kFinalized)) return kIOReturnOffline;
retain(); while (Acquired) {
if (sleep) {
retain();
CommandGate->retain();
rtn = CommandGate->commandSleep((void*)&Acquired);
CommandGate->release();
release();
if (OffLine || (Stage<kStarted)||(Stage>=kTerminated))
rtn = kIOReturnOffline;
}
if (rtn != THREAD_AWAKENED) goto fail;
}
if (!(Provider->open(this))) {
rtn = kIOReturnExclusiveAccess;
goto fail;
}
Stage = kAcquired;
Acquired = true;
setStateGated(PD_S_ACQUIRED | PD_S_TX_ENABLE | PD_S_RX_ENABLE | PD_RS232_A_TXO | PD_RS232_A_RXO , PD_RS232_S_MASK | PD_S_MASK);
if (!OffLine) {
resetUART();
outb(kREG_IRQ_Enable, IER_Mask & kIRQEN_ModemStatus);
flowMachine();
setStateGated(msrState(), kMSR_StateMask);
#ifdef HEARTBEAT
if (HeartBeatInterval > 0) {
HeartBeatNeeded = true;
HeartBeatTimer->setTimeoutUS(HeartBeatInterval);
}
#endif
startTxEngine();
}
return kIOReturnSuccess;
fail:
CommandGate->commandWakeup((void*)&Acquired, !OffLine);
release();
return rtn;
}
IOReturn Apple16X50UARTSync::releasePort()
{
switch (Stage) {
case kReleased : return kIOReturnSuccess;
case kTerminated : assert(CommandGate);
case kAcquired : IOReturn ret;
retain();
ret=CommandGate->runAction(releasePortAction);
release();
return ret;
default : break;
}
return kIOReturnOffline;
}
IOReturn Apple16X50UARTSync::
releasePortAction(OSObject *owner, void*, void*, void*, void*)
{ return ((Apple16X50UARTSync *)owner)->releasePortGated(); }
IOReturn Apple16X50UARTSync::releasePortGated()
{
DEBUG_IOLog("%s::releasePortGated()\n", Name);
if (!Acquired) return kIOReturnSuccess;
deactivatePort();
resetUART();
setStateGated(0, PD_RS232_S_MASK | PD_S_MASK); if (!OffLine) outb(kREG_ModemControl, 0x00);
CommandGate->commandWakeup((void*)&Acquired, !OffLine);
Provider->close(this);
if (Stage<kReleased) Stage = kReleased;
Acquired=false;
release(); return kIOReturnSuccess;
}
IOReturn Apple16X50UARTSync::setState(UInt32 state, UInt32 mask)
{
if (Stage != kAcquired) return kIOReturnOffline;
assert(CommandGate);
if (mask & (PD_S_ACQUIRED | PD_S_ACTIVE)) return kIOReturnBadArgument;
mask &= ~(FlowControl & PD_RS232_A_MASK);
if (mask) {
retain();
CommandGate->runAction(setStateAction, (void*)state, (void*)mask);
release();
}
return kIOReturnSuccess;
}
IOReturn Apple16X50UARTSync::
setStateAction(OSObject *owner, void*arg0, void*arg1, void*, void*)
{
((Apple16X50UARTSync *)owner)->setStateGated((UInt32)arg0, (UInt32)arg1);
return kIOReturnSuccess;
}
void Apple16X50UARTSync::setStateGated(UInt32 state, UInt32 mask)
{
UInt32 delta;
state = maskMux(State, state, mask); delta = (state ^ State); State = state;
if (delta & WatchStateMask) {
CommandGate->commandWakeup((void*)&State);
}
if (delta & ( PD_RS232_S_DTR | PD_RS232_S_RFR ))
programMCR(state);
startTxEngine();
delta <<= PD_RS232_N_SHIFT;
if (delta & FlowControl)
RxQ->enqueueEvent(PD_E_FLOW_CONTROL, delta | (state & PD_RS232_S_MASK));
}
UInt32 Apple16X50UARTSync::getState()
{
return State;
}
IOReturn Apple16X50UARTSync::watchState(UInt32 *state, UInt32 mask)
{
IOReturn ret;
if (!state) return kIOReturnBadArgument;
if (!mask) return kIOReturnSuccess;
if ((Stage<kStarted)||(Stage>=kTerminated)) return kIOReturnOffline;
assert(CommandGate);
retain();
ret=CommandGate->runAction(watchStateAction, (void*)state, (void*)mask);
release();
return ret;
}
IOReturn Apple16X50UARTSync::
watchStateAction(OSObject *owner, void*arg0, void*arg1, void*, void*)
{ return ((Apple16X50UARTSync *)owner)->watchStateGated((UInt32*)arg0, (UInt32)arg1); }
IOReturn Apple16X50UARTSync::watchStateGated(UInt32 *state, UInt32 mask)
{
bool watchForInactive = false;
IOReturn rtn;
DEBUG_IOLog("%s::watchStateGated(*0x%08x,0x%08x)\n", Name, (int)(*state), (int)mask);
if ((Stage<kStarted)||(Stage>=kTerminated)) return kIOReturnOffline;
if ( !(mask & (PD_S_ACQUIRED | PD_S_ACTIVE)) ) {
(*state) &= ~PD_S_ACTIVE; mask |= PD_S_ACTIVE; watchForInactive = true;
}
while (true) {
if (mask & ~((*state) ^ State)) {
*state = State;
if (watchForInactive && !(State & PD_S_ACTIVE))
rtn = kIOReturnOffline;
else
rtn = kIOReturnSuccess;
break;
}
WatchStateMask |= mask;
retain(); CommandGate->retain();
rtn = CommandGate->commandSleep((void*)&State);
CommandGate->release();
if (OffLine || (Stage<kStarted)||(Stage>=kTerminated)) {
DEBUG_IOLog("%s::watchStateGated() awakend to find port going away!\n", Name);
release();
return kIOReturnOffline;
}
if (rtn == THREAD_TIMED_OUT) {
rtn=kIOReturnTimeout;
break;
} else if (rtn == THREAD_INTERRUPTED) {
rtn=kIOReturnAborted;
break;
}
release();
}
WatchStateMask = 0;
CommandGate->commandWakeup((void*)&State);
DEBUG_IOLog("%s::watchStateGated() returning=%p\n", Name, (void*)rtn);
return rtn;
}
UInt32 Apple16X50UARTSync::nextEvent()
{
UInt32 ret=PD_E_EOQ;
if (Stage==kAcquired) {
retain();
ret=(UInt32)(CommandGate->runAction(nextEventAction));
release();
}
return ret;
}
IOReturn Apple16X50UARTSync::
nextEventAction(OSObject *owner, void*, void*, void*, void*)
{ return (IOReturn)(((Apple16X50UARTSync *)owner)->nextEventGated()); }
UInt32 Apple16X50UARTSync::nextEventGated()
{
UInt32 event=PD_E_EOQ;
if ((Stage==kAcquired) && RxQ)
event = RxQ->peekEvent();
return event;
}
IOReturn Apple16X50UARTSync::executeEvent(UInt32 event, UInt32 data)
{
IOReturn ret=kIOReturnOffline;
if (Stage==kAcquired) {
retain();
ret=CommandGate->runAction(executeEventAction, (void*)event, (void*)data);
release();
}
return ret;
}
IOReturn Apple16X50UARTSync::
executeEventAction(OSObject *owner, void*arg0, void*arg1, void*, void*)
{ return ((Apple16X50UARTSync *)owner)->executeEventGated((UInt32)arg0, (UInt32)arg1); }
IOReturn Apple16X50UARTSync::executeEventGated(UInt32 event, UInt32 data)
{
IOReturn ret = kIOReturnSuccess;
UInt32 tmp, state, delta;
DEBUG_IOLog("%s::executeEventGated(0x%02x,0x%02x)\n", Name, (int)event, (int)data);
if (Stage!=kAcquired) return kIOReturnOffline;
switch (event) {
case PD_E_FLOW_CONTROL:
tmp = kRxAutoFlow & (data ^ FlowControl);
FlowControl = data & ( kRxAutoFlow | kTxAutoFlow | PD_RS232_N_MASK );
if (tmp) {
if (tmp & PD_RS232_A_RXO)
RXO_State = kXO_Idle;
flowMachine();
}
break;
case PD_E_DELAY:
DelayInterval = data;
break;
case PD_E_RXQ_SIZE:
if (State & PD_S_ACTIVE)
ret = kIOReturnBusy;
else
RxQ->setSize(data);
break;
case PD_E_TXQ_SIZE:
if (State & PD_S_ACTIVE)
ret = kIOReturnBusy;
else
TxQ->setSize(data);
break;
default:
delta = 0;
state = State;
ret = executeEventGated(event, data, &state, &delta);
setStateGated(state, delta);
break;
}
return ret;
}
IOReturn Apple16X50UARTSync::
executeEventGated(UInt32 event, UInt32 data, UInt32 *state, UInt32 *delta)
{
IOReturn ret = kIOReturnSuccess;
UInt32 tmp;
DEBUG_IOLog("%s::executeEventGated(0x%02x,0x%02x,*0x%08x,*0x%08x)\n", Name, (int)event, (int)data, (int)*state, (int)*delta);
if (Stage!=kAcquired) return kIOReturnOffline;
switch (event) {
case PD_RS232_E_XON_BYTE:
if (data>0xff)
ret = kIOReturnBadArgument;
else
XOnChar = data;
break;
case PD_RS232_E_XOFF_BYTE:
if (data>0xff)
ret = kIOReturnBadArgument;
else
XOffChar = data;
break;
case PD_E_SPECIAL_BYTE:
if (data&(~0xff))
ret = kIOReturnBadArgument;
else
SW_Special[data>>5] |= (1<<(data&0x1f));
break;
case PD_E_VALID_DATA_BYTE:
if (data&(~0xff))
ret = kIOReturnBadArgument;
else
SW_Special[data>>5] &= ~(1<<(data&0x1f));
break;
case PD_E_FLOW_CONTROL :
tmp = (data>>PD_RS232_D_SHIFT) & kRxAutoFlow & (~FlowControl);
*state = maskMux(*state, data, tmp);
*delta |= tmp;
if (tmp & PD_RS232_S_RXO)
RXO_State = (data & PD_RS232_S_RXO) ? kXOnNeeded : kXOffNeeded;
programMCR(*state);
break;
case PD_E_ACTIVE:
if (BOOLVAL(data))
ret = activatePort();
else
deactivatePort();
break;
case PD_E_DATA_LATENCY:
DataLatInterval = data;
break;
case PD_RS232_E_MIN_LATENCY:
MinLatency = BOOLVAL(data);
Divisor = 0x0000; programUART();
break;
case PD_E_DATA_INTEGRITY:
if ((data < PD_RS232_PARITY_NONE) || (data > PD_RS232_PARITY_SPACE))
ret = kIOReturnBadArgument;
else {
Parity = data;
IgnoreParityErrors = false;
programUART();
}
break;
case PD_E_DATA_RATE:
if ((data < kMinBaud) || (data > MaxBaud))
ret = kIOReturnBadArgument;
else {
BaudRate = data;
programUART();
}
break;
case PD_E_DATA_SIZE:
if ((data < (5 bits)) || (data > (8 bits)) || (data&1))
ret = kIOReturnBadArgument;
else {
DataWidth = data;
programUART();
}
break;
case PD_RS232_E_STOP_BITS:
if ((data < (1 bits)) || (data > (2 bits)))
ret = kIOReturnBadArgument;
else {
StopBits = data;
programUART();
}
break;
case PD_E_RXQ_FLUSH:
if (RxQ) RxQ->flush();
if (!OffLine) outb(kREG_FIFOControl, (FCR_Image | kFIFO_ResetRx));
*state = maskMux(*state, generateRxQState(), (PD_S_RXQ_MASK | kRxAutoFlow));
*delta |= PD_S_RXQ_MASK | kRxAutoFlow;
break;
case PD_E_RX_DATA_INTEGRITY:
if (data==Parity) break;
if (data==PD_RS232_PARITY_DEFAULT) break;
if ((data==PD_RS232_PARITY_ANY) && (Parity!=PD_RS232_PARITY_NONE)) break;
ret = kIOReturnUnsupported;
break;
case PD_E_RX_DATA_RATE:
if ((data != 0) && (data != BaudRate))
ret = kIOReturnUnsupported;
break;
case PD_E_RX_DATA_SIZE:
if ((data != 0) && (data != DataWidth))
ret = kIOReturnUnsupported;
break;
case PD_RS232_E_RX_STOP_BITS:
if ((data != 0) && (data != StopBits))
ret = kIOReturnUnsupported;
break;
case PD_E_TXQ_FLUSH:
if (TxQ) TxQ->flush();
if (!OffLine) outb(kREG_FIFOControl, (FCR_Image | kFIFO_ResetTx));
*state = maskMux(*state, TxQ->getState(), PD_S_TXQ_MASK);
*delta |= PD_S_TXQ_MASK;
break;
case PD_RS232_E_LINE_BREAK :
if (!OffLine) {
LCR_Image = boolBit(LCR_Image, BOOLVAL(data), kLCR_SendBreak);
outb(kREG_LineControl, LCR_Image);
*state = boolBit(*state, BOOLVAL(data), PD_RS232_S_BRK);
*delta |= PD_RS232_S_BRK;
}
break;
case PD_E_DELAY:
if (data > 0) {
DelayTimerRunning=true;
DelayTimer->setTimeoutUS(data);
}
break;
case PD_E_RXQ_HIGH_WATER:
RxQ->setHighWater(data);
*state = maskMux(*state, generateRxQState(), (PD_S_RXQ_MASK | kRxAutoFlow));
*delta |= PD_S_RXQ_MASK | kRxAutoFlow;
break;
case PD_E_RXQ_LOW_WATER:
RxQ->setLowWater(data);
*state = maskMux(*state, generateRxQState(), (PD_S_RXQ_MASK | kRxAutoFlow));
*delta |= PD_S_RXQ_MASK | kRxAutoFlow;
break;
case PD_E_TXQ_HIGH_WATER:
TxQ->setHighWater(data);
*state = maskMux(*state, TxQ->getState(), PD_S_TXQ_MASK);
*delta |= PD_S_TXQ_MASK;
break;
case PD_E_TXQ_LOW_WATER:
TxQ->setLowWater(data);
*state = maskMux(*state, TxQ->getState(), PD_S_TXQ_MASK);
*delta |= PD_S_TXQ_MASK;
break;
default:
DEBUG_IOLog("%s::executeEventGated() unknown event=0x%02x, data=%p\n", Name, (int)event, (void*)data);
ret = kIOReturnBadArgument;
break;
}
return ret;
}
IOReturn Apple16X50UARTSync::requestEvent(UInt32 event, UInt32 *data)
{
DEBUG_IOLog("%s::requestEvent(0x%02x,*0x%02x)\n", Name, (int)event, (int)*data);
if (Stage!=kAcquired) return kIOReturnOffline;
if (data == NULL) return kIOReturnBadArgument;
switch (event) {
case PD_E_ACTIVE : *data = BOOLVAL(State&PD_S_ACTIVE); break;
case PD_E_FLOW_CONTROL: *data = FlowControl; break;
case PD_E_DELAY : *data = DelayInterval; break;
case PD_E_DATA_LATENCY : *data = DataLatInterval; break;
case PD_E_TXQ_SIZE : *data = TxQ->Size; break;
case PD_E_RXQ_SIZE : *data = RxQ->Size; break;
case PD_E_TXQ_LOW_WATER : *data = TxQ->LowWater; break;
case PD_E_RXQ_LOW_WATER : *data = RxQ->LowWater; break;
case PD_E_TXQ_HIGH_WATER : *data = TxQ->HighWater; break;
case PD_E_RXQ_HIGH_WATER : *data = RxQ->HighWater; break;
case PD_E_TXQ_AVAILABLE : *data = TxQ->Size - TxQ->Count; break;
case PD_E_RXQ_AVAILABLE : *data = RxQ->Count; break;
case PD_E_DATA_RATE : *data = BaudRate; break;
case PD_E_RX_DATA_RATE : *data = 0x00; break;
case PD_E_DATA_SIZE : *data = DataWidth; break;
case PD_E_RX_DATA_SIZE : *data = 0x00; break;
case PD_E_DATA_INTEGRITY : *data = Parity; break;
case PD_E_RX_DATA_INTEGRITY : *data = IgnoreParityErrors; break;
case PD_RS232_E_STOP_BITS : *data = StopBits; break;
case PD_RS232_E_RX_STOP_BITS : *data = 0x00; break;
case PD_RS232_E_XON_BYTE : *data = XOnChar; break;
case PD_RS232_E_XOFF_BYTE : *data = XOffChar; break;
case PD_RS232_E_LINE_BREAK : *data = BOOLVAL(State&PD_RS232_S_BRK); break;
case PD_RS232_E_MIN_LATENCY: *data = BOOLVAL(MinLatency); break;
default : DEBUG_IOLog("%s::requestEvent() unknown event=0x%02x\n", Name, (int)event);
return kIOReturnBadArgument;
}
return kIOReturnSuccess;
}
IOReturn Apple16X50UARTSync::enqueueEvent(UInt32 event, UInt32 data, bool sleep)
{
IOReturn ret=kIOReturnOffline;
retain();
if ((Stage==kAcquired)&&(State&PD_S_ACTIVE)) {
assert(CommandGate);
ret=CommandGate->runAction(enqueueEventAction, (void*)event, (void*)data, (void*)sleep);
}
release();
return ret;
}
IOReturn Apple16X50UARTSync::
enqueueEventAction(OSObject *owner, void*arg0, void*arg1, void*arg2, void*)
{ return ((Apple16X50UARTSync *)owner)->enqueueEventGated((UInt32)arg0, (UInt32)arg1, (bool)arg2); }
IOReturn Apple16X50UARTSync::enqueueEventGated(UInt32 event, UInt32 data, bool sleep)
{
DEBUG_IOLog("%s::enqueueEventGated(0x%02x,0x%02x,%s)\n", Name, (int)event, (int)data, BOOLSTR(sleep));
if (Stage!=kAcquired) return kIOReturnOffline;
if (!(State&PD_S_ACTIVE)) return kIOReturnOffline;
while (!(TxQ->enqueueEventTry(event, data))) {
UInt32 state=0;
IOReturn rtn;
if (!sleep) return kIOReturnNoResources;
rtn = watchStateGated(&state, (UInt32)PD_S_TXQ_FULL);
if (rtn != kIOReturnSuccess) return rtn;
}
if (TxQ->enqueueThresholdExceeded())
setStateGated(TxQ->getState(), PD_S_TXQ_MASK);
startTxEngine();
return kIOReturnSuccess;
}
IOReturn Apple16X50UARTSync::dequeueEvent(UInt32 *event, UInt32 *data, bool sleep)
{
IOReturn ret=kIOReturnOffline;
if ((!event) || (!data)) return kIOReturnBadArgument;
retain();
if ((Stage==kAcquired) && (State&PD_S_ACTIVE)) {
assert(CommandGate);
ret=CommandGate->runAction(dequeueEventAction, (void*)event, (void*)data, (void*)sleep);
}
release();
return ret;
}
IOReturn Apple16X50UARTSync::
dequeueEventAction(OSObject *owner, void*arg0, void*arg1, void*arg2, void*)
{ return ((Apple16X50UARTSync *)owner)->dequeueEventGated((UInt32*)arg0, (UInt32*)arg1, (bool)arg2); }
IOReturn Apple16X50UARTSync::dequeueEventGated(UInt32 *event, UInt32 *data, bool sleep)
{
DEBUG_IOLog("%s::dequeueEventGated(*0x%02x,*0x%02x,%s)\n", Name, (int)*event, (int)*data, BOOLSTR(sleep));
if (Stage!=kAcquired) return kIOReturnOffline;
if (!(State&PD_S_ACTIVE)) return kIOReturnOffline;
do {
UInt8 e = RxQ->dequeueEvent(data);
if (e != PD_E_EOQ) {
*event = (UInt32)e;
break; } else {
if (sleep) {
UInt32 state=0;
IOReturn rtn = watchStateGated(&state, (UInt32)PD_S_TXQ_EMPTY);
if (rtn != kIOReturnSuccess) return rtn;
}
}
} while (sleep);
if (RxQ->dequeueThresholdExceeded())
setStateGated(generateRxQState(), PD_S_RXQ_MASK | kRxAutoFlow);
return kIOReturnSuccess;
}
IOReturn Apple16X50UARTSync::
enqueueData(UInt8 *buffer, UInt32 size, UInt32 *count, bool sleep)
{
UInt8 *p = buffer;
DEBUG_IOLog("%s::enqueueData(%p,%d,%p,%s)\n", Name, buffer, (int)size, count, BOOLSTR(sleep));
if (!(buffer && count)) return kIOReturnBadArgument;
*count = 0;
if (Stage!=kAcquired) return kIOReturnOffline;
if (!(State&PD_S_ACTIVE)) return kIOReturnOffline;
retain();
while (*count < size) {
UInt32 chunkSize, chunkCount=0;
IOReturn rtn;
chunkSize = min((size-(*count)), 2048);
rtn = CommandGate->runAction(enqueueDataAction, (void*)p, (void*)chunkSize,
(void*)&chunkCount, (void*)sleep);
if (rtn != kIOReturnBadArgument) {
*count += chunkCount;
p += chunkCount;
}
if (rtn != kIOReturnSuccess) {
release();
return rtn;
}
}
release();
return kIOReturnSuccess;
}
IOReturn Apple16X50UARTSync::
enqueueDataAction(OSObject *owner, void*arg0, void*arg1, void*arg2, void*arg3)
{ return ((Apple16X50UARTSync *)owner)->enqueueDataGated((UInt8*)arg0, (UInt32)arg1, (UInt32*)arg2, (bool)arg3); }
IOReturn Apple16X50UARTSync::
enqueueDataGated(UInt8 *buffer, UInt32 size, UInt32 *count, bool sleep)
{
UInt8 *p = buffer;
DEBUG_IOLog("%s::enqueueDataGated(%p,%d,%p,%s)\n", Name, buffer, (int)size, count, BOOLSTR(sleep));
if (!(buffer && count)) return kIOReturnBadArgument;
*count = 0;
if (Stage!=kAcquired) return kIOReturnOffline;
if (!(State&PD_S_ACTIVE)) return kIOReturnOffline;
for (*count=0; (*count) < size; (*count)++) {
IOReturn rtn = enqueueEventGated(PD_E_VALID_DATA_BYTE, (UInt32)(*p), sleep);
if (rtn != kIOReturnSuccess) return rtn;
p++;
}
if (TxQ->enqueueThresholdExceeded())
setStateGated(TxQ->getState(), PD_S_TXQ_MASK);
startTxEngine();
return kIOReturnSuccess;
}
IOReturn Apple16X50UARTSync::
dequeueData(UInt8 *buffer, UInt32 size, UInt32 *count, UInt32 min)
{
UInt8 *p = buffer;
IOReturn rtn = kIOReturnSuccess;
enum { kTimerDisarmed, kTimerArmed, kTimerStarted } timerControl;
DEBUG_IOLog("%s::dequeueData(%p,%d,%p,%d)\n", Name, buffer, (int)size, count, (int)min);
if (!(count && buffer && (size >= min))) return kIOReturnBadArgument;
*count = 0;
if (Stage!=kAcquired) {
return kIOReturnOffline;
}
if (!(State&PD_S_ACTIVE)) {
return kIOReturnOffline;
}
while (*count < size) {
UInt32 chunkSize, chunkCount;
chunkSize = min((size-(*count)), 2048);
if (!CommandGate) return kIOReturnOffline;
retain();
rtn = CommandGate->runAction(dequeueDataAction, (void*)p, (void*)chunkSize, (void*)&chunkCount, (void*)(false));
release();
if (rtn != kIOReturnSuccess) return rtn;
if (chunkCount==0) { if ((*count) >= min) return rtn;
else break;
}
*count += chunkCount; p += chunkCount;
}
retain();
timerControl = ((DataLatInterval > 0) && ((min-(*count)) > 1)) ? kTimerArmed : kTimerDisarmed;
while (*count < min) {
UInt32 chunkSize, chunkCount;
if ((timerControl == kTimerArmed) && (*count)) {
WorkLoop->runAction(timerControlAction, DataLatTimer, (void*)DataLatInterval); timerControl = kTimerStarted;
}
chunkSize = min((min-(*count)), (timerControl == kTimerArmed) ? (UInt32)1 : (UInt32)2048);
rtn = CommandGate->runAction(dequeueDataAction, (void*)p, (void*)chunkSize, (void*)&chunkCount, (void*)(true));
if (rtn == kIOReturnBadArgument) break;
*count += chunkCount;
p += chunkCount;
if ( (rtn != kIOReturnSuccess) || (chunkCount == 0) )
break; }
if (timerControl == kTimerStarted)
WorkLoop->runAction(timerControlAction, DataLatTimer); release();
return rtn;
}
IOReturn Apple16X50UARTSync::
dequeueDataAction(OSObject *owner, void*arg0, void*arg1, void*arg2, void*arg3)
{ return ((Apple16X50UARTSync *)owner)->dequeueDataGated((UInt8*)arg0, (UInt32)arg1, (UInt32*)arg2, (UInt32)arg3); }
IOReturn Apple16X50UARTSync::
dequeueDataGated(UInt8 *buffer, UInt32 size, UInt32 *count, bool sleep)
{
UInt8 *p = buffer, event;
UInt32 data='?', bytes;
IOReturn rtn = kIOReturnSuccess;
DEBUG_IOLog("%s::dequeueDataGated(%p,%d,%p,%s)\n", Name, buffer, (int)size, count, BOOLSTR(sleep));
if (!(buffer && count)) return kIOReturnBadArgument;
*count = bytes = 0;
if (Stage!=kAcquired) return kIOReturnOffline;
if (!(State&PD_S_ACTIVE)) return kIOReturnOffline;
while (bytes < size) {
event = RxQ->peekEvent();
if (event==PD_E_VALID_DATA_BYTE) {
assert(RxQ->Count);
event=RxQ->dequeueEvent(&data);
assert(event==PD_E_VALID_DATA_BYTE);
*p++ = (UInt8)data;
bytes++;
} else if ((event==PD_E_EOQ) && sleep) {
UInt32 state=0;
rtn = watchStateGated(&state, (UInt32)PD_S_RXQ_EMPTY);
if (rtn != kIOReturnSuccess) break;
} else break;
}
*count = bytes;
if (RxQ->dequeueThresholdExceeded())
setStateGated(generateRxQState(), PD_S_RXQ_MASK | kRxAutoFlow);
return rtn;
}
bool Apple16X50UARTSync::attach(IOService *provider)
{
DEBUG_IOLog("%s::attach(%p)\n", Name, provider);
assert(Stage == kAllocated);
Provider = OSDynamicCast(Apple16X50BusInterface, provider);
if (!Provider) return false;
if ((!Provider->metaCast("com_apple_driver_16X50PCCard")) && (!Provider->metaCast("com_apple_driver_16X50PCI")) &&
(!Provider->metaCast("com_apple_driver_16X50ACPI")))
return false;
if (!IOService::attach(provider)) return false;
Stage = kAttached;
return true;
}
bool Apple16X50UARTSync::attachToChild(IORegistryEntry *child, const IORegistryPlane *plane)
{
if (!super::attachToChild(child, plane))
return false;
if ((child->metaCast("IOSerialBSDClient")) && (plane == gIOServicePlane))
child->setProperty(kNPProductNameKey, getProperty(kNPProductNameKey));
return true;
}
bool Apple16X50UARTSync::start(IOService *provider)
{
char buf[80];
OSString *nameString = OSDynamicCast(OSString, getProperty(kIOTTYSuffixKey));
if (nameString) {
sprintf(buf, "%s%s", Name, (char *)(nameString->getCStringNoCopy()));
setName(buf);
Name=getName();
}
DEBUG_IOLog("%s::start(%p)\n", Name, provider);
assert(Stage == kAttached);
if (!super::start(provider)) return false;
WorkLoop = OSDynamicCast(IOWorkLoop, Provider->getWorkLoop(fRefCon));
if (!WorkLoop) return false;
WorkLoop->retain();
CommandGate = IOCommandGate::commandGate(this);
if (!CommandGate) goto fail;
if (WorkLoop->addEventSource(CommandGate) != kIOReturnSuccess) goto fail;
CommandGate->enable();
FrameTimer = IOTimerEventSource::timerEventSource(this, frameTimeoutAction);
if (!FrameTimer) goto fail;
if (WorkLoop->addEventSource(FrameTimer) != kIOReturnSuccess) goto fail;
FrameTimer->enable();
DataLatTimer = IOTimerEventSource::timerEventSource(this, dataLatencyTimeoutAction);
if (!DataLatTimer) goto fail;
if (WorkLoop->addEventSource(DataLatTimer) != kIOReturnSuccess) goto fail;
DataLatTimer->enable();
DelayTimer = IOTimerEventSource::timerEventSource(this, delayTimeoutAction);
if (!DelayTimer) goto fail;
if (WorkLoop->addEventSource(DelayTimer) != kIOReturnSuccess) goto fail;
DelayTimer->enable();
#ifdef HEARTBEAT
HeartBeatTimer = IOTimerEventSource::timerEventSource(this, heartbeatTimeoutAction);
if (!HeartBeatTimer) goto fail;
if (WorkLoop->addEventSource(HeartBeatTimer) != kIOReturnSuccess) goto fail;
HeartBeatTimer->enable();
#endif
TxQ = new Apple16X50Queue(kTxQ);
RxQ = new Apple16X50Queue(kRxQ);
resetUART();
sprintf (buf, "%s FIFO=%d MaxBaud=%d", IOFindNameForValue(UART_Type, gUARTnames), (int)FIFO_Size, (int)(MaxBaud>>1));
IOLog("%s: Detected %s\n", Name, buf);
setProperty("UART Type", buf);
Stage = kStarted;
registerService();
return true;
fail:
DEBUG_IOLog("%s::start() Unable to setup EventSources\n", Name);
RELEASE(WorkLoop);
return false;
}
bool Apple16X50UARTSync::terminate(IOOptionBits options)
{
Stage = kTerminated;
OffLine = true;
CommandGate->commandWakeup((void*)&Acquired); CommandGate->commandWakeup((void*)&State); return super::terminate(options);
}
bool Apple16X50UARTSync::finalize(IOOptionBits options)
{
DEBUG_IOLog("%s::finalize()\n", Name);
assert((Stage==kReleased)||(Stage==kStarted)||(Stage==kTerminated));
assert(CommandGate);
Stage = kFinalized;
OffLine = true;
CommandGate->commandWakeup((void*)&Acquired); CommandGate->commandWakeup((void*)&State); if (DelayTimer) {
DelayTimer->cancelTimeout();
DelayTimer->disable();
}
if (DataLatTimer) {
DataLatTimer->cancelTimeout();
DataLatTimer->disable();
}
if (FrameTimer) {
FrameTimer->cancelTimeout();
FrameTimer->disable();
}
#ifdef HEARTBEAT
if (HeartBeatTimer) {
HeartBeatTimer->cancelTimeout();
HeartBeatTimer->disable();
}
#endif
RxQ->setSize(0);
TxQ->setSize(0);
return super::finalize(options);
}
void Apple16X50UARTSync::stop(IOService *provider)
{
retain();
DEBUG_IOLog("%s::stop(%p)\n", Name, provider);
assert(Stage==kFinalized);
Stage = kStopped;
OffLine = true;
CommandGate->runAction(stopAction, (void*)provider);
super::stop(provider);
release();
}
IOReturn Apple16X50UARTSync::
stopAction(OSObject *owner, void*arg0, void*, void*, void*)
{ ((Apple16X50UARTSync *)owner)->stopGated((IOService *)arg0); return kIOReturnSuccess; }
void Apple16X50UARTSync::stopGated(IOService *provider)
{
DEBUG_IOLog("%s::stopGated(%p)\n", Name, provider);
OffLine = true;
CommandGate->commandWakeup((void*)&Acquired);
CommandGate->commandWakeup((void*)&State);
}
void Apple16X50UARTSync::free()
{
DEBUG_IOLog("%s::free()\n", Name);
assert(Stage == kStopped);
assert(WorkLoop);
if (DelayTimer) {
WorkLoop->removeEventSource(DelayTimer);
RELEASE(DelayTimer);
}
if (DataLatTimer) {
WorkLoop->removeEventSource(DataLatTimer);
RELEASE(DataLatTimer);
}
if (FrameTimer) {
WorkLoop->removeEventSource(FrameTimer);
RELEASE(FrameTimer);
}
#ifdef HEARTBEAT
if (HeartBeatTimer) {
WorkLoop->removeEventSource(HeartBeatTimer);
RELEASE(HeartBeatTimer);
}
#endif
WorkLoop->removeEventSource(CommandGate);
RELEASE(WorkLoop);
if (RxQ) delete RxQ;
if (TxQ) delete TxQ;
Stage = kFreed;
super::free();
}
void Apple16X50UARTSync::flowMachine()
{
register UInt32 state = State;
if ((FlowControl & PD_RS232_A_RFR) || (FlowControl & PD_RS232_A_RXO)) {
if (FlowControl & PD_RS232_A_DTR)
state = boolBit(state, (State & PD_S_ACTIVE), PD_RS232_A_DTR);
if (FlowControl & PD_RS232_A_RFR)
state = boolBit(state, ((RxQ->Count <= RxQ->HighWater) && (State & PD_S_ACTIVE)), PD_RS232_A_RFR);
else if (FlowControl & PD_RS232_A_RXO) {
state = boolBit(state, (RxQ->Count <= RxQ->HighWater), PD_RS232_A_RXO);
if (RxQ->Count > RxQ->HighWater)
RXO_State = kXOffNeeded;
else if ((RXO_State != kXO_Idle) && (State & PD_S_ACTIVE))
RXO_State = kXOnNeeded;
}
} else if (FlowControl & PD_RS232_A_DTR) {
state = boolBit(state, ((RxQ->Count <= RxQ->HighWater) && (State & PD_S_ACTIVE)), PD_RS232_A_DTR);
}
setStateGated(state, kRxAutoFlow);
}
UInt32 Apple16X50UARTSync::generateRxQState()
{
UInt32 state = State & (kRxAutoFlow | kTxAutoFlow);
tQueueState fifostate = RxQ->getState();
state = maskMux(state, (UInt32)fifostate >> PD_S_RX_OFFSET, PD_S_RXQ_MASK);
switch (fifostate) {
case kQueueEmpty :
case kQueueLow :
if (FlowControl & PD_RS232_A_RFR) {
state |= PD_RS232_S_RFR;
} else if (FlowControl & PD_RS232_A_RXO) {
state |= PD_RS232_S_RXO;
switch (RXO_State) {
case kXOffSent :
case kXO_Idle : RXO_State=kXOnNeeded; break;
case kXOffNeeded : RXO_State=kXOnSent; break;
default : break;
}
} else if (FlowControl & PD_RS232_A_DTR) {
state |= PD_RS232_S_DTR;
}
break;
case kQueueHigh :
case kQueueFull :
if (FlowControl & PD_RS232_A_RFR) {
state &= ~PD_RS232_S_RFR;
} else if (FlowControl & PD_RS232_A_RXO) {
state &= ~PD_RS232_S_RXO;
switch (RXO_State) {
case kXOnSent :
case kXO_Idle : RXO_State=kXOffNeeded; break;
case kXOnNeeded : RXO_State=kXOffSent; break;
default : break;
}
} else if (FlowControl & PD_RS232_A_DTR) {
state &= ~PD_RS232_S_DTR;
}
break;
case kQueueMedium : break;
}
return state;
}
IOReturn Apple16X50UARTSync::activatePort()
{
DEBUG_IOLog("%s::activatePort()\n", Name);
if (State & PD_S_ACTIVE) return kIOReturnSuccess;
if (OffLine) return kIOReturnOffline;
if (RxQ->Size == 0) RxQ->setSize(); if (TxQ->Size == 0) TxQ->setSize(); programUART();
outb(kREG_FIFOControl, (FCR_Image | kFIFO_ResetTx | kFIFO_ResetRx));
setStateGated(PD_S_ACTIVE, PD_S_ACTIVE); flowMachine(); setStateGated(TxQ->getState() | generateRxQState(),
PD_S_TXQ_MASK | PD_S_RXQ_MASK | kRxAutoFlow);
if ( !(State & PD_S_TX_BUSY) ) FrameTimer->setTimeoutUS(1);
outb(kREG_IRQ_Enable, IER_Mask &
( kIRQEN_RxDataAvail | kIRQEN_TxDataEmpty | kIRQEN_LineStatus | kIRQEN_ModemStatus ) );
return kIOReturnSuccess;
}
void Apple16X50UARTSync::deactivatePort()
{
DEBUG_IOLog("%s::deactivatePort()\n", Name);
if (State & PD_S_ACTIVE) {
outb(kREG_IRQ_Enable, OffLine?0x00:IER_Mask & kIRQEN_ModemStatus);
#ifdef HEARTBEAT
HeartBeatTimer->cancelTimeout();
#endif
DelayTimer->cancelTimeout();
DataLatTimer->cancelTimeout();
FrameTimer->cancelTimeout();
setStateGated(0, PD_S_ACTIVE);
TxQ->setSize(0); RxQ->setSize(0); flowMachine();
}
}
IOReturn Apple16X50UARTSync::
timerControlAction(OSObject *owner, void*arg0, void*, void*, void*)
{
UInt32 usec = (UInt32)arg0;
if (usec )
return ((IOTimerEventSource *)owner)->setTimeoutUS(usec);
else
((IOTimerEventSource *)owner)->cancelTimeout();
return kIOReturnSuccess;
}
inline void Apple16X50UARTSync::startTxEngine()
{
if (OffLine) return;
if (!(State & PD_S_TX_BUSY))
FrameTimer->setTimeoutUS(1);
DEBUG_IOLog("%s::startTxEngine()\n", Name);
}
void Apple16X50UARTSync::
dataLatencyTimeoutAction(OSObject *owner, IOTimerEventSource *)
{
Apple16X50UARTSync *me = (Apple16X50UARTSync *)owner;
DEBUG_IOLog("%s::dataLatencyTimeoutAction(%p,*)\n", ((Apple16X50UARTSync *)owner)->Name, owner);
me->RxQ->enqueueEvent(PD_E_DATA_LATENCY, 0);
if (me->RxQ->enqueueThresholdExceeded())
me->setStateGated(me->generateRxQState(), PD_S_RXQ_MASK | kRxAutoFlow);
}
void Apple16X50UARTSync::
frameTimeoutAction(OSObject *owner, IOTimerEventSource *)
{
DEBUG_IOLog("%s::frameTimeoutAction(%p,*) F+", ((Apple16X50UARTSync *)owner)->Name, owner);
((Apple16X50UARTSync *)owner)->FrameTimerRunning = false;
((Apple16X50UARTSync *)owner)->interrupt();
DEBUG_IOLog("-F\n");
}
void Apple16X50UARTSync::
delayTimeoutAction(OSObject *owner, IOTimerEventSource *)
{
DEBUG_IOLog("%s::delayTimeoutAction(%p,*) D+", ((Apple16X50UARTSync *)owner)->Name, owner);
((Apple16X50UARTSync *)owner)->DelayTimerRunning = false;
((Apple16X50UARTSync *)owner)->interrupt();
DEBUG_IOLog("-D\n");
}
#ifdef HEARTBEAT
void Apple16X50UARTSync::
heartbeatTimeoutAction(OSObject *owner, IOTimerEventSource *)
{
Apple16X50UARTSync *me = (Apple16X50UARTSync *)owner;
DEBUG_IOLog("%s::heartbeatTimeoutAction(%p,*)\n", ((Apple16X50UARTSync *)owner)->Name, owner);
if (!OffLine && (me->State & PD_S_ACQUIRED)) {
if (me->HeartBeatNeeded) {
DEBUG_IOLog("H+");
me->interrupt();
DEBUG_IOLog("-H\n");
}
me->HeartBeatNeeded = true;
me->HeartBeatTimer->setTimeoutUS(me->HeartBeatInterval);
}
}
#endif
void Apple16X50UARTSync::interrupt()
{
UInt32 delta=0, state=State;
UInt32 tmp=0, data=0;
UInt8 lsr, event=0;
UInt32 fifoOverRun=0, fifoFree=0;
bool waitForTxIdle = FrameTimerRunning;
bool again;
bool breakme=false;
#ifdef HEARTBEAT
HeartBeatNeeded = false;
#endif
if (OffLine || (Stage != kAcquired)) {
DEBUG_IOLog("interrupt() while offline or not acquired!\n");
return; }
DEBUG_putc('/');
do {
DEBUG_putc('A');
again = false;
while ((lsr = inb(kREG_LineStatus)) & kLSR_DataReady) {
data = inb(kREG_Data);
DEBUG_putc('B');
if ((lsr == 0xff) && (data == 0xff)) {
DEBUG_IOLog("%s::interrupt() UART has been removed or powered down!\\\n", Name);
return;
}
if (!(state & PD_S_RX_ENABLE))
continue; if ((lsr & kLSR_Overrun) && !fifoOverRun)
fifoOverRun = FIFO_Size; if (lsr & kLSR_GotBreak) {
RxQ->enqueueEvent(PD_RS232_E_RX_LINE_BREAK);
} else if (lsr & kLSR_FramingError ) {
RxQ->enqueueEvent(PD_E_FRAMING_BYTE, data);
} else if ((lsr & kLSR_ParityError) && (!IgnoreParityErrors)) {
RxQ->enqueueEvent(PD_E_INTEGRITY_BYTE, data);
} else { data &= DataMask;
if ((FlowControl & (PD_RS232_A_TXO|PD_RS232_N_TXO))&&(data == XOnChar)) {
state |= PD_RS232_S_TXO;
delta |= PD_RS232_S_TXO;
} else if ((FlowControl & (PD_RS232_A_TXO|PD_RS232_N_TXO))&&(data == XOffChar) ) {
state &= ~PD_RS232_S_TXO;
delta |= PD_RS232_S_TXO;
} else { if (FlowControl & PD_RS232_A_XANY) {
state |= PD_RS232_S_TXO;
delta |= PD_RS232_S_TXO;
}
event = ((SW_Special[data>>5] & (1<<(data&0x1f))) ? PD_E_SPECIAL_BYTE : PD_E_VALID_DATA_BYTE);
RxQ->enqueueEvent(event, data);
DEBUG_putc('\'');
DEBUG_putc((char)data);
breakme=true;
}
}
if (fifoOverRun && (--fifoOverRun == 0))
RxQ->enqueueEvent(PD_E_HW_OVERRUN_ERROR);
}
if (fifoOverRun) { RxQ->enqueueEvent(PD_E_HW_OVERRUN_ERROR);
fifoOverRun = 0;
}
if ((state&PD_S_ACTIVE) && (RxQ->enqueueThresholdExceeded())) {
if (breakme) {
breakme=false;
}
state = maskMux(state, generateRxQState(), (PD_S_RXQ_MASK | kRxAutoFlow));
delta |= ((PD_S_RXQ_MASK | kRxAutoFlow) & (State ^ state));
programMCR(state);
}
state = maskMux(state, msrState(), kMSR_StateMask);
delta |= (kMSR_StateMask & (State ^ state));
if ((fifoFree == 0) && (!(lsr & kLSR_TxDataEmpty)))
continue; if (lsr & kLSR_TxIdle) {
waitForTxIdle = false;
fifoFree = FIFO_Size;
if (FrameTimerRunning) {
FrameTimer->cancelTimeout();
FrameTimerRunning = false;
}
}
if ((FlowControl & PD_RS232_A_RXO) && (RXO_State > kXO_Idle)) {
outb(kREG_Data, (RXO_State == kXOnNeeded) ? XOnChar : XOffChar);
(int)RXO_State = -(int)(RXO_State);
if (fifoFree) fifoFree--;
} else if (DelayTimerRunning) {
fifoFree = 0;
} else switch (TxQ->peekEvent()) {
case PD_E_EOQ :
fifoFree = 0;
break;
case PD_E_VALID_DATA_BYTE : DEBUG_putc('D');
if ( (~state) & ((kTxAutoFlow & FlowControl) | PD_S_TX_ENABLE) ) {
fifoFree = 0; break;
}
if (((lsr&(kLSR_TxDataEmpty|kLSR_TxIdle))==kLSR_TxDataEmpty) && (TxQ->peekEvent(1)!=PD_E_VALID_DATA_BYTE))
waitForTxIdle = true;
while (fifoFree) {
event = TxQ->peekEvent();
if (event == PD_E_VALID_DATA_BYTE) {
event = TxQ->dequeueEvent(&data);
assert(event == PD_E_VALID_DATA_BYTE);
outb(kREG_Data, (UInt8)data);
fifoFree--;
} else break;
}
break;
default: DEBUG_putc('C');
fifoFree = 0;
if (lsr & kLSR_TxIdle) {
event = TxQ->dequeueEvent(&data);
executeEventGated(event, data, &state, &delta);
again = true;
} else waitForTxIdle = true;
break;
}
} while (again || fifoFree || ((inb(kREG_IRQ_Ident)&kIRQID_None)==0));
if ((lsr&kLSR_TxDataEmpty) && (!(lsr&kLSR_TxIdle)))
waitForTxIdle = true;
if (waitForTxIdle && (!FrameTimerRunning)) {
FrameTimerRunning = true;
FrameTimer->setTimeoutUS(FrameInterval);
}
if (TxQ->dequeueThresholdExceeded())
state = maskMux(state, TxQ->getState(), PD_S_TXQ_MASK);
state = boolBit(state, !(lsr & kLSR_TxIdle), PD_S_TX_BUSY);
delta |= (State ^ state); if ( tmp = ((delta << PD_RS232_D_SHIFT) & FlowControl) )
RxQ->enqueueEvent(PD_E_FLOW_CONTROL, (state & PD_RS232_S_MASK) | tmp);
State = state;
if (delta & WatchStateMask) {
DEBUG_putc('W');
assert(CommandGate);
CommandGate->commandWakeup((void*)&State);
}
DEBUG_putc('\\');
return;
}
Apple16X50UARTSync *Apple16X50UARTSync::
probeUART(Apple16X50BusInterface *provider, void *refCon, tUART_Type type)
{
UInt32 fifoSize;
DEBUG_IOLog("Apple16X50UARTSync::probeUART(%p,%p,%s)\n",
provider, refCon, IOFindNameForValue(type, gUARTnames));
if ((!provider->metaCast("com_apple_driver_16X50PCCard")) && (!provider->metaCast("com_apple_driver_16X50PCI")) &&
(!provider->metaCast("com_apple_driver_16X50ACPI")))
return NULL;
if (type == kUART_Unknown)
type = identifyUART(provider, refCon);
switch (type) {
case kUART_16550C :
case kUART_16C1550 : fifoSize = 16; break;
case kUART_16C650 : fifoSize = 32; break;
case kUART_16C750 :
case kUART_16C950 : fifoSize = 128; break;
default : return NULL;
}
Apple16X50UARTSync *uart = new Apple16X50UARTSync;
if (!uart) return NULL;
uart->Provider = NULL;
uart->RxQ = NULL;
uart->TxQ = NULL;
uart->WorkLoop = NULL;
uart->CommandGate = NULL;
uart->Name = "Apple16X50UARTSync";
uart->Stage = kAllocated;
uart->State = 0x00000000;
uart->WatchStateMask = 0x00000000;
uart->Acquired = false;
uart->OffLine = false;
uart->FrameTimer = NULL;
uart->FrameInterval=0;
uart->FrameTimerRunning=false;
uart->DataLatTimer = NULL;
uart->DataLatInterval=0;
uart->DelayTimer = NULL;
uart->DelayInterval=0;
uart->DelayTimerRunning=false;
#ifdef HEARTBEAT
uart->HeartBeatTimer = NULL;
uart->HeartBeatInterval=0;
uart->HeartBeatNeeded=false;
#endif
uart->UART_Type=type;
uart->MaxBaud = 115200 bits;
uart->FIFO_Size = fifoSize;
uart->LCR_Image=0x00;
uart->FCR_Image=0x00;
uart->IER_Mask=0x00;
bzero(uart->SW_Special, 256>>3);
uart->DataWidth=0;
uart->DataMask=0x00;
uart->StopBits=0;
uart->Parity=0;
uart->BaudRate=0;
uart->MasterClock=k1xMasterClock;
uart->Divisor=0x0000;
uart->MinLatency=false;
uart->IgnoreParityErrors=false;
uart->FlowControl = 0x00000000; uart->RXO_State = kXO_Idle;
uart->XOnChar=kXOnChar;
uart->XOffChar=kXOffChar;
return uart;
}
#define INB(reg) ( provider->getReg((reg), refCon) )
#define OUTB(reg,val) ( provider->setReg((reg), val, refCon) )
tUART_Type Apple16X50UARTSync::
identifyUART(Apple16X50BusInterface *provider, void *refCon)
{
register UInt32 tmp;
DEBUG_IOLog("Apple16X50UARTSync::identifyUART()\n");
OUTB(kREG_LineControl, kLCR_DivisorAccess);
OUTB(kREG_DivisorLSB, 0x5a);
if (INB(kREG_DivisorLSB)!=0x5a) return kUART_Unknown;
OUTB(kREG_DivisorLSB, 0xa5);
if (INB(kREG_DivisorLSB)!=0xa5) return kUART_Unknown;
OUTB(kREG_LineControl, 0x00);
DEBUG_IOLog("Apple16X50UARTSync::identifyUART() BRG Divisor is accessable\n");
OUTB(kREG_Scratch, 0x5a);
if (INB(kREG_Scratch)!=0x5a) return kUART_8250;
OUTB(kREG_Scratch, 0xa5);
if (INB(kREG_Scratch)!=0xa5) return kUART_8250;
DEBUG_IOLog("Apple16X50UARTSync::identifyUART() Scratchpad is accessable\n");
OUTB(kREG_FIFOControl, kFIFO_Enable);
tmp = INB(kREG_IRQ_Ident) & kIRQID_FIFOEnabled;
OUTB(kREG_FIFOControl, 0x00);
switch (tmp) {
case 0x00 : return kUART_16450;
case 0x40 : return kUART_16C650;
case 0x80 : return kUART_16550;
case 0xC0 : break;
}
DEBUG_IOLog("Apple16X50UARTSync::identifyUART() FIFO Enable status returned 0xC0\n");
OUTB(kREG_LineControl, 0x00);
OUTB(kREG_Scratch, 0xde);
OUTB(kREG_LineControl, kLCR_DivisorAccess);
OUTB(kREG_Scratch, 0xa9);
tmp = INB(kREG_Scratch);
OUTB(kREG_Scratch, 0x00);
OUTB(kREG_LineControl, 0x00);
if ((INB(kREG_Scratch) == 0xde) && (tmp == 0xa9)) {
DEBUG_IOLog("Apple16X50UARTSync::identifyUART() Alternate Scratchpad is accessable\n");
return kUART_16C650;
}
tmp = INB(kREG_ModemControl) & 0x80;
OUTB(kREG_ModemControl, 0x00);
if (tmp == 0x80) return kUART_16C1550;
OUTB(kREG_FIFOControl, kFIFO_Enable);
OUTB(kREG_LineControl, 0x00);
OUTB(kREG_LineControl, 0xbf);
tmp = INB(kREG_LineControl);
OUTB(kREG_LineControl, 0x00);
OUTB(kREG_FIFOControl, 0x00);
if (tmp == 0x80) {
DEBUG_IOLog("Apple16X50UARTSync::identifyUART() 0xBF Magic number accepted!\n");
return kUART_16C750;
}
return kUART_16550C;
}
#undef INB
#undef OUTB
UInt32 Apple16X50UARTSync::determineMasterClock()
{
UInt32 count;
UInt32 sample[5];
UInt32 samples=0;
UInt32 tries=10;
IOSimpleLock *prot;
prot = IOSimpleLockAlloc();
if (!prot) return 0;
IOSimpleLockInit(prot);
resetUART();
programMCR(0, false, true);
setDivisor(1);
outb(kREG_LineControl, kLCR_8bitData | kLCR_1bitStop | kLCR_NoParity);
while (tries && (samples < 5)) {
AbsoluteTime before, after;
uint64_t duration;
IOSleep(1); count = 0;
while (inb(kREG_LineStatus) & kLSR_DataReady) {
inb(kREG_Data);
if (count++ >= 256) goto nogood;
}
IOSimpleLockLock(prot); outb(kREG_Data, samples*tries); clock_get_uptime(&before);
count = 0; while (!(inb(kREG_LineStatus) & kLSR_DataReady))
if (count++ >= 256) break;
clock_get_uptime(&after); IOSimpleLockUnlock(prot); if (count >= 256) goto nogood;
if (inb(kREG_Data)!=samples*tries) goto nogood;
SUB_ABSOLUTETIME(&after, &before); absolutetime_to_nanoseconds(after, &duration);
sample[samples]=(UInt32)duration;
if (sample[samples] > 300000) goto nogood;
DEBUG_IOLog("%s::determineMasterClock(): sample[%d/%d]=%d ns took %d loops\n",
Name, (int)samples, (int)tries, (int)duration, (int)count);
samples++;
nogood:
tries--;
}
IOSimpleLockFree(prot);
DEBUG_IOLog("%s::determineMasterClock(): got %d samples out of %d tries: ", Name, (int)samples, 10-(int)tries);
register unsigned int i;
for (i=0; i<samples; i++)
DEBUG_IOLog("%d ", (int)sample[i]);
DEBUG_IOLog("\n");
if (samples<3) goto fail;
for (i=samples-1; i; i--) { register unsigned int j;
for (j=0; j<i; j++)
if (sample[j+1] < sample[j]) {
register UInt32 tmp;
tmp=sample[j];
sample[j] = sample[j+1];
sample[j+1] = tmp;
}
}
samples=sample[samples>>1];
if (samples < 10000) MasterClock = 10 * k1xMasterClock;
else if (samples < 15000) MasterClock = 8 * k1xMasterClock;
else if (samples < 30000) MasterClock = 4 * k1xMasterClock;
else if (samples < 70000) MasterClock = (5 * k1xMasterClock) / 3;
else
fail:
MasterClock = k1xMasterClock;
DEBUG_IOLog("%s::determineMasterClock(): median=%d ns, MasterClock=%d : ", Name, (int)samples, (int)MasterClock);
return MasterClock;
}
void Apple16X50UARTSync::setMasterClock(UInt32 clock)
{
MasterClock = clock;
}
void Apple16X50UARTSync::setDivisor(UInt32 div)
{
register UInt8 lcr;
DEBUG_IOLog("%s::setDivisor(%d)\n", Name, (int)div);
div = CONSTRAIN(0x0001,div,0xffff);
lcr=inb(kREG_LineControl);
outb(kREG_LineControl, lcr | kLCR_DivisorAccess);
outb(kREG_DivisorLSB, (UInt8)(div&0xff) );
outb(kREG_DivisorMSB, (UInt8)((div%0xff00)>>8) );
outb(kREG_LineControl, lcr);
}
UInt32 Apple16X50UARTSync::getDivisor()
{
register UInt8 lcr;
register UInt32 div;
lcr=inb(kREG_LineControl);
outb(kREG_LineControl, lcr | kLCR_DivisorAccess);
div = inb(kREG_DivisorLSB);
div |= (inb(kREG_DivisorMSB)<<8);
outb(kREG_LineControl, lcr);
return div;
}
#ifdef DEBUG
void Apple16X50UARTSync::showRegs()
{
DEBUG_IOLog("%s::showRegs() RX=%02x IER=%02x IIR=%02x LCR=%02x MCR=%02x LSR=%02x MSR=%02x SCR=%02x DIV=%04x\n",
Name, inb(kREG_Data), inb(kREG_IRQ_Enable), inb(kREG_IRQ_Ident), LCR_Image=inb(kREG_LineControl),
inb(kREG_ModemControl), inb(kREG_LineStatus), inb(kREG_ModemStatus), inb(kREG_Scratch), (int)getDivisor()
);
}
#endif
void Apple16X50UARTSync::resetUART()
{
if (OffLine) return; DEBUG_IOLog("%s::resetUART()\n", Name);
DataWidth = 8 bits;
DataMask = 0xff;
StopBits = 1 bits;
Parity = PD_RS232_PARITY_NONE;
IgnoreParityErrors = false;
BaudRate = 9600 bits;
Divisor = 0x0000;
bzero(SW_Special, 256>>3);
XOnChar = kXOnChar;
XOffChar = kXOffChar;
RXO_State = kXO_Idle;
FCR_Image = 0x00;
LCR_Image = 0x00;
IER_Mask = 0x0f;
outb(kREG_IRQ_Enable, 0x00);
outb(kREG_Scratch, 0x00);
outb(kREG_LineControl, 0x00);
outb(kREG_IRQ_Enable, 0x00);
outb(kREG_FIFOControl, kFIFO_ResetRx | kFIFO_ResetTx);
outb(kREG_ModemControl, 0x00);
FlowControl = PD_RS232_A_DTR | PD_RS232_A_RFR | PD_RS232_A_CTS | PD_RS232_A_DSR;
programUART();
if (RxQ) RxQ->setSize(0);
if (RxQ) TxQ->setSize(0);
}
void Apple16X50UARTSync::programUART()
{
UInt8 lcr=0;
UInt16 dlr=0;
UInt32 frameSize=0;
UInt32 frame;
int level=0;
if (OffLine) return; DEBUG_IOLog("%s::programUART()\n", Name);
DataWidth = (DataWidth+1)&(~1); DataWidth = CONSTRAIN((5 bits), DataWidth, (8 bits));
switch (DataWidth) {
case (5 bits) : lcr = kLCR_5bitData; DataMask = 0x1f; break;
case (6 bits) : lcr = kLCR_6bitData; DataMask = 0x3f; break;
case (7 bits) : lcr = kLCR_7bitData; DataMask = 0x7f; break;
case (8 bits) : lcr = kLCR_8bitData; DataMask = 0xff; break;
}
switch (StopBits) {
case 3 : case (2 bits) : lcr |= kLCR_2bitStop;
if (DataWidth == (5 bits))
StopBits = 3; else
StopBits = (2 bits);
break;
default : lcr |= kLCR_1bitStop;
StopBits = (1 bits);
break;
}
switch (Parity) {
case PD_RS232_PARITY_ODD : lcr |= kLCR_OddParity; break;
case PD_RS232_PARITY_EVEN : lcr |= kLCR_EvenParity; break;
case PD_RS232_PARITY_MARK : lcr |= kLCR_MarkParity; break;
case PD_RS232_PARITY_SPACE : lcr |= kLCR_SpaceParity; break;
default : lcr |= kLCR_NoParity; break;
}
if (State & PD_RS232_S_BRK)
lcr |= kLCR_SendBreak;
BaudRate = CONSTRAIN(kMinBaud, BaudRate, MaxBaud);
dlr = (MasterClock) / (BaudRate << 3);
int err_lo = ((MasterClock) / (dlr << 3)) - BaudRate;
int err_hi = BaudRate - ((MasterClock) / ((dlr+1) << 3));
if (err_lo > err_hi) dlr++;
if (dlr != Divisor) {
setDivisor(Divisor = dlr);
frameSize = ( (DataWidth + StopBits) +
((Parity==PD_RS232_PARITY_NONE) ? (1 bits) : (2 bits) ) ); frame = ( (1000000 * frameSize) / BaudRate); FrameInterval = frame;
level = min( ((kTenMS/frame)-3), (FIFO_Size-(kTwoMS/frame)) );
DEBUG_IOLog("%s::programUART() MasterClock=%dHz frame=%dbits BaudRate=%dbps FrameInterval=%dµs\n",
Name, (int)MasterClock, (int)(frameSize>>1), (int)(BaudRate>>1), (int)FrameInterval);
switch (UART_Type) {
case kUART_16550C :
case kUART_16C1550 :
if (MinLatency) FCR_Image = kFIFO_Enable | kFIFO_01of16;
else if (level<4) FCR_Image = kFIFO_Enable | kFIFO_01of16;
else if (level<8) FCR_Image = kFIFO_Enable | kFIFO_04of16;
else FCR_Image = kFIFO_Enable | kFIFO_08of16;
break;
case kUART_16C650 :
if (MinLatency) FCR_Image = 0x00;
else if (level<16) FCR_Image = kFIFO_Enable | kFIFO_08of32;
else if (level<24) FCR_Image = kFIFO_Enable | kFIFO_16of32;
else FCR_Image = kFIFO_Enable | kFIFO_24of32;
break;
case kUART_16C750 :
case kUART_16C950 :
if (MinLatency) FCR_Image = kFIFO_Enable | kFIFO_001of128;
else if (level<32) FCR_Image = kFIFO_Enable | kFIFO_001of128;
else if (level<64) FCR_Image = kFIFO_Enable | kFIFO_032of128;
else FCR_Image = kFIFO_Enable | kFIFO_064of128;
outb(kREG_FIFOControl, FCR_Image);
outb(kREG_LineControl, lcr); outb(kREG_LineControl, 0xbf); outb(kREG_FuncControl, 0x10); DEBUG_IOLog("%s::programUART() set enhanced mode=0x%02x!\n", Name, inb(kREG_FuncControl));
outb(kREG_LineControl, lcr); break;
default :
FCR_Image = 0x00;
break;
}
outb(kREG_FIFOControl, FCR_Image);
DEBUG_IOLog("%s::programUART() FIFO Target=%d/%d FCR=0x%02x\n", Name, level, (int)FIFO_Size, FCR_Image);
}
outb(kREG_LineControl, lcr);
LCR_Image = lcr;
}
void Apple16X50UARTSync::programMCR(UInt32 state, bool irqen, bool loop)
{
UInt8 mcr=0;
if (OffLine) return; if (irqen) mcr |= kMCR_Out2; if (loop) mcr |= kMCR_Loop; if (state&PD_RS232_S_DTR) mcr |= kMCR_DTR;
if (state&PD_RS232_S_RFR) mcr |= kMCR_RTS;
outb(kREG_ModemControl, mcr);
}
#ifdef REFBUG
void Apple16X50UARTSync::retain() const
{
super::retain();
DEBUG_IOLog("%s::retain()==%d\n", Name, getRetainCount());
}
void Apple16X50UARTSync::release() const
{
DEBUG_IOLog("%s::release()==%d\n",Name, getRetainCount());
super::release();
}
#endif