#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; }