#include <string.h>
#include "cc1defs.h"
#include "intregs.h"
#include "intvecs.h"
#include "smdmport.h"
#include "charq_p.h"
#define THRE_BIT_POS 5
#define THRE_BIT_MASK (1 << THRE_BIT_POS)
#define TSRE_BIT_POS 6
#define TSRE_BIT_MASK (1 << TSRE_BIT_POS)
#define RXD_BIT_POS 0
#define RXD_BIT_MASK (1 << RXD_BIT_POS)
#define CR 13
#define ena_Rx 0x01
#define ena_Tx 0x02
#define ena_RxERR 0x04
#define ena_MDM_STS 0x08
#define mdm_ena_mask (ena_Rx + ena_Tx)
#define DCD_State_Bit 0x80
#define CTS_State_Bit 0x10
#define Delta_DCD_Bit 0x08
#define Delta_CTS_Bit 0x01
#define Ring_State_Bit 0x40
#define Trailing_Ring_Bit 0x04
#ifdef __cplusplus
#define __CPPARGS ...
#else
#define __CPPARGS
#endif
#pragma option -r-
static UINT mdm_prn_count;
static BOOL DCD_flag, RI_flag, MDM_XOFFED, rx_has_CR, rq_new_RI;
static UINT modem_alive, last_MSR, new_MSR;
BOOL get_mdm_CTS(void)
{
if (last_MSR & CTS_State_Bit)
return TRUE;
else
return FALSE;
}
static q_control *mdm_tx_q, *mdm_rx_q;
void set_mdm_tx_q(q_control *q)
{
if (q)
mdm_tx_q = q;
}
void set_mdm_rx_q(q_control *q)
{
if (q)
mdm_rx_q = q;
}
void interrupt MdmHandler (__CPPARGS)
{ char c;
goto first_test;
mdm_txd_0:
if (MDM_XOFFED)
goto Check_MSR_1;
mdm_txd_1:
if (mdm_tx_q->count) {
_AL = charq_getc(mdm_tx_q);
asm out ModemBase,al
}
goto Check_MSR_1;
mdm_rxd_1:
asm in ax,ModemBase // ; get char from UART
c = _AL;
if (_AL == CR)
rx_has_CR = TRUE;
charq_putc(mdm_rx_q, c);
goto Check_MSR_1;
first_test:
// first, check to see if modem is alive
if (modem_alive)
goto GotAModem;
// else if not alive, don't respond to modem ints any more
asm {
mov dx, Int0CtlReg
in ax, dx
or ax, Masked // mask the cpu's INT line from the modem
out dx, ax
}
goto FalseInt;
GotAModem: // Identify the type of interrupt
asm {
in ax, ModemBase+IIRofs
test al,1
jz TryMSR
jmp FalseInt
}
TryMSR:
asm {
cmp al,0
jne TryTx
jmp Check_MSR_1 // interrupted by a modem status change
}
TryTx:
asm {
cmp al,2
jne TryRx
jmp mdm_txd_0 // interrupted by THRE
}
TryRx:
asm {
cmp al,4
jne TryRxERR
jmp mdm_rxd_1 // interrupted by rcvd data
}
TryRxERR:
asm {
test al,6
jnz Check_MSR_1
// we have a rcv error - just clear it
in ax,ModemBase+LSRofs
}
Check_MSR_1:
asm in ax,ModemBase+MSRofs
_AH = 0;
new_MSR = _AX;
asm test al,Delta_CTS_Bit
asm jz Check_RI_rq
asm test al,CTS_State_Bit
asm jz Check_RI_rq
MDM_XOFFED = FALSE; // CTS is true, so XOFF is FALSE
goto mdm_txd_1;
Check_RI_rq:
if (rq_new_RI) {
rq_new_RI = FALSE;
RI_flag = FALSE;
}
CheckCTS:
if ((new_MSR & CTS_State_Bit) == 0)
MDM_XOFFED = TRUE; //
CheckDCD:
if (new_MSR & DCD_State_Bit) {
DCD_flag = TRUE;
RI_flag = FALSE;
goto finup;
}
DCD_Dropped:
if (last_MSR & DCD_State_Bit) {
DCD_flag = FALSE;
RI_flag = FALSE;
goto finup;
}
RI_Check:
if (new_MSR)
RI_flag = TRUE;
finup:
last_MSR = new_MSR;
FalseInt:
asm {
mov dx,EOIReg
mov ax,Mdm212IntVec
out dx,ax
}
}
BOOL mdm_rxwaiting(void)
{
if (mdm_rx_q->count)
return TRUE;
else
return FALSE;
}
BOOL get_DCD_flag(void)
{
return DCD_flag;
}
BOOL get_RI_flag(void)
{
return RI_flag;
}
void flush_mdm_tx(void)
{
asm pushf
asm CLI
asm mov al, ena_Rx
asm out (ModemBase + IERofs),al // ; turn off TX
reset_charque(mdm_tx_q);
mdm_prn_count = 0;
MDM_XOFFED = FALSE;
asm popf
}
void flush_mdm_rx(void)
{
asm pushf
asm CLI
reset_charque(mdm_rx_q);
rx_has_CR = FALSE;
asm popf
}
BOOL THRE_empty(void)
{
asm {
pushf
CLI
in ax,ModemBase+LSRofs
popf
}
if (_AX & THRE_BIT_MASK)
return TRUE;
else
return FALSE;
}
void mdm_tx_restart(void)
{ char c;
if (MDM_XOFFED)
return;
if (mdm_tx_q->count) {
asm {
pushf
CLI
in ax, (ModemBase + LSRofs)
}
if (_AL & THRE_BIT_MASK) { // ready for another character
asm mov al, mdm_ena_mask // enable RX and TX
asm out (ModemBase + IERofs),al
c = charq_getc(mdm_tx_q);
_AL = c;
asm out ModemBase,al
}
asm popf
}
else { // empty queue -- shut off the tx interrupt
asm {
pushf
CLI
mov al,ena_Rx
out (ModemBase + IERofs),al
popf
}
}
}
UINT mdm_tx_waiting(void)
{
return mdm_tx_q->count;
}
UINT mdm_tx_free(void)
{
return (mdm_tx_q->size - mdm_tx_q->count);
}
BOOL mdm_txbuf_empty(void)
{
if (mdm_tx_q->count)
return FALSE;
else
return TRUE;
}
BOOL mdm_tx_empty(void)
{
asm {
pushf
CLI
in ax,ModemBase+LSRofs
popf
}
if ((_AL & 0x60) == 0x60)
return TRUE;
else
return FALSE;
}
UCHAR mdm_getbufc(void)
{
return charq_getc(mdm_rx_q);
}
void mdm_puts(UCHAR *message)
{ UINT slen;
if (message) {
slen = strlen(message);
if (slen) {
charq_puts(mdm_tx_q, message, slen);
}
}
}
void mdm_putch(UCHAR c)
{
charq_putc(mdm_tx_q, c);
}
UINT mdm_prn2go(void)
{
return mdm_prn_count;
}
void ena_mdm_ints(void)
{
asm {
pushf
CLI
mov dx,Int0CtlReg
in ax,dx
and ax,(NOT Masked) // unmask the SocketModem INT line
out dx,ax
popf
}
}
void mask_mdm_ints(void)
{
asm {
pushf
CLI
mov dx,Int0CtlReg
in ax,dx
or ax,Masked // mask the cpu's INT line from the modem
out dx,ax
popf
}
}
void mdm_reg_init(void)
{ UINT saved;
asm {
pushf
CLI
mov ax, 0x5555
out (ModemBase + SCRofs), al
}
saved = _AX;
asm {
in ax, ModemBase // read the rx register
mov al, 3 // 8 data, 1 stop, no parity
or al, 0x80 // set the DLAB
out (ModemBase + LCRofs), al
xchg bx, bx
// set the default baud rate divisor for 2400 bps
mov ax, 48 // for 1200 bps, use 96
out (ModemBase + BRG0ofs), al
xchg bx, bx
mov al,ah
out (ModemBase + BRG1ofs), al
xchg bx, bx
// turn off DLAB
mov al, 3 // 8 data, 1 stop, no parity
out (ModemBase + LCRofs), al
xchg bx, bx
// assert DTR, negate OUT2
mov al, 0x01
out (ModemBase + MCRofs), al
xchg bx, bx
// read IIR to clear any pending interrupts
in ax, (ModemBase + IIRofs)
xchg bx, bx
// clear out any line status register junk
in ax, (ModemBase + LSRofs)
xchg bx, bx
// clear out any modem status register junk
xor ax, ax
out (ModemBase + MSRofs), ax
xchg bx, bx
mov al, ena_Rx // enable rx interrupt only
out (ModemBase + IERofs), al
in ax, (ModemBase + SCRofs)
}
if (_AL == (UCHAR) saved)
modem_alive = saved;
Done:
asm popf
}
void ena_mdm_EIA(void)
{
asm pushf
asm CLI
rq_new_RI = TRUE;
// enable rx, tx, and mdm status
asm mov al,(mdm_ena_mask OR ena_MDM_STS)
asm out (ModemBase + IERofs), al
asm nop
asm nop
asm popf
}
void mask_mdm_EIA(void)
{
asm pushf
asm CLI
asm mov al, mdm_ena_mask // enable rx, tx, interrupts
asm out (ModemBase + IERofs), al
asm nop
asm nop
asm popf
}
void mdm_cominit(void)
{
asm pushf
asm CLI
mask_mdm_ints();
modem_alive = FALSE; // init as 'NO MODEM'
DCD_flag = FALSE;
RI_flag = FALSE;
reset_charque(mdm_rx_q);
reset_charque(mdm_tx_q);
MDM_XOFFED = FALSE;
setvect(Mdm212IntVec, MdmHandler);
mdm_reg_init();
asm popf
}
void clear_mdm_flags(void)
{
asm pushf
asm CLI
DCD_flag = FALSE;
RI_flag = FALSE;
rq_new_RI = FALSE;
new_MSR = FALSE;
rx_has_CR = FALSE;
last_MSR = DCD_State_Bit;
asm popf
}
UINT get_IER(void)
{
asm {
pushf
CLI
in ax,ModemBase+IERofs
popf
}
_AH = 0;
return _AX;
}
void write_mdm_port(UINT port_addr, UINT value)
{
asm {
push ax
push dx
mov dx,port_addr
mov ax,value
pushf
CLI
out dx,al
popf
pop dx
pop ax
}
}
void reset_CR_flag(void)
{
rx_has_CR = FALSE;
}
BOOL rx212_has_CR(void)
{
return rx_has_CR;
}
void reset_RI_flag(void)
{
rq_new_RI = TRUE;
}