#include <IOKit/IOLib.h>
#include <IOKit/IOService.h>
#include <IOKit/assert.h>
#include <IOKit/IOTimerEventSource.h>
#include <IOKit/IODeviceTreeSupport.h>
#include <sys/kdebug.h>
#include "AppleRS232Serial.h"
#include <IOKit/serial/IORS232SerialStreamSync.h>
extern void flush_dcache(vm_offset_t addr, unsigned count, int phys);
#if USE_ELG
extern com_apple_iokit_XTrace *gXTrace;
extern UInt32 gTraceID;
#endif
bool CommandExecuted(SccChannel *Channel, UInt32 iterator);
bool SuckDataFromTheDBDMAChain(SccChannel *Channel);
UInt32 CommandStatus(SccChannel *Channel, UInt32 commandNumber);
#if USE_WORK_LOOPS
void rearmRxTimer(SccChannel *Channel, UInt32 timerDelay);
#endif
#define STRICT_85C30
#if 0
#define REGISTER_DELAY() IODelay(10)
#else
#define REGISTER_DELAY()
#endif
static UInt8 LocalDataBits[2][4] =
{
{ kRx5Bits, kRx6Bits, kRx7Bits, kRx8Bits},
{ kTx5Bits, kTx6Bits, kTx7Bits, kTx8Bits}
};
static UInt8 SCCConfigTable[] =
{
R4, k1StopBit, R1, kDMAReqSelect | kDMAReqOnRx | kParityIsSpCond,
R3, kRx8Bits & ~kRxEnable, R5, kTx8Bits | kRTS & ~kTxEnable, R9, kNV, R10, kNRZ, R11, kRxClockBRG | kTxClockBRG, R12, 0x0A, R13, 0x00, R14, kBRGFromRTxC, R15, kERegEnable, R7, kEReq, R14, kBRGEnable, R3, kRx8Bits | kRxEnable, R5, kTx8Bits | kTxEnable | kRTS, R1, kDMAReqSelect | kDMAReqOnRx | kParityIsSpCond | kWReqEnable,
R15, kBreakAbortIE | kCTSIE| kDCDIE | kERegEnable, R0, kResetExtStsInt, R0, kResetExtStsInt, R1, kDMAReqSelect | kDMAReqOnRx | kParityIsSpCond | kExtIntEnable | kRxIntOnlySC | kWReqEnable, R9, kMIE | kNV };
void initChip(PortInfo_t *port)
{
ELG(0, 0, "initChip");
port->TX_Parity = PD_RS232_PARITY_NONE;
port->RX_Parity = PD_RS232_PARITY_DEFAULT;
port->DLRimage = 0x0000;
port->FCRimage = 0x00;
ProbeSccDevice(port);
}
void ProbeSccDevice(PortInfo_t *port)
{
ELG(0, 0, "ProbeSccDevice");
port->DataRegister = (UInt8 *)(port->ChipBaseAddress + channelDataOffsetRISC);
port->ControlRegister = (UInt8 *)(port->ChipBaseAddress + channelControlOffsetRISC);
port->ConfigWriteRegister = (unsigned int)(port->ChipBaseAddress & 0xffffff00);
port->baudRateGeneratorEnable = kBRGEnable;
port->rtxcFrequency = 3686400;
SccWriteReg(port, R1, 0);
ELG(port->DataRegister, port->ControlRegister, "ProbeSccDevice - Data register, Control register");
}
void FixZeroBug(SccChannel *Channel)
{
ELG(0, 0, "FixZeroBug");
SccWriteReg(Channel, 9, (Channel->whichPort == serialPortA ? kChannelResetA : kChannelResetB) | kNV);
SccWriteReg(Channel, 4, kX1ClockMode | k8BitSyncMode); SccWriteReg(Channel, 3, kRx8Bits & ~kRxEnable);
SccWriteReg(Channel, 5, kTx8Bits | kRTS & ~kTxEnable);
SccWriteReg(Channel, 9, kNV); SccWriteReg(Channel, 11, kRxClockBRG | kTxClockBRG);
SccWriteReg(Channel, 12, 0); SccWriteReg(Channel, 13, 0); SccWriteReg(Channel, 14, kLocalLoopback | kBRGFromPCLK);
SccWriteReg(Channel, 14, kLocalLoopback | kBRGFromPCLK | kBRGEnable);
SccWriteReg(Channel, 3, kRx8Bits | kRxEnable);
SccWriteReg(Channel, 0, kResetExtStsInt); SccWriteReg(Channel, 0, kResetExtStsInt);
SccWriteReg(Channel, 9, kNV);
SccWriteReg(Channel, 4, kX16ClockMode | kStopBitsMask);
SccWriteReg(Channel, 3, kRx8Bits & ~kRxEnable);
while (SccReadReg(Channel, R0) & kRxCharAvailable)
{
(void)SccReadReg(Channel, R8); SccWriteReg(Channel, R0, kResetExtStsInt ); SccWriteReg(Channel, R0, kErrorReset); }
}
void OpenScc(SccChannel *Channel)
{
UInt32 SCCConfigTblSize = sizeof(SCCConfigTable)/sizeof(UInt8);
UInt32 i;
ELG(0, 0, "OpenScc");
FixZeroBug(Channel);
SccWriteReg(Channel, 9, (Channel->whichPort == serialPortA ? kChannelResetA : kChannelResetB) | kNV);
for (i = 0; i < SCCConfigTblSize; i += 2)
{
SccWriteReg(Channel, SCCConfigTable[i], SCCConfigTable[i + 1]);
}
SccEnableInterrupts(Channel, kSccInterrupts, 0);
SccWriteReg(Channel, R0, kErrorReset);
SccWriteReg(Channel, R0, kErrorReset);
SccGetDCD(Channel);
}
void SccCloseChannel(SccChannel *Channel)
{
UInt8 dontCare;
ELG(0, 0, "SccCloseChannel");
if (Channel->AreTransmitting == true)
{
Channel->AreTransmitting = false;
IOSleep(1000);
}
dontCare = SccDisableInterrupts(Channel, kSccInterrupts); dontCare = SccDisableInterrupts(Channel, kRxInterrupts); dontCare = SccDisableInterrupts(Channel, kTxInterrupts);
SccWriteReg(Channel, R1, kWReqDisable);
SccWriteReg(Channel, R11, kRxClockRTxC | kTxClockRTxC);
SccWriteReg(Channel, R14, kBRGDisable);
SccWriteReg(Channel, R15, kDCDIE); SccWriteReg(Channel, R0, kResetExtStsInt);
SccWriteReg(Channel, R0, kResetExtStsInt); SccWriteReg(Channel, R1, kExtIntEnable);
if (Channel->whichPort == serialPortA)
{
SccWriteReg(Channel, R9, kChannelResetA);
} else {
SccWriteReg(Channel, R9, kChannelResetB);
}
SccEnableDMAInterruptSources(Channel, false);
}
bool SccSetStopBits(SccChannel *Channel, UInt32 numbits)
{
UInt8 value;
ELG(0, numbits, "SccSetStopBits");
switch(numbits)
{
case 0:
value = 0;
break;
case 2:
value = k1StopBit;
break;
case 3:
value = k1pt5StopBits;
break;
case 4:
value = k2StopBits;
break;
default:
return false;
break;
}
SccWriteReg(Channel, R4, (Channel->lastWR[4] & ~kStopBitsMask) | value);
return true;
}
bool SccSetParity(SccChannel *Channel, ParityType ParitySetting)
{
ELG(0, ParitySetting, "SccSetParity");
switch(ParitySetting)
{
case PD_RS232_PARITY_NONE:
SccWriteReg(Channel, 4, Channel->lastWR[4] & ~kParityEnable);
SccWriteReg(Channel, 1, Channel->lastWR[1] & ~kParityIsSpCond);
break;
case PD_RS232_PARITY_ODD:
SccWriteReg(Channel, 4, Channel->lastWR[4] & ~kParityEven | kParityEnable);
SccWriteReg(Channel, 1, Channel->lastWR[1] | kParityIsSpCond);
break;
case PD_RS232_PARITY_EVEN:
SccWriteReg(Channel, 4, Channel->lastWR[4] | kParityEven | kParityEnable);
SccWriteReg(Channel, 1, Channel->lastWR[1] | kParityIsSpCond);
break;
case PD_RS232_PARITY_MARK:
case PD_RS232_PARITY_SPACE:
default:
return false;
}
SccEnableInterrupts( Channel, kRxInterrupts, 0);
SccEnableInterrupts( Channel, kSccInterrupts, 0);
SccWriteReg(Channel, R0, kResetRxInt);
SccWriteReg(Channel, R0, kResetExtStsInt);
return true;
}
bool SccSetDataBits(SccChannel *Channel, UInt32 numDataBits)
{
ELG(0, numDataBits, "SccSetDataBits");
if (numDataBits >= 5 && numDataBits <= 8)
{
numDataBits -= 5;
SccWriteReg(Channel, R5, (Channel->lastWR[5] & ~kTxBitsMask) | LocalDataBits[1][numDataBits]);
SccWriteReg(Channel, R3, (Channel->lastWR[3] & ~kRxBitsMask) | LocalDataBits[0][numDataBits]);
return true;
}
return false;
}
void SccSetCTSFlowControlEnable(SccChannel *Channel, bool enableCTS )
{
ELG(0, enableCTS, "SccSetCTSFlowControlEnable");
if (enableCTS)
{
SccWriteReg(Channel, R15, Channel->lastWR[15] | kCTSIE);
} else {
SccWriteReg(Channel, R15, Channel->lastWR[15] & ~kCTSIE);
}
}
void SccChannelReset(SccChannel *Channel)
{
ELG(0, 0, "SccChannelReset");
switch(Channel->whichPort)
{
case serialPortA:
SccWriteReg(Channel, R9, kChannelResetA | kNV);
break;
case serialPortB:
SccWriteReg(Channel, R9, kChannelResetB | kNV);
break;
default:
break;
}
}
bool SccSetBaud(SccChannel *Channel, UInt32 NewBaud)
{
UInt32 brgConstant;
UInt8 previousState;
UInt8 wr4Mirror;
ELG(0, NewBaud, "SccSetBaud");
previousState = SccDisableInterrupts(Channel, kSerialInterrupts);
wr4Mirror = Channel->lastWR[4] & (~kClockModeMask);
if (NewBaud == 115200)
{
SccWriteReg(Channel, 4, wr4Mirror | kX32ClockMode);
} else {
SccWriteReg(Channel, 4, wr4Mirror | kX16ClockMode);
}
brgConstant = 0;
if ((NewBaud < 115200) && (NewBaud > 0))
{
brgConstant = -2 + (1 + Channel->rtxcFrequency / (16 * NewBaud)) / 2;
if (brgConstant < 0 )
{
brgConstant = 0;
} else {
if (brgConstant > 0xFFFF)
{
brgConstant = 0xFFFF;
}
}
}
Channel->baudRateGeneratorLo = (UInt8)brgConstant; Channel->baudRateGeneratorHi = (UInt8)(brgConstant >> 8);
SccWriteReg(Channel, R14, Channel->lastWR[ 14 ] & (~kBRGEnable));
SccWriteReg(Channel, R12, Channel->baudRateGeneratorLo);
SccWriteReg(Channel, R13, Channel->baudRateGeneratorHi);
if ((NewBaud == 115200) || (NewBaud == 230400))
{
SccWriteReg(Channel, R11, (kRxClockRTxC | kTxClockRTxC));
} else {
SccWriteReg(Channel, R11, (kRxClockBRG | kTxClockBRG));
SccWriteReg(Channel, R14, (kBRGEnable));
}
SccEnableInterrupts(Channel, kSerialInterrupts, previousState);
Channel->BaudRate = NewBaud;
return true;
}
bool SccConfigureForMIDI(SccChannel *Channel, UInt32 ClockMode)
{
UInt8 previousState;
ELG(0, ClockMode, "SccConfigureForMIDI");
Channel->baudRateGeneratorLo = 0x00;
Channel->baudRateGeneratorHi = 0x00;
previousState = SccDisableInterrupts(Channel, kSerialInterrupts);
SccWriteReg(Channel, R4, (Channel->lastWR[4] & ~kClockModeMask | ClockMode));
SccWriteReg(Channel, R11, (kRxClockTRxC | kTxClockTRxC));
SccWriteReg(Channel, R14, Channel->lastWR[14] & (~kBRGEnable));
SccWriteReg(Channel, R12, Channel->baudRateGeneratorLo);
SccWriteReg(Channel, R13, Channel->baudRateGeneratorHi);
SccWriteReg(Channel, R1, Channel->lastWR[1] & ~kExtIntEnable);
SccWriteReg(Channel, R15, Channel->lastWR[15] & ~kCTSIE);
SccEnableInterrupts(Channel, kSerialInterrupts, previousState);
return true;
}
UInt8 SccReadReg(SccChannel *Channel, UInt8 sccRegister)
{
UInt8 ReturnValue;
IOLockLock(Channel->SCCAccessLock);
if (sccRegister != R0 )
{
*((volatile UInt8 *)Channel->ControlRegister) = sccRegister;
SynchronizeIO();
REGISTER_DELAY();
}
ReturnValue = *((volatile UInt8 *)Channel->ControlRegister);
IOLockUnlock(Channel->SCCAccessLock);
return ReturnValue;
}
bool SccWriteReg(SccChannel *Channel, UInt8 sccRegister, UInt8 Value)
{
IOLockLock(Channel->SCCAccessLock);
if (sccRegister <= kNumSCCWR )
{
*((volatile UInt8 *)Channel->ControlRegister) = sccRegister;
SynchronizeIO();
REGISTER_DELAY();
*((volatile UInt8 *)Channel->ControlRegister) = Value;
SynchronizeIO();
REGISTER_DELAY();
Channel->lastWR[sccRegister] = Value;
}
IOLockUnlock(Channel->SCCAccessLock);
return true;
}
void SccHandleExtErrors(SccChannel *Channel)
{
UInt8 errorCode;
ELG(0, 0, "SccHandleExtErrors");
errorCode = SccReadReg(Channel, 1);
ELG(0, errorCode, "SccHandleExtErrors");
if (errorCode & kRxErrorsMask)
{
ALERT(0, errorCode, "SccHandleExtErrors - An SCC Error Occurred ***");
SccWriteReg(Channel, R0, kErrorReset);
SccWriteReg(Channel, R0, kErrorReset);
}
}
void PPCSerialTxDMAISR(void *identity, void *istate, SccChannel *Channel)
{
AbsoluteTime deadline;
ELG(identity, Channel, "PPCSerialTxDMAISR");
Channel->Stats.ints++;
clock_interval_to_deadline(1, 1, &deadline);
thread_call_func_delayed((thread_call_func_t)SccdbdmaStartTransmission, Channel, deadline);
}
void PPCSerialRxDMAISR(void *identity, void *istate, SccChannel *Channel)
{
AbsoluteTime deadline;
ELG(identity, Channel, "PPCSerialRxDMAISR");
Channel->Stats.ints++;
clock_interval_to_deadline(1, 1, &deadline);
thread_call_func_delayed((thread_call_func_t) SccdbdmaRxHandleCurrentPosition, Channel, deadline);
}
void PPCSerialISR(OSObject *identity, void *istate, SccChannel *Channel)
{
ELG(identity, Channel, "PPCSerialISR");
SccHandleExtErrors(Channel);
SccHandleExtInterrupt(identity, istate, Channel);
SccEnableInterrupts(Channel, kSccInterrupts, 0);
}
void SccHandleExtInterrupt(OSObject *identity, void *istate, SccChannel *Channel)
{
AppleRS232Serial *RS232;
UInt8 ExtCondition;
UInt32 HW_FlowControl;
bool dcdChanged = false;
bool currentCTSState;
AbsoluteTime currentTime;
UInt64 uint64_currentTime;
UInt32 uint32_currentTime;
SerialDBDMAStatusInfo *dmaInfo;
ELG(0, 0, "SccHandleExtInterrupt");
if (!Channel)
return;
RS232 = (AppleRS232Serial *)identity;
ExtCondition = SccReadReg(Channel, R0);
if (ExtCondition & kRxCharAvailable)
ELG(0, ExtCondition, "SccHandleExtInterrupt - kRxCharAvailable");
if (ExtCondition & kZeroCount)
ELG(0, ExtCondition, "SccHandleExtInterrupt - kZeroCount");
if (ExtCondition & kTxBufferEmpty)
ELG(0, ExtCondition, "SccHandleExtInterrupt - kTxBufferEmpty");
if (ExtCondition & kDCDAsserted)
ELG(0, ExtCondition, "SccHandleExtInterrupt - kDCDAsserted");
if ((ExtCondition & kDCDAsserted) && !Channel->DCDState)
{
Channel->DCDState = true;
dcdChanged = true;
} else {
if (!(ExtCondition & kDCDAsserted) && Channel->DCDState)
{
Channel->DCDState = false;
dcdChanged = true;
}
}
if (dcdChanged) { if (Channel->DCDState)
{
RS232->setStateGated(PD_RS232_S_CAR, PD_RS232_S_CAR);
} else {
RS232->setStateGated(0, PD_RS232_S_CAR);
}
}
if (ExtCondition & kSyncHunt)
ELG(0, ExtCondition, "SccHandleExtInterrupt - kSyncHunt");
currentCTSState = ((ExtCondition & kCTSAsserted) == kCTSAsserted);
if (Channel->lastCTSState != currentCTSState)
{
Channel->lastCTSState = currentCTSState;
if (Channel->ctsTransitionCount > 76) {
SccSetCTSFlowControlEnable(Channel, false); }
clock_get_uptime (¤tTime);
absolutetime_to_nanoseconds (currentTime, &uint64_currentTime);
uint32_currentTime = uint64_currentTime/1000000;
if (uint32_currentTime >= Channel->lastCTSTime + 10) {
Channel->lastCTSTime = uint32_currentTime;
Channel->ctsTransitionCount = 0;
}
++Channel->ctsTransitionCount;
}
if (ExtCondition & kCTSAsserted)
ELG(0, ExtCondition, "SccHandleExtInterrupt - kCTSAsserted");
HW_FlowControl = Channel->FlowControl & PD_RS232_S_CTS;
if (HW_FlowControl && (Channel->FlowControlState != PAUSE_SEND))
{
dmaInfo = &Channel->TxDBDMAChannel;
Channel->FlowControlState = PAUSE_SEND;
IODBDMAPause(dmaInfo->dmaBase); } else {
HW_FlowControl = Channel->FlowControl & PD_RS232_S_CTS;
if (HW_FlowControl && (Channel->FlowControlState == PAUSE_SEND))
{
dmaInfo = &Channel->TxDBDMAChannel;
Channel->FlowControlState = CONTINUE_SEND;
IODBDMAContinue(dmaInfo->dmaBase);
if (!Channel->AreTransmitting && UsedSpaceinQueue(&(Channel->TX)))
{
AbsoluteTime deadline;
clock_interval_to_deadline(1, 1, &deadline);
thread_call_func_delayed((thread_call_func_t) SccdbdmaStartTransmission, Channel, deadline);
}
}
}
if (ExtCondition & kTXUnderRun)
{
ELG(0, ExtCondition, "SccHandleExtInterrupt - kTXUnderRun");
RS232->setStateGated(0, PD_S_TX_BUSY);
}
if (ExtCondition & kBreakReceived)
ELG(0, ExtCondition, "SccHandleExtInterrupt - kBreakReceived");
SccWriteReg(Channel, R0, kResetExtStsInt);
}
bool SetUpTransmit(SccChannel *Channel)
{
ELG(0, 0, "SetUpTransmit");
if (Channel->AreTransmitting == TRUE)
{
ELG(0, 0, "SetUpTransmit - Already transmitting");
return false;
}
if (GetQueueStatus(&(Channel->TX)) != queueEmpty)
{
SccdbdmaStartTransmission(Channel);
}
return true;
}
UInt8 SccDisableInterrupts(SccChannel *Channel, UInt32 WhichInts)
{
UInt8 previousState = 0;
UInt8 sccState;
ELG(0, 0, "SccDisableInterrupts");
if (Channel->ControlRegister)
{
switch ( WhichInts)
{
case kTxInterrupts: sccState = Channel->lastWR[5];
previousState = (UInt8)sccState;
SccWriteReg(Channel, R5, sccState & ~kTxEnable);
break;
case kRxInterrupts: sccState = Channel->lastWR[3];
previousState = (UInt8)sccState;
SccWriteReg(Channel, R3, sccState & ~kRxEnable);
break;
case kSccInterrupts: sccState = Channel->lastWR[9];
previousState = (UInt8)sccState;
SccWriteReg(Channel, R9, sccState & ~kMIE & ~kNV);
break;
default:
break;
}
}
return previousState;
}
void SccEnableInterrupts(SccChannel *Channel, UInt32 WhichInts, UInt8 previousState)
{
ELG(0, 0, "SccEnableInterrupts");
switch (WhichInts)
{
case kTxInterrupts: SccWriteReg(Channel, R5, Channel->lastWR[5] | kTxEnable);
break;
case kRxInterrupts: SccWriteReg(Channel, R3, Channel->lastWR[3] | kRxEnable);
SccWriteReg(Channel, R0, kResetRxInt);
break;
case kSccInterrupts: SccWriteReg(Channel, R9, Channel->lastWR[9] | kMIE | kNV);
break;
default:
break;
}
}
void SccSetBreak(SccChannel *Channel, bool setBreak)
{
ELG(0, setBreak, "SccSetBreak");
if (setBreak)
{
SccWriteReg(Channel, R5, Channel->lastWR[5] | kSendBreak);
} else {
SccWriteReg(Channel, R5, Channel->lastWR[5] & ~kSendBreak);
}
}
void SccSetDTR(SccChannel *Channel, bool assertDTR)
{
ELG(0, assertDTR, "SccSetDTR");
if (assertDTR)
{
SccWriteReg(Channel, R5, Channel->lastWR[5] | kDTR);
} else {
SccWriteReg(Channel, R5, Channel->lastWR[5] & ~kDTR);
}
}
void SccSetRTS(SccChannel *Channel, bool assertRTS)
{
ELG(0, assertRTS, "SccSetRTS");
if (assertRTS)
{
SccWriteReg(Channel, R5, Channel->lastWR[5] | kRTS);
} else {
SccWriteReg(Channel, R5, Channel->lastWR[5] & ~kRTS);
}
}
bool SccGetDCD(SccChannel *Channel)
{
bool Value;
ELG(0, 0, "SccGetDCD");
Value = (SccReadReg(Channel, R0) & kDCDAsserted);
if (Value)
{
Channel->State |= PD_RS232_S_CAR;
Channel->DCDState = true; } else {
Channel->State &= ~PD_RS232_S_CAR;
Channel->DCDState = false; }
return Value;
}
bool SccGetCTS(SccChannel *Channel)
{
bool Value;
ELG(0, 0, "SccGetCTS");
Value = (SccReadReg(Channel, R0) & kCTSAsserted);
if (Value)
{
Channel->State |= PD_RS232_S_CTS;
} else {
Channel->State &= ~PD_RS232_S_CTS;
}
return Value;
}
void SccSetDMARegisters(SccChannel *Channel, IOService *provider)
{
UInt32 firstDMAMap = 1;
IOMemoryMap *map;
ELG(0, 0, "SccSetDMARegisters");
Channel->TxDBDMAChannel.dmaChannelAddress = NULL;
Channel->TxDBDMAChannel.dmaBase = NULL;
Channel->RxDBDMAChannel.dmaChannelAddress = NULL;
Channel->RxDBDMAChannel.dmaBase = NULL;
for(firstDMAMap = 1; ; firstDMAMap++)
{
map = provider->mapDeviceMemoryWithIndex(firstDMAMap);
if (!map)
return;
if (map->getLength() > 1)
break;
}
Channel->TxDBDMAChannel.dmaChannelAddress = (IODBDMAChannelRegisters*)map->getVirtualAddress();
Channel->TxDBDMAChannel.dmaBase = (IODBDMAChannelRegisters*)map->getVirtualAddress();
map = provider->mapDeviceMemoryWithIndex(firstDMAMap + 1);
if (!map)
return;
Channel->RxDBDMAChannel.dmaChannelAddress = (IODBDMAChannelRegisters*)map->getVirtualAddress();
Channel->RxDBDMAChannel.dmaBase = (IODBDMAChannelRegisters*)map->getVirtualAddress();
}
void SccEnableDMAInterruptSources(SccChannel *Channel, bool onOff)
{
UInt8 dmaRemoveInterrupt = kRxIntAllOrSC | kTxIntEnable;
UInt8 dmaInterruptMask = kDMAReqSelect | kDMAReqOnRx | kDMAReqOnTx | kWReqEnable | kExtIntEnable | kRxIntOnlySC;
UInt8 newRegisterValue;
ELG(0, onOff, "SccEnableDMAInterruptSources");
if (onOff)
{
newRegisterValue = Channel->lastWR[1] & (~dmaRemoveInterrupt) | dmaInterruptMask;
} else {
newRegisterValue = Channel->lastWR[1] & (~dmaInterruptMask) | dmaRemoveInterrupt;
}
SccWriteReg(Channel, R1, newRegisterValue);
SccEnableInterrupts(Channel, kRxInterrupts, 0);
SccWriteReg(Channel, R0, kResetRxInt);
SccWriteReg(Channel, R0, kResetExtStsInt);
}
void SccSetupReceptionChannel(SccChannel *Channel)
{
SerialDBDMAStatusInfo *dmaInfo;
ELG(0, 0, "SccSetupReceptionChannel");
dmaInfo = &Channel->RxDBDMAChannel;
IODBDMAReset(dmaInfo->dmaBase);
dmaInfo->lastPosition = 0;
IODBDMAReset(dmaInfo->dmaBase);
}
void SccFreeReceptionChannel(SccChannel *Channel)
{
SerialDBDMAStatusInfo *dmaInfo;
ELG(0, 0, "SccFreeupReceptionChannel");
if (Channel == NULL)
return;
if (Channel->IODBDMARxLock)
{
IOLockLock(Channel->IODBDMARxLock);
SccdbdmaEndReception(Channel);
dmaInfo = &Channel->RxDBDMAChannel;
#if NEWPHYS
if (dmaInfo->dmaChannelCommandAreaMDP != NULL)
{
dmaInfo->dmaChannelCommandAreaMDP->complete();
dmaInfo->dmaChannelCommandAreaMDP->release();
dmaInfo->dmaChannelCommandAreaMDP = NULL;
}
#else
if (dmaInfo->dmaChannelCommandArea != NULL)
IOFreeAligned(dmaInfo->dmaChannelCommandArea, sizeof(IODBDMADescriptor) * dmaInfo->dmaNumberOfDescriptors);
#endif
#if NEWPHYS
if (dmaInfo->dmaTransferBufferMDP != NULL)
{
dmaInfo->dmaTransferBufferMDP->complete();
dmaInfo->dmaTransferBufferMDP->release();
dmaInfo->dmaTransferBufferMDP = NULL;
}
#else
if (dmaInfo->dmaTransferBuffer != NULL)
IOFreeAligned(dmaInfo->dmaTransferBuffer, PAGE_SIZE);
#endif
dmaInfo->lastPosition = 0;
dmaInfo->dmaNumberOfDescriptors = 0;
dmaInfo->dmaChannelCommandArea = NULL;
dmaInfo->dmaTransferBuffer = NULL;
IOLockUnlock(Channel->IODBDMARxLock);
}
}
void SccdbdmaDefineReceptionCommands(SccChannel *Channel)
{
SerialDBDMAStatusInfo *dmaInfo;
UInt32 iterator;
IOPhysicalAddress physaddr;
IOPhysicalAddress physaddr1;
ELG(0, 0, "SccdbdmaDefineReceptionCommands");
dmaInfo = &Channel->RxDBDMAChannel;
if ((dmaInfo->dmaChannelCommandArea == NULL) || (dmaInfo->dmaTransferBuffer == NULL))
return;
#if NEWPHYS
IOByteCount temp;
if (dmaInfo->dmaTransferBufferMDP == NULL)
return;
#endif
for (iterator = 0; iterator < dmaInfo->dmaNumberOfDescriptors; iterator ++)
{
if (iterator == 0)
{
#if NEWPHYS
physaddr = dmaInfo->dmaTransferBufferMDP->getPhysicalSegment(0, &temp);
ELG(physaddr, dmaInfo->dmaTransferBuffer, "SccdbdmaDefineReceptionCommands - Physical/Virtual RX buffer");
ELG(0, &dmaInfo->dmaChannelCommandArea[iterator], "SccdbdmaDefineReceptionCommands - RX Command area");
IOMakeDBDMADescriptor(&dmaInfo->dmaChannelCommandArea[iterator], kdbdmaInputMore, kdbdmaKeyStream0, kdbdmaIntAlways, kdbdmaBranchNever,
kdbdmaWaitNever, 1, physaddr);
#else
physaddr = pmap_extract(kernel_pmap, (vm_address_t)dmaInfo->dmaTransferBuffer);
ELG(physaddr, dmaInfo->dmaTransferBuffer, "SccdbdmaDefineReceptionCommands - Physical/Virtual RX buffer");
ELG(0, &dmaInfo->dmaChannelCommandArea[iterator], "SccdbdmaDefineReceptionCommands - RX Command area");
IOMakeDBDMADescriptor(&dmaInfo->dmaChannelCommandArea[iterator], kdbdmaInputMore, kdbdmaKeyStream0, kdbdmaIntAlways, kdbdmaBranchNever,
kdbdmaWaitNever, 1, physaddr);
#endif
} else {
if (iterator == (dmaInfo->dmaNumberOfDescriptors - 1))
{
#if NEWPHYS
physaddr = dmaInfo->dmaTransferBufferMDP->getPhysicalSegment(0, &temp);
ELG(physaddr, dmaInfo->dmaTransferBuffer, "SccdbdmaDefineReceptionCommands - Physical/Virtual RX buffer");
physaddr1 = dmaInfo->dmaChannelCommandAreaMDP->getPhysicalSegment(sizeof(IODBDMADescriptor), &temp);
ELG(physaddr1, &dmaInfo->dmaChannelCommandArea[1], "SccdbdmaDefineReceptionCommands - Physical/Virtual RX Command area [1]");
ELG(0, &dmaInfo->dmaChannelCommandArea[iterator], "SccdbdmaDefineReceptionCommands - RX Command area");
IOMakeDBDMADescriptorDep(&dmaInfo->dmaChannelCommandArea[iterator], kdbdmaInputMore, kdbdmaKeyStream0, kdbdmaIntNever, kdbdmaBranchAlways,
kdbdmaWaitNever, 1, physaddr, physaddr1);
#else
physaddr = pmap_extract(kernel_pmap, (vm_address_t)dmaInfo->dmaTransferBuffer);
ELG(physaddr, dmaInfo->dmaTransferBuffer, "SccdbdmaDefineReceptionCommands - Physical/Virtual");
physaddr1 = pmap_extract(kernel_pmap, (vm_address_t)&dmaInfo->dmaChannelCommandArea[1]);
ELG(physaddr1, &dmaInfo->dmaChannelCommandArea[1], "SccdbdmaDefineReceptionCommands - Physical/Virtual RX Command area [1]");
ELG(0, &dmaInfo->dmaChannelCommandArea[iterator], "SccdbdmaDefineReceptionCommands - RX Command area");
IOMakeDBDMADescriptorDep(&dmaInfo->dmaChannelCommandArea[iterator], kdbdmaInputMore, kdbdmaKeyStream0, kdbdmaIntNever, kdbdmaBranchAlways,
kdbdmaWaitNever, 1, physaddr, physaddr1);
#endif
} else {
#if NEWPHYS
physaddr = dmaInfo->dmaTransferBufferMDP->getPhysicalSegment(iterator, &temp);
ELG(physaddr, &dmaInfo->dmaTransferBuffer[iterator], "SccdbdmaDefineReceptionCommands - Physical/Virtual RX buffer");
ELG(0, &dmaInfo->dmaChannelCommandArea[iterator], "SccdbdmaDefineReceptionCommands - RX Command area");
IOMakeDBDMADescriptor(&dmaInfo->dmaChannelCommandArea[iterator], kdbdmaInputMore, kdbdmaKeyStream0, kdbdmaIntNever, kdbdmaBranchNever,
kdbdmaWaitNever, 1, physaddr);
#else
physaddr = pmap_extract(kernel_pmap, (vm_address_t)dmaInfo->dmaTransferBuffer + iterator);
ELG(physaddr, &dmaInfo->dmaTransferBuffer[iterator], "SccdbdmaDefineReceptionCommands - Physical/Virtual RX buffer");
ELG(0, &dmaInfo->dmaChannelCommandArea[iterator], "SccdbdmaDefineReceptionCommands - RX Command area");
IOMakeDBDMADescriptor(&dmaInfo->dmaChannelCommandArea[iterator], kdbdmaInputMore, kdbdmaKeyStream0, kdbdmaIntNever, kdbdmaBranchNever,
kdbdmaWaitNever, 1, physaddr);
#endif
}
}
}
}
void SccdbdmaStartReception(SccChannel *Channel)
{
SerialDBDMAStatusInfo *dmaInfo;
IODBDMADescriptor *baseCommands;
ELG(0, 0, "SccdbdmaStartReception");
dmaInfo = &Channel->RxDBDMAChannel;
IODBDMAReset(dmaInfo->dmaBase);
IODBDMAReset(dmaInfo->dmaBase);
if ((dmaInfo->dmaChannelCommandArea == NULL) || (dmaInfo->dmaTransferBuffer == NULL))
return;
#if NEWPHYS
IOByteCount temp;
baseCommands = (IODBDMADescriptor *)dmaInfo->dmaChannelCommandAreaMDP->getPhysicalSegment(0, &temp);
#else
baseCommands = (IODBDMADescriptor *)pmap_extract(kernel_pmap, (vm_address_t)dmaInfo->dmaChannelCommandArea);
#endif
ELG(0, baseCommands, "SccdbdmaStartReception - Base physical address");
flush_dcache((vm_offset_t)dmaInfo->dmaChannelCommandArea, sizeof(IODBDMADescriptor) * dmaInfo->dmaNumberOfDescriptors, false);
dmaInfo->lastPosition = 0;
SccEnableInterrupts(Channel, kRxInterrupts, 0);
IODBDMAStart(dmaInfo->dmaBase, baseCommands);
}
bool CommandExecuted(SccChannel *Channel, UInt32 iterator)
{
SerialDBDMAStatusInfo *dmaInfo;
UInt32 result;
ELG(0, iterator, "CommandExecuted");
dmaInfo = &Channel->RxDBDMAChannel;
result = IOGetCCResult(&dmaInfo->dmaChannelCommandArea[iterator]);
if (result != 0)
return true;
return false;
}
UInt32 CommandStatus(SccChannel *Channel, UInt32 commandNumber)
{
SerialDBDMAStatusInfo *dmaInfo;
dmaInfo = &Channel->RxDBDMAChannel;
return IOGetCCResult(&dmaInfo->dmaChannelCommandArea[commandNumber]);
}
void SccdbdmaRxHandleCurrentPosition(SccChannel *Channel)
{
AppleRS232Serial *RS232;
SerialDBDMAStatusInfo *dmaInfo;
UInt32 kDataIsValid;
bool gotData;
natural_t numberOfbytes;
natural_t bitInterval;
natural_t nsec;
UInt8 savedR1Reg;
UInt32 commandStatus;
ELG(0, 0, "SccdbdmaRxHandleCurrentPosition");
if (Channel == NULL)
return;
RS232 = (AppleRS232Serial *)Channel->RS232;
dmaInfo = &Channel->RxDBDMAChannel;
IOLockLock (Channel->IODBDMARxLock);
kDataIsValid = (kdbdmaStatusRun | kdbdmaStatusActive);
if ((dmaInfo->dmaChannelCommandArea == NULL) || (dmaInfo->dmaTransferBuffer == NULL))
{
IOLockUnlock(Channel->IODBDMARxLock);
return;
}
SccHandleExtErrors(Channel);
gotData = SuckDataFromTheDBDMAChain(Channel);
if (gotData) {
RS232->CheckQueues(Channel);
if (Channel->DataLatInterval.tv_nsec == 0)
{
numberOfbytes = (dmaInfo->dmaNumberOfDescriptors - 1) / 3;
bitInterval = (1000000 * 10)/Channel->BaudRate; nsec = bitInterval * 1000 * numberOfbytes; } else {
nsec = Channel->DataLatInterval.tv_nsec;
}
IOLockUnlock (Channel->IODBDMARxLock);
#if USE_WORK_LOOPS
rearmRxTimer(Channel, nsec);
#else
clock_interval_to_deadline(nsec, 1, &deadline);
thread_call_func_delayed((thread_call_func_t) SccdbdmaRxHandleCurrentPosition, Channel, deadline);
#endif
} else {
IODBDMAPause(dmaInfo->dmaBase); savedR1Reg = Channel->lastWR[1];
SccWriteReg(Channel, R1, savedR1Reg & ~kWReqEnable);
IOSetDBDMAChannelControl(dmaInfo->dmaBase, IOClearDBDMAChannelControlBits(kdbdmaPause));
IODBDMAFlush(dmaInfo->dmaBase);
IOSetDBDMAChannelControl(dmaInfo->dmaBase, IOClearDBDMAChannelControlBits(kdbdmaRun));
while(IOGetDBDMAChannelStatus(dmaInfo->dmaBase) & (kdbdmaActive))
{
eieio();
}
SccWriteReg(Channel, R1, savedR1Reg);
commandStatus = CommandStatus(Channel, dmaInfo->lastPosition);
if ((commandStatus & kDataIsValid) == kDataIsValid) {
if (SuckDataFromTheDBDMAChain(Channel))
{
RS232->CheckQueues(Channel);
}
}
IOSetCCResult(&dmaInfo->dmaChannelCommandArea[dmaInfo->lastPosition], 0); eieio();
SccdbdmaStartReception(Channel);
IOLockUnlock (Channel->IODBDMARxLock);
}
}
bool SuckDataFromTheDBDMAChain(SccChannel *Channel)
{
AppleRS232Serial *RS232;
UInt32 SW_FlowControl;
SerialDBDMAStatusInfo *TxdmaInfo;
SerialDBDMAStatusInfo *dmaInfo;
UInt32 iterator;
UInt32 kDataIsValid;
UInt8 byteRead;
bool gotData = false;
UInt32 excess = 0;
ELG(0, 0, "SuckDataFromTheDBDMAChain");
RS232 = (AppleRS232Serial *)Channel->RS232;
SW_FlowControl = Channel->FlowControl & PD_RS232_S_RXO;
dmaInfo = &Channel->RxDBDMAChannel;
TxdmaInfo = &Channel->TxDBDMAChannel;
iterator = dmaInfo->lastPosition;
kDataIsValid = (kdbdmaStatusRun | kdbdmaStatusActive);
while ((CommandStatus(Channel, iterator) & kDataIsValid) == kDataIsValid)
{
IOSetCCResult(&dmaInfo->dmaChannelCommandArea[iterator], 0);
eieio();
if (iterator == (dmaInfo->dmaNumberOfDescriptors - 1))
{
byteRead = dmaInfo->dmaTransferBuffer[0]; iterator = 1;
} else {
byteRead = dmaInfo->dmaTransferBuffer[iterator]; iterator++;
}
if (SW_FlowControl)
{
if (byteRead == Channel->XONchar)
{
if (Channel->RXOstate == NEEDS_XON)
{
Channel->RXOstate = NEEDS_XOFF;
IODBDMAContinue(TxdmaInfo->dmaBase); Channel->FlowControlState = CONTINUE_SEND;
}
} else {
if (byteRead == Channel->XOFFchar)
{
if (Channel->RXOstate == NEEDS_XOFF)
{
Channel->RXOstate = NEEDS_XON;
IODBDMAPause(TxdmaInfo->dmaBase); Channel->FlowControlState = PAUSE_SEND;
}
} else {
AddBytetoQueue(&(Channel->RX), byteRead); }
}
} else {
AddBytetoQueue(&(Channel->RX), byteRead);
excess = UsedSpaceinQueue(&(Channel->RX)) - Channel->RXStats.HighWater;
if (!Channel->aboveRxHighWater)
{
if (excess > 0)
{
Channel->aboveRxHighWater = true;
RS232->CheckQueues(Channel);
}
} else {
if (excess <= 0)
{
Channel->aboveRxHighWater = false;
}
}
}
gotData = true;
}
dmaInfo->lastPosition = iterator;
return gotData;
}
void SccdbdmaEndReception(SccChannel *Channel)
{
SerialDBDMAStatusInfo *dmaInfo;
UInt32 cmdResult = 0;
ELG(0, 0, "SccdbdmaEndReception");
dmaInfo = &Channel->RxDBDMAChannel;
if (dmaInfo->dmaBase)
{
IODBDMAStop(dmaInfo->dmaBase); IODBDMAReset(dmaInfo->dmaBase); }
if (dmaInfo->dmaChannelCommandArea != NULL)
{
cmdResult = IOGetDBDMADescriptor(&dmaInfo->dmaChannelCommandArea[0], result);
dmaInfo->dmaTransferSize = dmaInfo->dmaTransferSize - (cmdResult & 0xFFFF);
ELG(0, dmaInfo->dmaTransferSize, "SccdbdmaEndReception - number of bytes received");
}
}
void SccSetupTansmissionChannel(SccChannel *Channel)
{
SerialDBDMAStatusInfo *dmaInfo;
ELG(0, 0, "SccSetupTansmissionChannel");
dmaInfo = &Channel->TxDBDMAChannel;
IODBDMAReset(dmaInfo->dmaBase); dmaInfo->lastPosition = 0;
IODBDMAReset(dmaInfo->dmaBase);
}
void SccFreeTansmissionChannel(SccChannel *Channel)
{
SerialDBDMAStatusInfo *dmaInfo;
ELG(0, 0, "SccFreeTansmissionChannel");
if (Channel == NULL)
return;
if (Channel->IODBDMATrLock)
{
IOLockLock(Channel->IODBDMATrLock);
SccdbdmaEndTransmission(Channel);
dmaInfo = &Channel->TxDBDMAChannel;
#if NEWPHYS
if (dmaInfo->dmaChannelCommandAreaMDP != NULL)
{
dmaInfo->dmaChannelCommandAreaMDP->complete();
dmaInfo->dmaChannelCommandAreaMDP->release();
dmaInfo->dmaChannelCommandAreaMDP = NULL;
}
#else
if (dmaInfo->dmaChannelCommandArea != NULL)
IOFreeAligned(dmaInfo->dmaChannelCommandArea, PAGE_SIZE);
#endif
#if NEWPHYS
if (dmaInfo->dmaTransferBufferMDP != NULL)
{
dmaInfo->dmaTransferBufferMDP->complete();
dmaInfo->dmaTransferBufferMDP->release();
dmaInfo->dmaTransferBufferMDP = NULL;
}
#else
if (dmaInfo->dmaTransferBuffer != NULL)
IOFreeAligned(dmaInfo->dmaTransferBuffer, PAGE_SIZE);
#endif
dmaInfo->dmaNumberOfDescriptors = 0;
dmaInfo->dmaChannelCommandArea = NULL;
dmaInfo->dmaTransferBuffer = NULL;
IOLockUnlock(Channel->IODBDMATrLock);
}
}
void SccdbdmaDefineTansmissionCommands(SccChannel *Channel)
{
SerialDBDMAStatusInfo *dmaInfo;
IOPhysicalAddress physaddr;
ELG(0, 0, "SccdbdmaDefineTansmissionCommands");
dmaInfo = &Channel->TxDBDMAChannel;
#if NEWPHYS
IOByteCount temp;
physaddr = dmaInfo->dmaTransferBufferMDP->getPhysicalSegment(0, &temp);
IOMakeDBDMADescriptor(&dmaInfo->dmaChannelCommandArea[0], kdbdmaOutputLast, kdbdmaKeyStream0, kdbdmaIntAlways, kdbdmaBranchNever, kdbdmaWaitNever, 0,
physaddr);
#else
physaddr = pmap_extract(kernel_pmap, (vm_address_t)dmaInfo->dmaTransferBuffer);
IOMakeDBDMADescriptor(&dmaInfo->dmaChannelCommandArea[0], kdbdmaOutputLast, kdbdmaKeyStream0, kdbdmaIntAlways, kdbdmaBranchNever, kdbdmaWaitNever, 0,
physaddr);
#endif
ELG(physaddr, dmaInfo->dmaTransferBuffer, "SccdbdmaDefineTansmissionCommands - Physical/Virtual");
IOMakeDBDMADescriptor(&dmaInfo->dmaChannelCommandArea[1], kdbdmaStop, kdbdmaKeyStream0, kdbdmaIntNever, kdbdmaBranchNever, kdbdmaWaitNever, 0, 0);
}
void SccdbdmaStartTransmission(SccChannel *Channel)
{
AppleRS232Serial *RS232;
SerialDBDMAStatusInfo *dmaInfo;
IODBDMADescriptor *baseCommands;
UInt8 *localBuffer;
UInt32 sizeReadFromBuffer = 0;
UInt8 *bufferPtr = 0;
UInt32 bytesToTransfer;
bool wrapped = false;
ELG(0, 0, "SccdbdmaStartTransmission");
if (Channel == NULL)
return;
RS232 = (AppleRS232Serial *)Channel->RS232;
IOLockLock(Channel->IODBDMATrLock);
dmaInfo = &Channel->TxDBDMAChannel;
SccHandleExtErrors(Channel);
Channel->AreTransmitting = TRUE;
RS232->setStateGated(PD_S_TX_BUSY, PD_S_TX_BUSY);
if ((dmaInfo->dmaChannelCommandArea != NULL) && (dmaInfo->dmaTransferBuffer != NULL))
{
IODBDMAReset(dmaInfo->dmaBase);
#if NEWPHYS
IOByteCount temp;
baseCommands = (IODBDMADescriptor *)dmaInfo->dmaChannelCommandAreaMDP->getPhysicalSegment(0, &temp);
#else
baseCommands = (IODBDMADescriptor *)pmap_extract(kernel_pmap, (vm_address_t)dmaInfo->dmaChannelCommandArea);
#endif
localBuffer = dmaInfo->dmaTransferBuffer;
bytesToTransfer = UsedSpaceinQueue(&(Channel->TX));
if (bytesToTransfer)
{
sizeReadFromBuffer = bytesToTransfer;
bufferPtr = BeginDirectReadFromQueue(&(Channel->TX), &sizeReadFromBuffer, &wrapped);
if (bufferPtr && sizeReadFromBuffer)
{
LogData(kSerialOut, sizeReadFromBuffer, (char*)bufferPtr);
if (sizeReadFromBuffer > MAX_BLOCK_SIZE)
sizeReadFromBuffer = MAX_BLOCK_SIZE;
dmaInfo->dmaTransferSize = sizeReadFromBuffer;
bcopy(bufferPtr, localBuffer, sizeReadFromBuffer);
}
} else {
dmaInfo->dmaTransferSize = 0;
}
if ((Channel->FlowControlState != PAUSE_SEND) && (dmaInfo->dmaTransferSize > 0))
{
IOSetDBDMADescriptor(&dmaInfo->dmaChannelCommandArea[0], operation, IOMakeDBDMAOperation(kdbdmaOutputLast, kdbdmaKeyStream0, kdbdmaIntAlways,
kdbdmaBranchNever, kdbdmaWaitNever, dmaInfo->dmaTransferSize));
eieio();
flush_dcache((vm_offset_t)dmaInfo->dmaChannelCommandArea, sizeof(IODBDMADescriptor) * dmaInfo->dmaNumberOfDescriptors, false);
IODBDMAStart(dmaInfo->dmaBase, baseCommands);
EndDirectReadFromQueue(&(Channel->TX), dmaInfo->dmaTransferSize);
RS232->CheckQueues(Channel);
IOLockUnlock(Channel->IODBDMATrLock);
return;
} else {
EndDirectReadFromQueue(&(Channel->TX), 0);
}
}
RS232->CheckQueues(Channel);
Channel->AreTransmitting = FALSE;
RS232->setStateGated(0, PD_S_TX_BUSY);
IOLockUnlock(Channel->IODBDMATrLock);
}
void SccdbdmaEndTransmission(SccChannel *Channel)
{
SerialDBDMAStatusInfo *dmaInfo;
UInt32 cmdResult = 0;
ELG(0, 0, "SccdbdmaEndTransmission");
dmaInfo = &Channel->TxDBDMAChannel;
if (dmaInfo->dmaBase)
{
IODBDMAStop(dmaInfo->dmaBase); IODBDMAReset(dmaInfo->dmaBase); }
SccDisableInterrupts(Channel, kTxInterrupts);
if (dmaInfo->dmaChannelCommandArea != NULL)
{
cmdResult = IOGetDBDMADescriptor(&dmaInfo->dmaChannelCommandArea[0], result);
dmaInfo->dmaTransferSize = dmaInfo->dmaTransferSize - (cmdResult & 0xFFFF);
ELG(0, dmaInfo->dmaTransferSize, "SccdbdmaEndTransmission - number of bytes sent");
}
}
void HandleRxIntTimeout(SccChannel *Channel)
{
}
void rxTimeoutHandler(OSObject *owner, IOTimerEventSource *sender)
{
AppleRS232Serial *serialPortPtr;
serialPortPtr = OSDynamicCast(AppleRS232Serial, owner);
if(serialPortPtr)
{
SccdbdmaRxHandleCurrentPosition(&serialPortPtr->fPort);
}
}
#if USE_WORK_LOOPS
void rearmRxTimer(SccChannel *Channel, UInt32 timerDelay)
{
Channel->rxTimer->setTimeout(timerDelay);
}
#endif