COMM - NAVYTIME.ZIP - COMM.C

 
Output of file : COMM.C contained in archive : NAVYTIME.ZIP

/* comm -- communications port i/o */
/* copyright 1987 Michael M Rubenstein */

#pragma inline
#include
#include
#include "atfinish.h"
#include "comm.h"

#define NUMUNIT 2 /* number of comm units */

#define COMM_BUFSIZE 256 /* must be power of 2 <= 2^7 */

#define DATA0 0x3f8 /* COM1 port address */
#define DATA1 0x2f8 /* COM2 port address */
#define INTMASK0 0xef /* mask for COM1 interrupt */
#define INTMASK1 0xf7 /* mask for COM2 interrupt */
#define INTERRUPT_VEC0 0x0c /* interrupt vector for COM1 */
#define INTERRUPT_VEC1 0x0b /* interrupt vector for COM2 */

#define DATA comm_base[unit]
#define ENABLE_INT (comm_base[unit] + 1)
#define DIVISOR0 (comm_base[unit] + 0)
#define DIVISOR1 (comm_base[unit] + 1)
#define INTERRUPT_ID (comm_base[unit] + 2)
#define LINE_CTL (comm_base[unit] + 3)
#define MODEM_CTL (comm_base[unit] + 4)
#define LINE_STATUS (comm_base[unit] + 5)
#define MODEM_STATUS (comm_base[unit] + 6)

#define INTERRUPT_CTL 0x20
#define INTERRUPT_MASK 0x21

static unsigned comm_base[NUMUNIT] = { DATA0, DATA1 };
static unsigned char interrupt_mask[NUMUNIT] = { INTMASK0, INTMASK1 };
static unsigned interrupt_vector[NUMUNIT] = { INTERRUPT_VEC0,
INTERRUPT_VEC1
};

static void interrupt (*holdvec[NUMUNIT])();
static unsigned char hold_interrupt_enable[NUMUNIT];
static unsigned char hold_interrupt_mask[NUMUNIT];

static unsigned char buffer0[COMM_BUFSIZE];
static unsigned char buffer1[COMM_BUFSIZE];
static unsigned char *buffer[NUMUNIT] = { buffer0, buffer1 };

static int first[NUMUNIT] = { 0, 0 },
next[NUMUNIT] = { 0, 0 };

static int any_opened = FALSE;
static int opened[NUMUNIT] = { FALSE, FALSE };

void comm_int0(void);
void comm_int1(void);

/* open comm port. */
int comm_open(unsigned unit, unsigned baud, int parity, int stop,
int wordsize)
{
unsigned divisor;
struct { char p_char;
unsigned int p_bits;
} parity_bits[] = { { 'n', 0x00 },
{ 'o', 0x04 },
{ 'e', 0x0c },
{ 0, 0 }
},
*pb;
unsigned lctl;


if (unit >= NUMUNIT)
return FALSE;

lctl = 0;
for (pb = parity_bits; pb->p_char != 0; ++ pb)
if (pb->p_char == parity)
{
lctl = pb->p_bits;
break;
}
lctl |= (wordsize - 5);
lctl |= (stop - 1) << 2;


holdvec[unit] = getvect(interrupt_vector[unit]);
setvect(interrupt_vector[unit],
(unit == 0) ? (void interrupt (*)()) comm_int0
: (void interrupt (*)()) comm_int1);

hold_interrupt_enable[unit] = inportb(ENABLE_INT);

outportb(ENABLE_INT, 0x01); /* set data ready int */
hold_interrupt_mask[unit] = inportb(INTERRUPT_MASK);
outportb(INTERRUPT_MASK, hold_interrupt_mask[unit] & interrupt_mask[unit]);

outportb(LINE_CTL, 0x80); /* access divisor latch */

divisor = (int) (0x1c200l / (long) baud);
outportb(DIVISOR0, divisor); /* set baud divisor */
outportb(DIVISOR1, divisor >> 8);
outportb(LINE_CTL, lctl); /* 81n */
outportb(MODEM_CTL, 0x0b); /* DTR, RTS, interrupts */
outportb(INTERRUPT_CTL, 0x20); /* EOI to 8259 */

if (!any_opened)
atfinish(comm_close_all);

any_opened = opened[unit] = TRUE;

comm_clr(unit);
return TRUE;
}

/* close all comm ports */
void comm_close_all(void)
{
int i;

for (i = 0; i < NUMUNIT; ++i)
comm_close(i);
}

/* close a comm port -- drop modem control signals and stop interrupts */
void comm_close(unsigned unit)
{
if (unit < NUMUNIT && opened[unit])
{
outportb(MODEM_CTL, 0x00); /* no DTR, RTS, interrupts */
outportb(ENABLE_INT, hold_interrupt_enable[unit]);
outportb(INTERRUPT_MASK, hold_interrupt_mask[unit]);
setvect(interrupt_vector[unit], holdvec[unit]);
opened[unit] = FALSE;
}
}

/* interrupt handler for COM1 */
static void comm_int0(void)
{
asm push ds
asm push dx
asm push bx
asm push ax

asm mov dx,dgroup
asm mov ds,dx
asm mov dx,3f8h
asm in al,dx /* get character */
asm sub bx,bx
asm mov bx,next+0*2
asm mov byte ptr buffer0[bx],al /* mov char. into buffer */
asm inc bx /* advance buffer pointer */
asm and bx,COMM_BUFSIZE-1
asm cmp bx,first+0*2
asm je finish /* don't update ptr if no room */
asm mov next+0*2,bx

finish:
asm mov al,20h /* send EOI to 8259 */
asm out 20h,al

asm pop ax
asm pop bx
asm pop dx
asm pop ds
asm iret
}

/* interrupt handler for COM2 */
static void comm_int1(void)
{
asm push ds
asm push dx
asm push bx
asm push ax

asm mov dx,dgroup
asm mov ds,dx
asm mov dx,2f8h
asm in al,dx /* get character */
asm sub bx,bx
asm mov bx,next+1*2
asm mov byte ptr buffer1[bx],al /* mov char. into buffer */
asm inc bx /* advance buffer pointer */
asm and bx,COMM_BUFSIZE-1
asm cmp bx,first+1*2
asm je finish /* don't update ptr if no room */
asm mov next+1*2,bx
finish:
asm mov al,20h /* send EOI to 8259 */
asm out 20h,al

asm pop ax
asm pop bx
asm pop dx
asm pop ds
asm iret
}

/* get character from comm */
int comm_getc(unsigned unit)
{
int c;

if (unit >= NUMUNIT)
return -1;

if (first[unit] == next[unit])
return -1;

c = buffer[unit][first[unit]];
first[unit] = (first[unit] == COMM_BUFSIZE - 1) ? 0 : first[unit] + 1;
return c;
}

/* clear input buffer */
void comm_clr(unsigned unit)
{
if (unit < NUMUNIT)
{
disable();
first[unit] = next[unit];
inportb(DATA); /* also clear anything in the chip */
inportb(DATA);
enable();
}
}

/* put character to comm */
int comm_putc(unsigned unit, int c)
{
if (unit > NUMUNIT)
return FALSE;

if (inportb(LINE_STATUS) & 0x20)
{
outportb(DATA, c);
return TRUE;
}
return FALSE;
}