?? rs232.c
字號:
int thr;
int rbr;
int iir;
int fcr;
int ier;
int mcr;
int lsr;
int lcr;
int msr;
int uart;
int pic;
unsigned ibuf_siz;
unsigned obuf_siz;
char xon;
char xoff;
char hdw_flw;
unsigned char *in_buf;
unsigned char *out_buf;
unsigned char oldmask;
}rs_ss;
volatile struct rs_dynamics{ /* dynamic variables */
unsigned in_head;
unsigned in_tail;
unsigned out_head;
unsigned out_tail;
unsigned rcv_cnt;
unsigned char ier_msk;
unsigned char msr_cod;
unsigned char err_cod;
}rs_ds;
int rs_portopen = 0;
struct rs_userport rs_user = {0,'\0'};
void interrupt (*rs_oldvec)(void) = NULL;
/* Interrupt service routine - Get received character from port rs_ss.rbr,
store in rs_ss.in_buf and increment rs_inrcv. If flow control enabled,
update global variable rs_ss.iermsk to enable or disable output as
required */
void interrupt rs_inthndlr(void)
{
extern struct rs_statics rs_ss;
extern volatile struct rs_dynamics rs_ds;
extern void interrupt (*rs_oldvec)(void);
int rs_xmitcnt;
#ifndef RS_POLLED_XMIT
if(rs_ss.uart)
outportb(rs_ss.ier,rs_ds.ier_msk); /* nudge xmit intrpt if not 8250B */
#endif
_AL = (inportb(rs_ss.iir) & '\x07'); /* get interrupt id */
if(!(_AL & '\x01')){ /* interrupt pending ? */
do{
if(_AL == '\x06'){ /* receive error ? */
rs_ds.err_cod = inportb(rs_ss.lsr); /* record error */
}
else if((_AL & '\x04')){ /* data received interrupt ? */
do{
_AL = inportb(rs_ss.rbr); /* get the byte */
_CL = _AL;
if(rs_ss.flow == 2){
if(_CL == rs_ss.xon){
#ifndef RS_POLLED_XMIT
outportb(rs_ss.ier,'\x0F');
#endif
rs_ds.ier_msk = '\x0F';
}
else if(_CL == rs_ss.xoff){
#ifndef RS_POLLED_XMIT
outportb(rs_ss.ier,'\x0D');
#endif
rs_ds.ier_msk = '\x0D';
}
else
goto rs_J1;
}
else{
/* store incoming byte */
rs_J1:
*(rs_ss.in_buf + rs_ds.in_head++) = _CL;
/* in case head ptr wrapped around */
rs_ds.in_head &= rs_ss.ibuf_siz;
rs_ds.rcv_cnt++; /* track rcv buffer overflow */
}
}while(inportb(rs_ss.lsr) & '\x01'); /* loop while data avail. */
}
#ifndef RS_POLLED_XMIT
else if(_AL & '\x02'){ /* transmit holding reg. empty ? */
for(rs_xmitcnt = 0;rs_xmitcnt < rs_ss.xmitfifo;rs_xmitcnt++){
/* send a byte if any to send */
if(rs_ds.out_tail != rs_ds.out_head){
outportb(rs_ss.thr,*(rs_ss.out_buf + rs_ds.out_tail++));
/* in case tail pointer wrapped around */
rs_ds.out_tail &= rs_ss.obuf_siz;
}
else
break;
}
}
#endif
else{ /* change in one of the modem control lines */
rs_ds.msr_cod = inportb(rs_ss.msr); /* record modem status */
if(rs_ss.flow == 1){
if(rs_ds.msr_cod & rs_ss.hdw_flw)
rs_ds.ier_msk = '\x0F'; /* enable xmit interrupts */
else
rs_ds.ier_msk = '\x0D'; /* disable xmit interrupts */
#ifndef RS_POLLED_XMIT
outportb(rs_ss.ier,rs_ds.ier_msk);
#endif
}
}
}while(!((_AL = inportb(rs_ss.iir)) & '\x01')); /* loop if int. pending */
}
else
rs_oldvec(); /* no interrupt pending on entry - call old isr */
enable(); /* enable interrupts */
outportb(rs_ss.pic,'\x20'); /* non-specific EOI to 8259 */
if(rs_ss.pic == 0xA0)
outportb(0x20,'\x20');
}
/* rs_initport: Initialize port, interrupt vector and interrupt mask (see
description with function prototype for details on arguments). */
int rs_initport(char rs_port,long rs_baud,char rs_parity,char rs_bits,
char rs_stop,unsigned rs_userinbufsiz, char *rs_userinbuf,
unsigned rs_useroutbufsiz,char *rs_useroutbuf)
{
extern struct rs_statics rs_ss;
extern volatile struct rs_dynamics rs_ds;
extern int rs_portopen;
extern void interrupt (*rs_oldvec)(void);
int rs_init[] = {0x6328,0x2029,0x2E43,0x4B20,0x7261,0x6863,0x7265,
0x3120,0x3939,0x2033,0x3439};
int rs_dll,rs_dlm,rs_portbase,rs_ret;
int far *rs_bda;
unsigned char rs_dvsrl,rs_dvsrh,rs_mask,rs_irq,rs_tmp1,rs_tmp2,rs_tmp3;
if(rs_portopen) /* if there's already a port open, close it */
rs_close();
rs_ss.oldmask = '\0';
/* make sure buffer size is valid */
if((rs_userinbufsiz - 1) & rs_userinbufsiz)
return -1;
rs_ss.ibuf_siz = rs_userinbufsiz - 1;
if((rs_ss.in_buf = (unsigned char *)rs_userinbuf) == NULL)
return -1;
#ifndef RS_POLLED_XMIT
if((rs_useroutbufsiz - 1) & rs_useroutbufsiz)
return -2;
rs_ss.obuf_siz = rs_useroutbufsiz - 1;
if((rs_ss.out_buf = (unsigned char *)rs_useroutbuf) == NULL)
return -2;
#endif
/* initialize buffer head and tail pointers */
rs_ds.in_head = rs_ds.in_tail = rs_ds.out_head = rs_ds.out_tail = 0;
if(rs_init[1])
rs_bda = (int far*)MK_FP(0x40,0); /* get far pointer to BIOS data area */
switch(rs_port){ /* find i/o port address and irq */
case '1':
rs_portbase = *rs_bda;
if(rs_portbase == 0)
rs_portbase = 0x3F8;
rs_irq = 4;
break;
case '2':
rs_portbase = *(rs_bda + 1);
if(rs_portbase == 0)
rs_portbase = 0x2F8;
rs_irq = 3;
break;
case '3':
rs_portbase = *(rs_bda + 2);
if(rs_portbase == 0)
rs_portbase = 0x3E8;
if(rs_portbase == 0x3220) /* if it's a PS/2 */
rs_irq = 3;
else
rs_irq = 4;
break;
case '4':
rs_portbase = *(rs_bda + 3);
if(rs_portbase == 0)
rs_portbase = 0x2E8;
if(rs_portbase == 0x3228) /* if it's a PS/2 */
rs_irq = 4;
else
rs_irq = 3;
break;
case '0': /* user defined IRQ and base address defined by struct rs_user */
if(! rs_user.base) /* make sure it's been init'd */
return -3;
rs_portbase = rs_user.base;
rs_irq = rs_user.irq;
break;
default:
return -3;
}
if(rs_irq <= 7){ /* find interrupt number and PIC address */
rs_ss.int_no = rs_irq + 8;
rs_ss.pic = 0x20;
}
else if(rs_irq <= 15){
rs_irq -= 8;
rs_ss.int_no = rs_irq + 0x70;
rs_ss.pic = 0xA0;
}
else
return -3;
rs_mask = ('\x01' << rs_irq) ^ '\xFF';
switch(rs_parity){
case 'N':
rs_parity = 0;
break;
case 'E':
rs_parity = '\x18';
break;
case 'O':
rs_parity = '\x08';
break;
case 'S':
rs_parity = '\x38';
break;
case 'M':
rs_parity = '\x28';
break;
default:
return -4;
}
if(rs_bits == '7')
rs_bits = 2;
else if(rs_bits == '8')
rs_bits = 3;
else
return -5;
if(rs_stop == '1')
rs_stop = 0;
else if(rs_stop == '2')
rs_stop = 4;
else
return -6;
/* 8250 (or 16x50) registers: */
/* out, bit 7 of LCR = 0, (Transmit Holding Register) */
rs_ss.thr = rs_portbase + 0;
/* in, bit 7 of LCR = 0, (Receive Buffer Register) */
rs_ss.rbr = rs_portbase + 0;
/* out, bit 7 of LCR = 1, (Divisor Latch LSB) */
rs_dll = rs_portbase + 0;
/* out, bit 7 of LCR = 1, (Divisor Latch MSB) */
rs_dlm = rs_portbase + 1;
/* out, bit 7 of LCR = 0, (Interrupt Enable Register)
bit 0 = 1 data rcvd
bit 1 = 1 transmit holding reg. empty
bit 2 = 1 data reception error
bit 3 = 1 change in modem status
bit 4-7 unused */
rs_ss.ier = rs_portbase + 1;
/* in, (Interrupt ID register)
bit 0 : 0 = interrupt pending
bits 2-1: 00 = modem status change - read status
01 = transmit ready - output character or
read iir to clear
10 = data rcvd - read data
11 = break or error
bits 7-6: 11 = 16550 in FIFO mode */
rs_ss.iir = rs_portbase + 2;
/* out, (FIFO control register - 16550)
bit 0: 1 = FIFO enable
bit 1: 1 = RCVR FIFO reset
bit 2: 1 = XMIT FIFO reset
bit 6 & 7: RCVR trigger level
(00 = 1, 01 = 4, 10 = 8, 11 = 14) */
rs_ss.fcr = rs_portbase + 2;
/* out, (Line Control Register)
bits 0-1: Character Length
00 = 5 bits
01 = 6 bits
10 = 7 bits
11 = 8 bits
bit 2: Number of stop bits
0 = 1 (1.5 if character length 5)
1 = 2
bit 3: Parity
0 = no parity
1 = parity generated
bit 4: Parity type
0 = odd
1 = even
bit 5: Stick Parity
0 = disabled
1 = always 1 if bit 3 = 1 & bit 4 = 0 or
always 0 if bit 3 = 1 & bit 4 = 1 or
no parity if bit 3 = 0
bit 6: Set Break
0 = disabled
1 = output string of 0s
bit 7: Enable write to baud divisor regs. if 1 */
rs_ss.lcr = rs_portbase + 3;
/* out, (Modem Control Register)
bit 0: 1 = data terminal ready
bit 1: 1 = request to send
bit 2: 1 = aux. output 1
bit 3: 1 = aux. output 2 - enables hdwr intrrpts.
bit 4: 1 = UART loopback mode
bit 5-7: always 0 */
rs_ss.mcr = rs_portbase + 4;
/* in, (Line Status Register)
bit 0: 1 = character received
bit 1: 1 = rcvd data overrun
bit 2: 1 = parity error
bit 3: 1 = framing error
bit 4: 1 = break detected
bit 5: 1 = transmit holding reg. empty
bit 6: 1 = transmitter empty
bit 7: 1 = rcvr FIFO error (16550) */
rs_ss.lsr = rs_portbase + 5;
/* in, (Modem Status Register)
bit 0: 1 = delta clear to send
bit 1: 1 = delta data set ready
bit 2: 1 = delta ring indicator
bit 3: 1 = delta data carrier detect
bit 4: 1 = clear to send
bit 5: 1 = data set ready
bit 6: 1 = ring indicator
bit 7: 1 = data carrier detect */
rs_ss.msr = rs_portbase + 6;
/* check for existence of UART */
outportb(rs_ss.fcr,'\0'); /* if 16550, make it a 16450 */
rs_tmp1 = inportb(rs_ss.mcr); /* save mcr */
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -