SccChipPrimatives.cpp [plain text]
#include <IOKit/IOLib.h>
#include <IOKit/IOService.h>
#include <IOKit/assert.h>
#include <IOKit/IOTimerEventSource.h>
#include <sys/kdebug.h>
#include "Z85C30.h"
#include "PPCSerialPort.h"
#include "SccChipPrimatives.h"
#include "SccQueuePrimatives.h"
#include <IOKit/serial/IORS232SerialStreamSync.h>
extern void flush_dcache(vm_offset_t addr, unsigned count, int phys);
UInt32 gTimerCanceled = 0;
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
#ifdef SHOW_DEBUG_STRINGS
#define DLOG(fmt, args...) IOLog(fmt, ## args)
#else
#define DLOG(fmt, args...)
#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}
};
void initChip(PortInfo_t *port)
{
port->TX_Parity = PD_RS232_PARITY_NONE;
port->RX_Parity = PD_RS232_PARITY_DEFAULT;
port->DLRimage = 0x0000;
port->FCRimage = 0x00;
ProbeSccDevice(port);
}
void programChip(PortInfo_t *port)
{
}
bool ProbeSccDevice( PortInfo_t *Port) {
DLOG("In ProbeSccDevice\n");
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);
DLOG("SccProbe %x %x\n", (int)Port->DataRegister, (int)Port->ControlRegister);
return(TRUE);
}
#define USE_OLD_SCC_ROUTINES 0
#if USE_OLD_SCC_ROUTINES
void FixZeroBug(SccChannel *Channel)
{
SccWriteReg(Channel, 9, kChannelResetA | kChannelResetB);
IOSleep(10);
SccWriteReg(Channel, 9, (Channel->whichPort == serialPortA ? kChannelResetA : kChannelResetB) | kNV);
SccWriteReg(Channel, 4, kX1ClockMode | kExtSyncMode);
SccWriteReg(Channel, 3, 8 & ~kRxEnable);
SccWriteReg(Channel, 5, 8 & ~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, 8 | kRxEnable);
SccWriteReg(Channel, 0, kResetExtStsInt); SccWriteReg(Channel, 0, kResetExtStsInt);
SccWriteReg(Channel, 9, kNV);
SccWriteReg(Channel, 4, 1);
SccWriteReg(Channel, 3, 8 & ~kRxEnable);
while (SccReadReg(Channel, R0) & kRxCharAvailable) {
(void) SccReadReg(Channel, R8); SccWriteReg(Channel, R0, kResetExtStsInt ); SccWriteReg(Channel, R0, kErrorReset); }
}
#else
void FixZeroBug(SccChannel *Channel)
{
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); }
}
#endif
#if USE_OLD_SCC_ROUTINES
bool OpenScc(SccChannel *Channel)
{
UInt32 i;
static UInt8 SCCConfigTable[] = {
R9, 0, R4, kX16ClockMode | k1StopBit, R3, kRx8Bits, R5, kDTR | kTx8Bits | kRTS, R2, 0x00, R10, kNRZ, R11, kRxClockBRG | kTxClockBRG, R12, 0x00, R13, 0x00, R3, kRx8Bits | kRxEnable, R5, kDTR | kTx8Bits | kTxEnable | kRTS, R14, kBRGEnable, R15, kCTSIE | kDCDIE, R0, kResetExtStsInt, R0, kResetExtStsInt, R1, kDMAReqSelect | kDMAReqOnRx | kDMAReqOnTx | kWReqEnable | kExtIntEnable | kRxIntOnlySC, R9, kMIE | kNV };
UInt32 SCCConfigTblSize = sizeof(SCCConfigTable)/sizeof(UInt8); DLOG("In OpenSCC %d\n", Channel->whichPort);
if ( Channel->whichPort == serialPortB )
SCCConfigTable[1] |= kChannelResetB;
else
SCCConfigTable[1] |= kChannelResetA;
FixZeroBug(Channel);
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);
DLOG("PPCSerOpen End \n");
return( TRUE );
}
#else
bool OpenScc(SccChannel *Channel)
{
UInt32 i;
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 };
UInt32 SCCConfigTblSize = sizeof(SCCConfigTable)/sizeof(UInt8); DLOG("In OpenSCC %d\n", Channel->whichPort);
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);
DLOG("PPCSerOpen End \n");
return( TRUE );
}
#endif
void SccCloseChannel(SccChannel *Channel)
{
InterruptState dontCare;
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);
DLOG("In SccCloseChannel %d\n", Channel->whichPort);
}
bool SccSetStopBits(SccChannel *Channel, UInt32 otSymbolic )
{
UInt8 value;
DLOG("SccSetStopBits %d\n", (int)otSymbolic);
switch( otSymbolic ) {
case 00 :
value = 0x00;
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 )
{
DLOG("SccSetParity %d\n",ParitySetting);
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 )
{
if (numDataBits >= 5 && numDataBits <= 8) {
numDataBits -= 5;
DLOG("In Set Data Bits %d Tx %x Rx %x\n", (int)numDataBits , LocalDataBits[1][numDataBits],
LocalDataBits[0][numDataBits]);
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 )
{
if ( enableCTS )
{
SccWriteReg(Channel, R15, Channel->lastWR[ 15 ] | kCTSIE );
}
else
{
SccWriteReg(Channel, R15, Channel->lastWR[ 15 ] & ~kCTSIE );
}
}
void SccChannelReset(SccChannel *Channel)
{
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 wr4Mirror;
InterruptState 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)
{
Channel->baudRateGeneratorLo = 0x00;
Channel->baudRateGeneratorHi = 0x00;
InterruptState 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;
if (!IOLockTryLock(Channel->SCCAccessLock))
return -1;
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)
{
if (Channel == NULL)
return;
UInt8 errorCode = SccReadReg(Channel, 1);
DLOG("RecErrorStatus Int %x\n\r", errorCode);
#if 0
if (IOGetDBDMAChannelStatus(&Channel->RxDBDMAChannel) & kdbdmaStatusDead)
{
}
#endif
if (errorCode & kRxErrorsMask) {
#ifdef TRACE
KERNEL_DEBUG_CONSTANT((DRVDBG_CODE(DBG_DRVSERIAL, 0x100)) | DBG_FUNC_NONE, errorCode, SccReadReg(Channel, R0), 0, 0, 0
); #endif
IOLog("************An SCC Error Occurred 0x%X\n", errorCode);
SccWriteReg(Channel, R0, kErrorReset);
SccWriteReg(Channel, R0, kErrorReset);
}
}
void PPCSerialTxDMAISR(void *identity, void *istate, SccChannel *Channel)
{
AppleSCCSerial *scc = (AppleSCCSerial *) identity;
Channel->Stats.ints++;
AbsoluteTime deadline;
clock_interval_to_deadline(1, 1, &deadline);
if (scc->fdmaStartTransmissionThread != NULL)
{
OSIncrementAtomic(&scc->fTransmissionCount);
thread_call_enter_delayed(scc->fdmaStartTransmissionThread,deadline);
}
}
void PPCSerialRxDMAISR(void *identity, void *istate, SccChannel *Channel)
{
AppleSCCSerial *scc = (AppleSCCSerial *) identity;
Channel->Stats.ints++;
AbsoluteTime deadline;
clock_interval_to_deadline(1, 1, &deadline);
if (scc->dmaRxHandleCurrentPositionThread != NULL)
{
OSIncrementAtomic(&scc->fCurrentPositionCount);
thread_call_enter_delayed(scc->dmaRxHandleCurrentPositionThread,deadline);
}
}
void SccCurrentPositionDelayedHandler( thread_call_param_t arg, thread_call_param_t )
{
AppleSCCSerial *serialPortPtr = (AppleSCCSerial *)arg;
SccdbdmaRxHandleCurrentPosition(&serialPortPtr->Port);
OSDecrementAtomic(&serialPortPtr->fCurrentPositionCount);
}
void SccStartTransmissionDelayedHandler ( thread_call_param_t arg, thread_call_param_t )
{
AppleSCCSerial *serialPortPtr = (AppleSCCSerial *) arg;
SccdbdmaStartTransmission(&serialPortPtr->Port);
OSDecrementAtomic(&serialPortPtr->fTransmissionCount);
}
void PPCSerialISR(OSObject *identity, void *istate, SccChannel *Channel)
{
SccHandleExtErrors(Channel);
SccHandleExtInterrupt(identity, istate,Channel);
SccEnableInterrupts(Channel, kSccInterrupts, 0);
#ifdef TRACE
KERNEL_DEBUG_CONSTANT((DRVDBG_CODE(DBG_DRVSERIAL, 3)) | DBG_FUNC_END, 0, 0, 0, 0, 0); #endif
}
bool SccHandleExtInterrupt(OSObject *identity, void *istate, SccChannel *Channel)
{
UInt8 ExtCondition;
UInt32 HW_FlowControl;
if (!Channel)
return false;
AppleSCCSerial *scc = (AppleSCCSerial *) identity;
ExtCondition = SccReadReg(Channel, R0 );
if (ExtCondition & kRxCharAvailable)
DLOG("Ext-> kRxCharAvailable\n");
if (ExtCondition & kZeroCount)
DLOG("Ext-> kZeroCount\n");
if (ExtCondition & kTxBufferEmpty)
DLOG("Ext-> kTxBufferEmpty\n");
bool dcdChanged = false;
if ( (ExtCondition & kDCDAsserted) && !Channel->DCDState) {
Channel->DCDState = true;
dcdChanged = true;
if ((Channel->whichPort == serialPortA) && (Channel->gDCPModemFound))
{
if (Channel->DCPModemSupportPtr)
{
if (Channel->gDCPUserClientSet)
{
Channel->DCPModemSupportPtr->callDCPModemSupportFunctions (DCPFunction_SetDCD, (UInt8) kOn, NULL, NULL);
}
}
}
}
else if ( !(ExtCondition & kDCDAsserted) && Channel->DCDState)
{
Channel->DCDState = false;
dcdChanged = true;
if ((Channel->whichPort == serialPortA) && (Channel->gDCPModemFound))
{
if (Channel->DCPModemSupportPtr)
{
if (Channel->gDCPUserClientSet)
{
Channel->DCPModemSupportPtr->callDCPModemSupportFunctions (DCPFunction_SetDCD, (UInt8) kOff, NULL, NULL);
}
}
}
}
if (dcdChanged) {
OSIncrementAtomic(&scc->fCarrierHackCount);
if ( thread_call_enter1(scc->fPollingThread, (thread_call_param_t) Channel->DCDState) )
OSDecrementAtomic(&scc->fCarrierHackCount);
if (Channel->DCDState)
AppleSCCSerial::changeState(Channel, PD_RS232_S_CAR, PD_RS232_S_CAR);
else
AppleSCCSerial::changeState(Channel, 0, PD_RS232_S_CAR);
}
if (ExtCondition & kSyncHunt)
DLOG("Ext-> kSyncHunt\n");
bool currentCTSState = ((ExtCondition & kCTSAsserted) == kCTSAsserted);
if (Channel->lastCTSState != currentCTSState)
{
Channel->lastCTSState = currentCTSState;
if (Channel->ctsTransitionCount > 76) {
SccSetCTSFlowControlEnable(Channel, false);
}
AbsoluteTime currentTime;
UInt64 uint64_currentTime;
UInt32 uint32_currentTime;
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) {
DLOG("Ext-> kCTSAsserted\n");
HW_FlowControl = Channel->FlowControl & PD_RS232_S_CTS;
if (HW_FlowControl && (Channel->FlowControlState != PAUSE_SEND))
{
SerialDBDMAStatusInfo *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))
{
SerialDBDMAStatusInfo *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_enter_delayed(scc->fdmaStartTransmissionThread, deadline);
}
}
}
if (ExtCondition & kTXUnderRun) {
AppleSCCSerial::changeState(Channel, 0, PD_S_TX_BUSY);
DLOG("Ext-> kTXUnderRun\n");
}
if (ExtCondition & kBreakReceived)
DLOG("Ext-> kBreakReceived\n");
SccWriteReg(Channel, R0, kResetExtStsInt );
return noErr;
}
bool SetUpTransmit(SccChannel *Channel)
{
DLOG("++> SetUpTransmit\n");
if (Channel->AreTransmitting == TRUE) {
DLOG("--> SetUpTransmit Already Set\n");
return FALSE;
}
if (GetQueueStatus(&(Channel->TX)) != queueEmpty) {
SccdbdmaStartTransmission(Channel);
DLOG("Write First block.\n\r");
}
return TRUE;
}
InterruptState SccDisableInterrupts(SccChannel *Channel, UInt32 WhichInts)
{
InterruptState previousState = 0;
UInt8 sccState;
switch ( WhichInts) {
case kTxInterrupts: sccState = Channel->lastWR[ 5 ];
previousState = (InterruptState)sccState;
SccWriteReg(Channel, R5, sccState & ~kTxEnable );
break;
case kRxInterrupts: sccState = Channel->lastWR[ 3 ];
previousState = (InterruptState)sccState;
SccWriteReg(Channel, R3, sccState & ~kRxEnable );
break;
case kSccInterrupts: sccState = Channel->lastWR[ 9 ];
previousState = (InterruptState)sccState;
SccWriteReg(Channel, R9, sccState & ~kMIE & ~kNV );
break;
default:
break;
}
return previousState;
}
void SccEnableInterrupts(SccChannel *Channel, UInt32 WhichInts, InterruptState previousState)
{
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 SccSetDTR( SccChannel *Channel, bool assertDTR )
{
if ( assertDTR )
SccWriteReg(Channel, R5, Channel->lastWR[ 5 ] | kDTR );
else
SccWriteReg(Channel, R5, Channel->lastWR[ 5 ] & ~kDTR );
}
void SccSetRTS( SccChannel *Channel, bool assertRTS )
{
if ( assertRTS )
SccWriteReg(Channel, R5, Channel->lastWR[ 5 ] | kRTS );
else
SccWriteReg(Channel, R5, Channel->lastWR[ 5 ] & ~kRTS );
}
bool SccGetDCD( SccChannel *Channel )
{
bool Value;
Value = (SccReadReg(Channel, R0 ) & kDCDAsserted);
if (Value) {
Channel->State |= PD_RS232_S_CAR;
}
else {
Channel->State &= ~PD_RS232_S_CAR;
}
return Value;
}
bool SccGetCTS( SccChannel *Channel )
{
bool Value;
Value = (SccReadReg(Channel, R0 ) & kCTSAsserted);
if (Value)
Channel->State |= PD_RS232_S_CTS;
else
Channel->State &= ~PD_RS232_S_CTS;
return Value;
}
#include <IOKit/IODeviceTreeSupport.h>
void SccSetDMARegisters(SccChannel *Channel, IOService *provider)
{
UInt32 firstDMAMap = 1;
IOMemoryMap *map;
Channel->TxDBDMAChannel.dmaChannelAddress = NULL;
Channel->TxDBDMAChannel.dmaBase = NULL;
Channel->RxDBDMAChannel.dmaChannelAddress = NULL;
Channel->RxDBDMAChannel.dmaBase = NULL;
for(firstDMAMap = 1;; firstDMAMap++) {
if ( !(map = provider->mapDeviceMemoryWithIndex(firstDMAMap)) )
return;
if (map->getLength() > 1)
break;
}
Channel->TxDBDMAChannel.dmaChannelAddress = (IODBDMAChannelRegisters*)map->getVirtualAddress();
Channel->TxDBDMAChannel.dmaBase = (IODBDMAChannelRegisters*)map->getVirtualAddress();
if ( !(map = provider->mapDeviceMemoryWithIndex( firstDMAMap + 1 )) ) 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;
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 = &Channel->RxDBDMAChannel;
IODBDMAReset(dmaInfo->dmaBase);
dmaInfo->lastPosition = 0;
IODBDMAReset(dmaInfo->dmaBase);
}
void SccFreeReceptionChannel(SccChannel *Channel)
{
if (Channel == NULL)
return;
IOLockLock (Channel->IODBDMARxLock);
SccdbdmaEndReception(Channel);
SerialDBDMAStatusInfo *dmaInfo = &Channel->RxDBDMAChannel;
if (dmaInfo->dmaChannelCommandAreaMDP != NULL)
{
dmaInfo->dmaChannelCommandAreaMDP->complete();
dmaInfo->dmaChannelCommandAreaMDP->release();
dmaInfo->dmaChannelCommandAreaMDP = NULL;
}
if (dmaInfo->dmaTransferBufferMDP != NULL)
{
dmaInfo->dmaTransferBufferMDP->complete();
dmaInfo->dmaTransferBufferMDP->release();
dmaInfo->dmaTransferBufferMDP = NULL;
}
dmaInfo->lastPosition = 0;
dmaInfo->dmaNumberOfDescriptors = 0;
dmaInfo->dmaChannelCommandArea = NULL;
IOLockUnlock(Channel->IODBDMARxLock);
}
void SccdbdmaDefineReceptionCommands(SccChannel *Channel)
{
SerialDBDMAStatusInfo *dmaInfo = &Channel->RxDBDMAChannel;
UInt32 iterator;
IOPhysicalAddress physaddr;
IOPhysicalAddress physaddr1;
IOByteCount temp;
if ((dmaInfo->dmaChannelCommandArea == NULL) ||
(dmaInfo->dmaTransferBuffer == NULL))
return;
if (dmaInfo->dmaTransferBufferMDP == NULL)
return;
for (iterator = 0; iterator < dmaInfo->dmaNumberOfDescriptors; iterator ++) {
if (iterator == 0) {
physaddr = dmaInfo->dmaTransferBufferMDP->getPhysicalSegment(0, &temp);
IOMakeDBDMADescriptor(&dmaInfo->dmaChannelCommandArea[iterator],
kdbdmaInputMore,
kdbdmaKeyStream0,
kdbdmaIntAlways,
kdbdmaBranchNever,
kdbdmaWaitNever,
1,
physaddr);
}
else if (iterator == (dmaInfo->dmaNumberOfDescriptors - 1)) {
physaddr = dmaInfo->dmaTransferBufferMDP->getPhysicalSegment(0, &temp);
physaddr1 = dmaInfo->dmaChannelCommandAreaMDP->getPhysicalSegment(sizeof(IODBDMADescriptor), &temp);
IOMakeDBDMADescriptorDep(&dmaInfo->dmaChannelCommandArea[iterator],
kdbdmaInputMore,
kdbdmaKeyStream0,
kdbdmaIntNever,
kdbdmaBranchAlways,
kdbdmaWaitNever,
1,
physaddr,
physaddr1);
}
else {
physaddr = dmaInfo->dmaTransferBufferMDP->getPhysicalSegment(iterator, &temp);
IOMakeDBDMADescriptor(&dmaInfo->dmaChannelCommandArea[iterator],
kdbdmaInputMore,
kdbdmaKeyStream0,
kdbdmaIntNever,
kdbdmaBranchNever,
kdbdmaWaitNever,
1,
physaddr);
}
}
}
void SccdbdmaStartReception(SccChannel *Channel)
{
IOByteCount temp;
SerialDBDMAStatusInfo *dmaInfo = &Channel->RxDBDMAChannel;
IODBDMAReset(dmaInfo->dmaBase);
IODBDMAReset(dmaInfo->dmaBase);
if ((dmaInfo->dmaChannelCommandArea == NULL) ||
(dmaInfo->dmaTransferBuffer == NULL))
return;
IODBDMADescriptor *baseCommands = (IODBDMADescriptor *)dmaInfo->dmaChannelCommandAreaMDP->getPhysicalSegment(0, &temp);
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 = &Channel->RxDBDMAChannel;
UInt32 result = IOGetCCResult(&dmaInfo->dmaChannelCommandArea[iterator]);
if (result != 0)
return true;
return false;
}
UInt32 CommandStatus(SccChannel *Channel, UInt32 commandNumber)
{
SerialDBDMAStatusInfo *dmaInfo = &Channel->RxDBDMAChannel;
return IOGetCCResult(&dmaInfo->dmaChannelCommandArea[commandNumber]);
}
void SccdbdmaRxHandleCurrentPosition(SccChannel *Channel)
{
void *owner;
AppleSCCSerial *scc;
if (OSCompareAndSwap(1,1,&gTimerCanceled))
return;
if (Channel == NULL)
return;
owner = Channel->fAppleSCCSerialInstance;
scc = (AppleSCCSerial *) owner;
IOLockLock (Channel->IODBDMARxLock);
SerialDBDMAStatusInfo *dmaInfo = &Channel->RxDBDMAChannel;
UInt32 kDataIsValid = (kdbdmaStatusRun | kdbdmaStatusActive);
if ((dmaInfo->dmaChannelCommandArea == NULL) ||
(dmaInfo->dmaTransferBuffer == NULL))
{
IOLockUnlock (Channel->IODBDMARxLock);
return;
}
SccHandleExtErrors(Channel);
#ifdef TRACE
KERNEL_DEBUG_CONSTANT((DRVDBG_CODE(DBG_DRVSERIAL, 4)) | DBG_FUNC_START, 0, 0, 0, 0, 0); #endif
bool gotData = SuckDataFromTheDBDMAChain(Channel);
if (gotData)
{
natural_t numberOfbytes;
natural_t bitInterval;
natural_t nsec;
AppleSCCSerial::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
AbsoluteTime deadline;
clock_interval_to_deadline(nsec, 1, &deadline);
thread_call_enter_delayed(scc->dmaRxHandleCurrentPositionThread, deadline);
#endif
}
else
{
#ifdef TRACE
KERNEL_DEBUG_CONSTANT((DRVDBG_CODE(DBG_DRVSERIAL, 5)) | DBG_FUNC_START, 0, 0, 0, 0, 0); #endif
IODBDMAPause(dmaInfo->dmaBase);
UInt8 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);
UInt32 commandStatus = CommandStatus(Channel, dmaInfo->lastPosition);
if ((commandStatus & kDataIsValid) == kDataIsValid) {
if (SuckDataFromTheDBDMAChain(Channel))
{
AppleSCCSerial::CheckQueues(Channel);
}
}
IOSetCCResult(&dmaInfo->dmaChannelCommandArea[dmaInfo->lastPosition],0);
eieio();
SccdbdmaStartReception(Channel);
IOLockUnlock (Channel->IODBDMARxLock);
}
#ifdef TRACE
KERNEL_DEBUG_CONSTANT((DRVDBG_CODE(DBG_DRVSERIAL, 4)) | DBG_FUNC_END, 0, 0, 0, 0, 0); #endif
}
bool SuckDataFromTheDBDMAChain(SccChannel *Channel)
{ UInt32 SW_FlowControl = Channel->FlowControl & PD_RS232_S_RXO;
SerialDBDMAStatusInfo *TxdmaInfo = &Channel->TxDBDMAChannel;
SerialDBDMAStatusInfo *dmaInfo = &Channel->RxDBDMAChannel;
UInt32 iterator = dmaInfo->lastPosition;
bool gotData = false;
bool checkByte = true;
iterator = dmaInfo->lastPosition;
UInt32 kDataIsValid = (kdbdmaStatusRun | kdbdmaStatusActive);
while ((CommandStatus(Channel, iterator) & kDataIsValid) == kDataIsValid)
{
UInt8 byteRead;
IOSetCCResult(&dmaInfo->dmaChannelCommandArea[iterator],0);
eieio();
if (iterator == (dmaInfo->dmaNumberOfDescriptors - 1)) {
byteRead = dmaInfo->dmaTransferBuffer[0];
iterator = 1;
}
else {
byteRead = dmaInfo->dmaTransferBuffer[iterator];
iterator++;
}
if ((Channel->whichPort == serialPortA) && (Channel->gDCPModemFound) && (Channel->gDCPUserClientSet))
{
bool addByte = false;
bool result;
if (!(Channel->DCDState))
{
result = Channel->DCPModemSupportPtr->callDCPModemSupportFunctions (DCPFunction_ParseData, byteRead, &checkByte, &addByte);
if (!result)
{
Channel->gDCPUserClientSet = false;
checkByte = true;
}
else
{
if (addByte)
{
AddBytetoQueue(&(Channel->RX), 0x7E);
}
}
}
}
#ifdef TRACE
KERNEL_DEBUG_CONSTANT((DRVDBG_CODE(DBG_DRVSERIAL, 4)) | DBG_FUNC_NONE, byteRead, byteRead, 0, 0, 0); #endif
if (checkByte)
{
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 {
int excess = 0;
AddBytetoQueue(&(Channel->RX), byteRead);
excess = UsedSpaceinQueue(&(Channel->RX)) - Channel->RXStats.HighWater;
if (!Channel->aboveRxHighWater)
{
if (excess > 0)
{
Channel->aboveRxHighWater = true;
AppleSCCSerial::CheckQueues(Channel);
}
}
else if (excess <= 0)
{
Channel->aboveRxHighWater = false;
}
}
}
gotData = true;
}
dmaInfo->lastPosition = iterator;
return gotData;
}
void SccdbdmaEndReception(SccChannel *Channel)
{
SerialDBDMAStatusInfo *dmaInfo = &Channel->RxDBDMAChannel;
UInt32 cmdResult = 0;
IODBDMAStop(dmaInfo->dmaBase);
IODBDMAReset(dmaInfo->dmaBase);
if (dmaInfo != NULL) {
cmdResult = IOGetDBDMADescriptor(&dmaInfo->dmaChannelCommandArea[0], result);
dmaInfo->dmaTransferSize = dmaInfo->dmaTransferSize - (cmdResult & 0xFFFF);
DLOG("SccdbdmaEndTansmission: dma sent %u bytes\n", (unsigned) dmaInfo->dmaTransferSize);
}
}
void SccSetupTansmissionChannel(SccChannel *Channel)
{
SerialDBDMAStatusInfo *dmaInfo = &Channel->TxDBDMAChannel;
IODBDMAReset(dmaInfo->dmaBase);
dmaInfo->lastPosition = 0;
IODBDMAReset(dmaInfo->dmaBase);
}
void SccFreeTansmissionChannel(SccChannel *Channel)
{
if (Channel == NULL)
return;
IOLockLock (Channel->IODBDMATrLock);
SccdbdmaEndTransmission(Channel);
SerialDBDMAStatusInfo *dmaInfo = &Channel->TxDBDMAChannel;
if (dmaInfo->dmaChannelCommandAreaMDP != NULL)
{
dmaInfo->dmaChannelCommandAreaMDP->complete();
dmaInfo->dmaChannelCommandAreaMDP->release();
dmaInfo->dmaChannelCommandAreaMDP = NULL;
}
if (dmaInfo->dmaTransferBufferMDP != NULL)
{
dmaInfo->dmaTransferBufferMDP->complete();
dmaInfo->dmaTransferBufferMDP->release();
dmaInfo->dmaTransferBufferMDP = NULL;
}
dmaInfo->dmaNumberOfDescriptors = 0;
dmaInfo->dmaChannelCommandArea = NULL;
IOLockUnlock (Channel->IODBDMATrLock);
}
void SccdbdmaDefineTansmissionCommands(SccChannel *Channel)
{
IOPhysicalAddress physaddr;
IOByteCount temp;
SerialDBDMAStatusInfo *dmaInfo = &Channel->TxDBDMAChannel;
physaddr = dmaInfo->dmaTransferBufferMDP->getPhysicalSegment(0, &temp);
IOMakeDBDMADescriptor(&dmaInfo->dmaChannelCommandArea[0],
kdbdmaOutputLast,
kdbdmaKeyStream0,
kdbdmaIntAlways,
kdbdmaBranchNever,
kdbdmaWaitNever,
0,
physaddr);
IOMakeDBDMADescriptor(&dmaInfo->dmaChannelCommandArea[1],
kdbdmaStop,
kdbdmaKeyStream0,
kdbdmaIntNever,
kdbdmaBranchNever,
kdbdmaWaitNever,
0, 0
);
}
void SccdbdmaStartTransmission(SccChannel *Channel)
{
IOByteCount temp;
if (Channel == NULL)
return;
IOLockLock (Channel->IODBDMATrLock);
SerialDBDMAStatusInfo *dmaInfo = &Channel->TxDBDMAChannel;
SccHandleExtErrors(Channel);
Channel->AreTransmitting = TRUE;
AppleSCCSerial::changeState(Channel, PD_S_TX_BUSY, PD_S_TX_BUSY);
if ((dmaInfo->dmaChannelCommandArea != NULL) &&
(dmaInfo->dmaTransferBuffer != NULL)) {
IODBDMAReset(dmaInfo->dmaBase);
IODBDMADescriptor *baseCommands = (IODBDMADescriptor *)dmaInfo->dmaChannelCommandAreaMDP->getPhysicalSegment(0, &temp);
UInt8 *localBuffer = dmaInfo->dmaTransferBuffer;
UInt32 sizeReadFromBuffer = 0;
u_char* bufferPtr = 0;
UInt32 bytesToTransfer = UsedSpaceinQueue(&(Channel->TX));
if (bytesToTransfer)
{
Boolean wrapped = false;
sizeReadFromBuffer = bytesToTransfer;
bufferPtr = BeginDirectReadFromQueue(&(Channel->TX), &sizeReadFromBuffer, &wrapped);
if (bufferPtr && sizeReadFromBuffer)
{
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);
AppleSCCSerial::CheckQueues(Channel);
IOLockUnlock(Channel->IODBDMATrLock);
return;
}
else
{
EndDirectReadFromQueue(&(Channel->TX), 0);
}
}
AppleSCCSerial::CheckQueues(Channel);
Channel->AreTransmitting = FALSE;
AppleSCCSerial::changeState(Channel, 0, PD_S_TX_BUSY);
IOLockUnlock(Channel->IODBDMATrLock);
}
void SccdbdmaEndTransmission(SccChannel *Channel)
{
SerialDBDMAStatusInfo *dmaInfo = &Channel->TxDBDMAChannel;
UInt32 cmdResult = 0;
IODBDMAStop(dmaInfo->dmaBase);
IODBDMAReset(dmaInfo->dmaBase);
SccDisableInterrupts( Channel, kTxInterrupts);
if (dmaInfo != NULL) {
cmdResult = IOGetDBDMADescriptor(&dmaInfo->dmaChannelCommandArea[0], result);
dmaInfo->dmaTransferSize = dmaInfo->dmaTransferSize - (cmdResult & 0xFFFF);
DLOG("SccdbdmaEndTansmission: dma sent %u bytes\n", (unsigned) dmaInfo->dmaTransferSize);
}
}
void HandleRxIntTimeout(SccChannel *Channel)
{
}
void rxTimeoutHandler(OSObject *owner, IOTimerEventSource *sender)
{
AppleSCCSerial* serialPortPtr;
if (OSCompareAndSwap(1,1,&gTimerCanceled))
return;
serialPortPtr = OSDynamicCast( AppleSCCSerial, owner );
if( serialPortPtr ) {
SccdbdmaRxHandleCurrentPosition(serialPortPtr->portPtr());
}
}
#if USE_WORK_LOOPS
void rearmRxTimer(SccChannel *Channel, UInt32 timerDelay)
{
if (OSCompareAndSwap(1,1,&gTimerCanceled))
return;
Channel->rxTimer->setTimeout( timerDelay );
}
#endif