⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rs232.c

📁 Minix3.11的源码。[MINIX 3是一个为高可靠性应用而设计的自由且简洁的类UNIX系统。]
💻 C
📖 第 1 页 / 共 2 页
字号:
#include <minix/config.h>/*---------------------------------------------------------------------------* *		rs232.c - serial driver for 8250 and 16450 UARTs	     * *		Added support for Atari ST M68901 and YM-2149	--kub	     * *---------------------------------------------------------------------------*/#include "../drivers.h"#include <termios.h>#include <signal.h>#include "tty.h"#if NR_RS_LINES > 0#if (MACHINE != IBM_PC) && (MACHINE != ATARI)#error				/* rs232.c only supports PC and Atari ST */#endif#if (MACHINE == ATARI)#include "staddr.h"#include "stsound.h"#include "stmfp.h"#if (NR_RS_LINES > 1)#error				/* Only one physical RS232 line available */#endif#endif#if (MACHINE == IBM_PC)		/* PC/AT 8250/16450 chip combination *//* 8250 constants. */#define UART_FREQ         115200L	/* timer frequency *//* Interrupt enable bits. */#define IE_RECEIVER_READY       1#define IE_TRANSMITTER_READY    2#define IE_LINE_STATUS_CHANGE   4#define IE_MODEM_STATUS_CHANGE  8/* Interrupt status bits. */#define IS_MODEM_STATUS_CHANGE  0#define IS_TRANSMITTER_READY    2#define IS_RECEIVER_READY       4#define IS_LINE_STATUS_CHANGE   6/* Line control bits. */#define LC_2STOP_BITS        0x04#define LC_PARITY            0x08#define LC_PAREVEN           0x10#define LC_BREAK             0x40#define LC_ADDRESS_DIVISOR   0x80/* Line status bits. */#define LS_OVERRUN_ERR          2#define LS_PARITY_ERR           4#define LS_FRAMING_ERR          8#define LS_BREAK_INTERRUPT   0x10#define LS_TRANSMITTER_READY 0x20/* Modem control bits. */#define MC_DTR                  1#define MC_RTS                  2#define MC_OUT2                 8	/* required for PC & AT interrupts *//* Modem status bits. */#define MS_CTS               0x10#define MS_RLSD              0x80       /* Received Line Signal Detect */#define MS_DRLSD             0x08       /* RLSD Delta */#else /* MACHINE == ATARI */		/* Atari ST 68901 USART *//* Most of the USART constants are already defined in stmfp.h . The local * definitions made here are for keeping C code changes smaller.   --kub */#define UART_FREQ          19200L	/* timer frequency *//* Line status bits. */#define LS_OVERRUN_ERR       R_OE#define LS_PARITY_ERR        R_PE#define LS_FRAMING_ERR       R_FE#define LS_BREAK_INTERRUPT   R_BREAK/* Modem status bits. */#define MS_CTS               IO_SCTS	/* 0x04 */#endif /* MACHINE == ATARI */#define DATA_BITS_SHIFT         8	/* amount data bits shifted in mode */#define DEF_BAUD             1200	/* default baud rate */#define RS_IBUFSIZE          1024	/* RS232 input buffer size */#define RS_OBUFSIZE          1024	/* RS232 output buffer size *//* Input buffer watermarks. * The external device is asked to stop sending when the buffer * exactly reaches high water, or when TTY requests it.  Sending restarts * when the input buffer empties below the low watermark. */#define RS_ILOWWATER	(1 * RS_IBUFSIZE / 4)#define RS_IHIGHWATER	(3 * RS_IBUFSIZE / 4)/* Output buffer low watermark. * TTY is notified when the output buffer empties below the low watermark, so * it may continue filling the buffer if doing a large write. */#define RS_OLOWWATER	(1 * RS_OBUFSIZE / 4)#if (MACHINE == IBM_PC)/* Macros to handle flow control. * Interrupts must be off when they are used. * Time is critical - already the function call for outb() is annoying. * If outb() can be done in-line, tests to avoid it can be dropped. * istart() tells external device we are ready by raising RTS. * istop() tells external device we are not ready by dropping RTS. * DTR is kept high all the time (it probably should be raised by open and * dropped by close of the device). * OUT2 is also kept high all the time. */#define istart(rs) \	(sys_outb((rs)->modem_ctl_port, MC_OUT2 | MC_RTS | MC_DTR), \		(rs)->idevready = TRUE)#define istop(rs) \	(sys_outb((rs)->modem_ctl_port, MC_OUT2 | MC_DTR), \		(rs)->idevready = FALSE)/* Macro to tell if device is ready.  The rs->cts field is set to MS_CTS if * CLOCAL is in effect for a line without a CTS wire. */#define devready(rs) ((my_inb(rs->modem_status_port) | rs->cts) & MS_CTS)/* Macro to tell if transmitter is ready. */#define txready(rs) (my_inb(rs->line_status_port) & LS_TRANSMITTER_READY)/* Macro to tell if carrier has dropped. * The RS232 Carrier Detect (CD) line is usually connected to the 8250 * Received Line Signal Detect pin, reflected by bit MS_RLSD in the Modem * Status Register.  The MS_DRLSD bit tells if MS_RLSD has just changed state. * So if MS_DRLSD is set and MS_RLSD cleared, we know that carrier has just * dropped. */#define devhup(rs)	\	((my_inb(rs->modem_status_port) & (MS_RLSD|MS_DRLSD)) == MS_DRLSD)#else /* MACHINE == ATARI *//* Macros to handle flow control. * Time is critical - already the function call for lock()/restore() is * annoying. * istart() tells external device we are ready by raising RTS. * istop() tells external device we are not ready by dropping RTS. * DTR is kept high all the time (it probably should be raised by open and * dropped by close of the device). NOTE: The modem lines are active low. */#define set_porta(msk,val) { register int s = lock();		\			     SOUND->sd_selr = YM_IOA;		\			     SOUND->sd_wdat =			\				SOUND->sd_rdat & (msk) | (val);	\			     restore(s);	}#define istart(rs)         { set_porta( ~(PA_SRTS|PA_SDTR),0 ); \			     (rs)->idevready = TRUE;	}#define istop(rs)          { set_porta( ~PA_SDTR, PA_SRTS );	\			     (rs)->idevready = FALSE;	}/* Macro to tell if device is ready.  The rs->cts field is set to MS_CTS if * CLOCAL is in effect for a line without a CTS wire. */#define devready(rs)         ((~MFP->mf_gpip | rs->cts) & MS_CTS)/* Transmitter ready test */#define txready(rs)          (MFP->mf_tsr & (T_EMPTY | T_UE))#endif /* MACHINE == ATARI *//* Types. */typedef unsigned char bool_t;	/* boolean *//* RS232 device structure, one per device. */typedef struct rs232 {  tty_t *tty;			/* associated TTY structure */  int icount;			/* number of bytes in the input buffer */  char *ihead;			/* next free spot in input buffer */  char *itail;			/* first byte to give to TTY */  bool_t idevready;		/* nonzero if we are ready to receive (RTS) */  char cts;			/* normally 0, but MS_CTS if CLOCAL is set */  unsigned char ostate;		/* combination of flags: */#define ODONE          1	/* output completed (< output enable bits) */#define ORAW           2	/* raw mode for xoff disable (< enab. bits) */#define OWAKEUP        4	/* tty_wakeup() pending (asm code only) */#define ODEVREADY MS_CTS	/* external device hardware ready (CTS) */#define OQUEUED     0x20	/* output buffer not empty */#define OSWREADY    0x40	/* external device software ready (no xoff) */#define ODEVHUP  MS_RLSD	/* external device has dropped carrier */#define OSOFTBITS  (ODONE | ORAW | OWAKEUP | OQUEUED | OSWREADY)				/* user-defined bits */#if (OSOFTBITS | ODEVREADY | ODEVHUP) == OSOFTBITS				/* a weak sanity check */#error				/* bits are not unique */#endif  unsigned char oxoff;		/* char to stop output */  bool_t inhibited;		/* output inhibited? (follows tty_inhibited) */  bool_t drain;			/* if set drain output and reconfigure line */  int ocount;			/* number of bytes in the output buffer */  char *ohead;			/* next free spot in output buffer */  char *otail;			/* next char to output */#if (MACHINE == IBM_PC)  port_t xmit_port;		/* i/o ports */  port_t recv_port;  port_t div_low_port;  port_t div_hi_port;  port_t int_enab_port;  port_t int_id_port;  port_t line_ctl_port;  port_t modem_ctl_port;  port_t line_status_port;  port_t modem_status_port;#endif  unsigned char lstatus;	/* last line status */  unsigned char pad;		/* ensure alignment for 16-bit ints */  unsigned framing_errors;	/* error counts (no reporting yet) */  unsigned overrun_errors;  unsigned parity_errors;  unsigned break_interrupts;  int irq;			/* irq for this line */  int irq_hook_id;		/* interrupt hook */  char ibuf[RS_IBUFSIZE];	/* input buffer */  char obuf[RS_OBUFSIZE];	/* output buffer */} rs232_t;PUBLIC rs232_t rs_lines[NR_RS_LINES];/* Table and macro to translate an RS232 line number to its rs_lines entry. */PRIVATE rs232_t *p_rs_addr[NR_RS_LINES];#define rs_addr(line)	(p_rs_addr[line])#if (MACHINE == IBM_PC)/* 8250 base addresses. */PRIVATE port_t addr_8250[] = {  0x3F8,	/* COM1 */  0x2F8,	/* COM2 */  0x3E8,	/* COM3 */  0x2E8,	/* COM4 */};#endifFORWARD _PROTOTYPE( void in_int, (rs232_t *rs)				);FORWARD _PROTOTYPE( void line_int, (rs232_t *rs)			);FORWARD _PROTOTYPE( void modem_int, (rs232_t *rs)			);FORWARD _PROTOTYPE( int rs_write, (tty_t *tp, int try)			);FORWARD _PROTOTYPE( void rs_echo, (tty_t *tp, int c)			);FORWARD _PROTOTYPE( int rs_ioctl, (tty_t *tp, int try)			);FORWARD _PROTOTYPE( void rs_config, (rs232_t *rs)			);FORWARD _PROTOTYPE( int rs_read, (tty_t *tp, int try)			);FORWARD _PROTOTYPE( int rs_icancel, (tty_t *tp, int try)		);FORWARD _PROTOTYPE( int rs_ocancel, (tty_t *tp, int try)		);FORWARD _PROTOTYPE( void rs_ostart, (rs232_t *rs)			);FORWARD _PROTOTYPE( int rs_break, (tty_t *tp, int try)			);FORWARD _PROTOTYPE( int rs_close, (tty_t *tp, int try)			);FORWARD _PROTOTYPE( void out_int, (rs232_t *rs)				);FORWARD _PROTOTYPE( void rs232_handler, (rs232_t *rs)			);/* XXX */PRIVATE void lock(void) {}PRIVATE void unlock(void) {}PRIVATE int my_inb(port_t port){	int r, v = 0;	r = sys_inb(port, &v);	if (r != OK)		printf("RS232 warning: failed inb 0x%x\n", port);	return v;}/*===========================================================================* *				rs_write				     * *===========================================================================*/PRIVATE int rs_write(tp, try)register tty_t *tp;int try;{/* (*devwrite)() routine for RS232. */  rs232_t *rs = tp->tty_priv;  int count, ocount;  if (rs->inhibited != tp->tty_inhibited) {	/* Inhibition state has changed. */	lock();	rs->ostate |= OSWREADY;	if (tp->tty_inhibited) rs->ostate &= ~OSWREADY;	unlock();	rs->inhibited = tp->tty_inhibited;  }  if (rs->drain) {	/* Wait for the line to drain then reconfigure and continue output. */	if (rs->ocount > 0) return 0;	rs->drain = FALSE;	rs_config(rs);  }  /* While there is something to do. */  for (;;) {	ocount = buflen(rs->obuf) - rs->ocount;	count = bufend(rs->obuf) - rs->ohead;	if (count > ocount) count = ocount;	if (count > tp->tty_outleft) count = tp->tty_outleft;	if (count == 0 || tp->tty_inhibited) {		if (try) return 0;		break;	}	if (try) return 1;	/* Copy from user space to the RS232 output buffer. */	sys_vircopy(tp->tty_outproc, D, (vir_bytes) tp->tty_out_vir, 		SELF, D, (vir_bytes) rs->ohead, (phys_bytes) count);	/* Perform output processing on the output buffer. */	out_process(tp, rs->obuf, rs->ohead, bufend(rs->obuf), &count, &ocount);	if (count == 0) break;	/* Assume echoing messed up by output. */	tp->tty_reprint = TRUE;	/* Bookkeeping. */	lock();			/* protect interrupt sensitive rs->ocount */	rs->ocount += ocount;	rs_ostart(rs);	unlock();	if ((rs->ohead += ocount) >= bufend(rs->obuf))		rs->ohead -= buflen(rs->obuf);	tp->tty_out_vir += count;	tp->tty_outcum += count;	if ((tp->tty_outleft -= count) == 0) {		/* Output is finished, reply to the writer. */		tty_reply(tp->tty_outrepcode, tp->tty_outcaller,					tp->tty_outproc, tp->tty_outcum);		tp->tty_outcum = 0;	}  }  if (tp->tty_outleft > 0 && tp->tty_termios.c_ospeed == B0) {	/* Oops, the line has hung up. */	tty_reply(tp->tty_outrepcode, tp->tty_outcaller, tp->tty_outproc, EIO);	tp->tty_outleft = tp->tty_outcum = 0;  }  return 1;}/*===========================================================================* *				rs_echo					     * *===========================================================================*/PRIVATE void rs_echo(tp, c)tty_t *tp;			/* which TTY */int c;				/* character to echo */{/* Echo one character.  (Like rs_write, but only one character, optionally.) */  rs232_t *rs = tp->tty_priv;  int count, ocount;  ocount = buflen(rs->obuf) - rs->ocount;  if (ocount == 0) return;		/* output buffer full */  count = 1;  *rs->ohead = c;			/* add one character */  out_process(tp, rs->obuf, rs->ohead, bufend(rs->obuf), &count, &ocount);  if (count == 0) return;  lock();  rs->ocount += ocount;  rs_ostart(rs);  unlock();  if ((rs->ohead += ocount) >= bufend(rs->obuf)) rs->ohead -= buflen(rs->obuf);}/*===========================================================================* *				rs_ioctl				     * *===========================================================================*/PRIVATE int rs_ioctl(tp, dummy)tty_t *tp;			/* which TTY */int dummy;{/* Reconfigure the line as soon as the output has drained. */  rs232_t *rs = tp->tty_priv;  rs->drain = TRUE;  return 0;	/* dummy */}/*===========================================================================* *				rs_config				     * *===========================================================================*/PRIVATE void rs_config(rs)rs232_t *rs;			/* which line */{/* Set various line control parameters for RS232 I/O. * If DataBits == 5 and StopBits == 2, 8250 will generate 1.5 stop bits. * The 8250 can't handle split speed, so we use the input speed. */  tty_t *tp = rs->tty;  int divisor;  int line_controls;  static struct speed2divisor {	speed_t	speed;	int	divisor;  } s2d[] = {#if (MACHINE == IBM_PC)	{ B50,		UART_FREQ / 50		},#endif	{ B75,		UART_FREQ / 75		},	{ B110,		UART_FREQ / 110		},	{ B134,		UART_FREQ * 10 / 1345	},	{ B150,		UART_FREQ / 150		},	{ B200,		UART_FREQ / 200		},	{ B300,		UART_FREQ / 300		},	{ B600,		UART_FREQ / 600		},	{ B1200,	UART_FREQ / 1200	},#if (MACHINE == IBM_PC)	{ B1800,	UART_FREQ / 1800	},#endif	{ B2400,	UART_FREQ / 2400	},	{ B4800,	UART_FREQ / 4800	},	{ B9600,	UART_FREQ / 9600	},	{ B19200,	UART_FREQ / 19200	},#if (MACHINE == IBM_PC)	{ B38400,	UART_FREQ / 38400	},	{ B57600,	UART_FREQ / 57600	},	{ B115200,	UART_FREQ / 115200L	},#endif  };  struct speed2divisor *s2dp;  /* RS232 needs to know the xoff character, and if CTS works. */  rs->oxoff = tp->tty_termios.c_cc[VSTOP];  rs->cts = (tp->tty_termios.c_cflag & CLOCAL) ? MS_CTS : 0;  /* Look up the 8250 rate divisor from the output speed. */  divisor = 0;  for (s2dp = s2d; s2dp < s2d + sizeof(s2d)/sizeof(s2d[0]); s2dp++) {	if (s2dp->speed == tp->tty_termios.c_ospeed) divisor = s2dp->divisor;  }  if (divisor == 0) return;	/* B0? */#if (MACHINE == IBM_PC)  /* Compute line control flag bits. */  line_controls = 0;  if (tp->tty_termios.c_cflag & PARENB) {	line_controls |= LC_PARITY;	if (!(tp->tty_termios.c_cflag & PARODD)) line_controls |= LC_PAREVEN;  }  if (divisor >= (UART_FREQ / 110)) line_controls |= LC_2STOP_BITS;  line_controls |= (tp->tty_termios.c_cflag & CSIZE) >> 2;  /* Lock out interrupts while setting the speed. The receiver register is   * going to be hidden by the div_low register, but the input interrupt   * handler relies on reading it to clear the interrupt and avoid looping   * forever.   */  lock();  /* Select the baud rate divisor registers and change the rate. */  sys_outb(rs->line_ctl_port, LC_ADDRESS_DIVISOR);  sys_outb(rs->div_low_port, divisor);  sys_outb(rs->div_hi_port, divisor >> 8);  /* Change the line controls and reselect the usual registers. */  sys_outb(rs->line_ctl_port, line_controls);  rs->ostate = devready(rs) | ORAW | OSWREADY;	/* reads modem_ctl_port */  if ((tp->tty_termios.c_lflag & IXON) && rs->oxoff != _POSIX_VDISABLE)	rs->ostate &= ~ORAW;  unlock();#else /* MACHINE == ATARI */  line_controls = U_Q16;  if (tp->tty_termios.c_cflag & PARENB) {	line_controls |= U_PAR;	if (!(tp->tty_termios.c_cflag & PARODD)) line_controls |= U_EVEN;  }  line_controls |= (divisor >= (UART_FREQ / 110)) ? U_ST2 : U_ST1;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -