?? rs232.c
字號:
rs_tmp2 = inportb(rs_ss.ier); /* save ier */
outportb(rs_ss.ier,'\0'); /* disable interrupts at UART */
inportb(rs_ss.rbr); /* read rcv buffer register */
inportb(rs_ss.lsr); /* read lsr */
inportb(rs_ss.msr); /* read msr */
inportb(rs_ss.iir); /* read iir */
if(inportb(rs_ss.iir) != '\x01') /* read it again, should indicate... */
return 0; /* ...no interrupt pending */
outportb(rs_ss.lcr,'\0'); /* make sure out2 is 0 */
outportb(rs_ss.ier,'\x02'); /* enable thre interrupt indication */
outportb(rs_ss.ier,'\x02'); /* do it again for 8250 */
goto rs_J1; /* give UART some time */
rs_J1:
rs_tmp3 = inportb(rs_ss.iir); /* get iir */
outportb(rs_ss.ier,rs_tmp2); /* restore original values */
outportb(rs_ss.mcr,rs_tmp1);
if(rs_tmp3 != '\x02') /* should have seen thre interrupt... */
return 0; /* ...else port is unavailable */
/* find out what kind of UART it is */
rs_ss.xmitfifo = 1; /* initialize for no FIFO */
outportb(rs_portbase + 7,'\x55'); /* try writing scratch register */
if(inportb(rs_portbase + 7) != '\x55') /* and then reading it */
rs_ret = 1; /* if value written wasn't read it's an 8250B */
else{
/* check for presence of 16550, if 16550A,C,CF, enable FIFOs */
outportb(rs_ss.fcr,'\x41'); /* enable FIFO's with 4 byte RCVR trig. level */
rs_tmp1 = inportb(rs_ss.iir);
rs_tmp1 &= '\xC0';
if(rs_tmp1 == (unsigned char)'\xC0'){ /* 16550A,C,CF bits 6 & 7 are set */
rs_ret = 4;
rs_ss.xmitfifo = 16; /* #of bytes to write to XMIT FIFO per interrupt */
}
else{ /* otherwise, it's an 8250A, 16450 or 16550 */
outportb(rs_ss.fcr,'\x0');
if(rs_tmp1 == (unsigned char)'\x80') /* 16550 */
rs_ret = 3;
else /* 8250A or 16450 */
rs_ret = 2;
}
}
/* get the baud rate divisor values */
rs_dvsrh = 0;
switch(rs_baud){
case 110L:
rs_dvsrh = '\x04';
rs_dvsrl = '\x17';
break;
case 300L:
rs_dvsrh = '\x01';
rs_dvsrl = '\x80';
break;
case 600L:
rs_dvsrl = '\xC0';
break;
case 1200L:
rs_dvsrl = '\x60';
break;
case 2400L:
rs_dvsrl = '\x30';
break;
case 4800L:
rs_dvsrl = '\x18';
break;
case 9600L:
rs_dvsrl = '\x0C';
break;
case 19200L:
rs_dvsrl = '\x06';
break;
case 38400L:
rs_dvsrl = '\x03';
break;
case 57600L:
rs_dvsrl = '\x02';
break;
case 115200L:
rs_dvsrl = '\x01';
break;
default:
return -7;
}
rs_oldvec = getvect(rs_ss.int_no); /* get the old interrupt vector */
setvect(rs_ss.int_no,rs_inthndlr); /* plug in the new one */
outportb(rs_ss.ier,0); /* disable UART interrupts */
outportb(rs_ss.lcr,'\x80'); /* enable baud rate divisor registers */
outportb(rs_dll,rs_dvsrl); /* write divisor lo byte */
outportb(rs_dlm,rs_dvsrh); /* write divisor hi byte */
outportb(rs_ss.lcr,(rs_parity | rs_bits | rs_stop)); /* characteristics */
/* enable interrupts at UART, do not change modem control lines */
outportb(rs_ss.mcr,(inportb(rs_ss.mcr) | '\x08')); /* set out2 */
inportb(rs_ss.iir); /* clear out any data...*/
inportb(rs_ss.lsr); /*...left in...*/
inportb(rs_ss.rbr); /*...UART's status...*/
inportb(rs_ss.msr); /*...registers */
disable();
outportb(rs_ss.ier,'\x0D'); /* enable UART interrupts */
inportb(rs_ss.iir);
rs_ss.oldmask = inportb(rs_ss.pic + 1); /* save old interrupt mask */
rs_mask &= rs_ss.oldmask;
outportb(rs_ss.pic + 1,rs_mask); /* interrupt now enabled */
rs_ds.msr_cod = inportb(rs_ss.msr) & '\xF0'; /* initialize modem status */
enable();
rs_timer(0); /* zero out tick counter */
rs_ss.flow = 0; /* initialize flow control */
rs_ds.rcv_cnt = 0; /* initialize receive count */
rs_ds.err_cod = '\x00'; /* initialize error flags */
rs_ds.ier_msk = '\x0F'; /* insure that xmit interrupts stay enabled */
rs_portopen = 1; /* set port open flag */
rs_ss.uart = rs_ret - 1; /* set UART type */
return rs_ret;
}
/* rs_close: Restore original 8259 interrupt controller mask value,
disable UART interrupts and restore original interrupt vector. */
void rs_close(void)
{
extern struct rs_statics rs_ss;
extern volatile struct rs_dynamics rs_ds;
extern int rs_portopen;
extern void interrupt (*rs_oldvec)(void);
unsigned rs_time,rs_tail;
if(! rs_portopen) /* no port to close */
return;
/* if buffer xmit in progress, wait til it's done */
if(rs_ds.ier_msk == '\x0F'){
rs_time = rs_timer(1);
rs_tail = rs_ds.out_tail;
while(rs_ds.out_head != rs_ds.out_tail)
/* make sure output is moving else time out (wait one char period) */
if(rs_timer(1) - rs_time > 4 && rs_tail == rs_ds.out_tail)
break;
}
/* insure that tranmitter is empty before continuing */
rs_time = rs_timer(1);
while(! (inportb(rs_ss.lsr) & '\x40'))
if(rs_timer(1) - rs_time > 4)
break;
if(rs_ss.oldmask){
disable();
outportb(0x20,'\xC7'); /* restore interrupt priorities */
enable();
}
/* disable UART interrupts */
outportb(rs_ss.ier,0);
outportb(rs_ss.mcr,inportb(rs_ss.mcr) & '\xF7');
/* restore old interrupt vector */
if(rs_oldvec != NULL)
setvect(rs_ss.int_no,rs_oldvec);
rs_oldvec = NULL;
rs_portopen = 0; /* signal port closed */
}
/* rs_sndbyt: Output byte via output buffer. If no space in output buffer,
wait til there is unless output is disabled via flow control, in which
case return -1. If RS_POLLED_XMIT is defined, the byte is written to
the port when the transmit holding register becomes empy. THRE interrupt
and output buffer are not used. Return -1 if output disabled via flow
control. */
int rs_sndbyt(int rs_snd)
{
extern int rs_portopen;
extern volatile struct rs_dynamics rs_ds;
extern struct rs_statics rs_ss;
if(! rs_portopen) /* is a port open ? */
return -1;
#ifndef RS_POLLED_XMIT /* interrupt driven output */
while(((rs_ds.out_head + 1) & rs_ss.obuf_siz) == rs_ds.out_tail){
/* make sure there's room in the buffer */
/* if xmit disabled via flow control, don't wait */
if(rs_ds.ier_msk == '\x0D')
return -1;
}
disable();
*(rs_ss.out_buf + rs_ds.out_head++) = (unsigned char)rs_snd;
rs_ds.out_head &= rs_ss.obuf_siz;
enable();
if(rs_ds.ier_msk != '\x0D'){
outportb(rs_ss.ier,'\x0D');
if(! rs_ss.uart) /* if it's an 8250 or 8250B... */
while(! (inportb(rs_ss.lsr) & '\x20')) /* ...wait for THRE */
;
outportb(rs_ss.ier,'\x0F'); /* generate an interrupt if needed */
}
#else /* polled mode output */
if(rs_ds.ier_msk == '\x0D')
return -1;
while(! (inportb(rs_ss.lsr) & '\x20')) /* wait for THRE */
;
outportb(rs_ss.thr,(unsigned char)rs_snd);
#endif
return 0;
}
/* rs_sndstr: Output rs_sndcnt chars from rs_str to output buffer. If not
enough space in output buffer, wait til there is. If output disabled
via flow control, return count of characters written to output buffer
if less than string length. If rs_sndcnt is 0, output characters from
rs_str until nul character is reached. If RS_POLLED_XMIT is defined,
string is written to port by polling the line status register for THRE
and the buffer is not used. If output is disabled via flow control,
return count of characters sent */
int rs_sndstr(int rs_sndcnt, char *rs_str)
{
extern struct rs_statics rs_ss;
extern volatile struct rs_dynamics rs_ds;
int rs_x,rs_y;
if(! rs_portopen) /* is a port open? */
return -1;
if(rs_sndcnt) /* string length specified? */
rs_y = rs_sndcnt;
else
rs_y = 0x7FFF; /* max buffer length (`11/2) */
#ifndef RS_POLLED_XMIT /* interrupt driven transmit */
for(rs_x = 0;rs_x < rs_y;rs_x++){
/* if no string length specified, stop when nul is encountered */
if(! rs_sndcnt){
if(*(rs_str + rs_x) == '\0')
break;
}
while(((rs_ds.out_head + 1) & rs_ss.obuf_siz) == rs_ds.out_tail){
/* if xmit disabled via flow control,don't wait */
if(rs_ds.ier_msk == '\x0D')
return rs_x;
else{ /* otherwise, may need to get xmit interrupts going (`11/2) */
outportb(rs_ss.ier,'\x0D');
if(! rs_ss.uart) /* if it's an 8250 or 8250B... */
while(! (inportb(rs_ss.lsr) & '\x20')) /* wait for THRE */
;
outportb(rs_ss.ier,'\x0F'); /* kick transmit interrupt */
}
}
disable();
*(rs_ss.out_buf + rs_ds.out_head++) = (unsigned char)*(rs_str + rs_x);
rs_ds.out_head &= rs_ss.obuf_siz;
enable();
}
if(rs_ds.ier_msk != '\x0D'){
outportb(rs_ss.ier,'\x0D');
if(! rs_ss.uart)
while(! (inportb(rs_ss.lsr) & '\x20'))
;
outportb(rs_ss.ier,'\x0F'); /* generate an interrupt if needed */
}
#else /* polled transmit */
for(rs_x = 0;rs_x < rs_y;rs_x++){
/* if xmit disabled via flow control,don't wait */
if(rs_ds.ier_msk == '\x0D')
return rs_x;
/* if no string length specified, stop when nul is encountered */
if(! rs_sndcnt){
if(*(rs_str + rs_x) == '\0')
break;
}
while(! (inportb(rs_ss.lsr) & '\x20'))
;
outportb(rs_ss.thr,(unsigned char)*(rs_str + rs_x));
}
#endif
return 0;
}
/* rs_outfre: Return amount of free space available in output buffer.
This function does not return a meaningful value if RS_POLLED_XMIT is
defined because transmission does not use the buffer */
unsigned rs_outfre(void)
{
extern struct rs_statics rs_ss;
extern volatile struct rs_dynamics rs_ds;
return(rs_ss.obuf_siz + 1 - ((rs_ds.out_head - rs_ds.out_tail) &
rs_ss.obuf_siz));
}
/* rs_scanin: Scan for first occurance of string rs_scan_str in input buffer.
Return -1 if not found, offset into buffer if found */
int rs_scanin(char *rs_scan_str)
{
extern struct rs_statics rs_ss;
extern volatile struct rs_dynamics rs_ds;
extern int rs_portopen;
int rs_off,rs_incnt,rs_flg = 0,rs_len = 0;
while(*(rs_scan_str + rs_len))
rs_len++;
if((! rs_portopen) || (! rs_ds.rcv_cnt) || (! rs_len))
return -1;
for(rs_off = 0;rs_off < rs_ds.rcv_cnt;rs_off++){
if(*(rs_ss.in_buf + ((rs_ds.in_tail + rs_off) & rs_ss.ibuf_siz)) ==
*(rs_scan_str + rs_flg)){
rs_flg++;
if(rs_flg == rs_len)
return((rs_off - (rs_len - 1)) & rs_ss.ibuf_siz);
}
else
rs_flg = 0;
}
return -1;
}
/* rs_peek: Return next available character from input buffer, leave
character in buffer. Return -1 if none are available */
int rs_peek(void)
{
extern struct rs_statics rs_ss;
extern volatile struct rs_dynamics rs_ds;
extern int rs_portopen;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -