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

📄 termios.c

📁 RTEMS (Real-Time Executive for Multiprocessor Systems) is a free open source real-time operating sys
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * TERMIOS serial line support * *  Author: *    W. Eric Norum *    Saskatchewan Accelerator Laboratory *    University of Saskatchewan *    Saskatoon, Saskatchewan, CANADA *    eric@skatter.usask.ca * *  The license and distribution terms for this file may be *  found in the file LICENSE in this distribution or at *  http://www.rtems.com/license/LICENSE. * *  $Id: termios.c,v 1.39.2.6 2006/03/07 22:22:46 joel Exp $ */#if HAVE_CONFIG_H#include "config.h"#endif#include <rtems.h>#include <rtems/libio.h>#include <ctype.h>#include <errno.h>#include <stdio.h>#include <stdlib.h>#include <termios.h>#include <unistd.h>#include <sys/ttycom.h>#include <rtems/termiostypes.h>/* *  FreeBSD does not support a full POSIX termios so we have to help it out */#if !HAVE_DECL_XTABS#define XTABS   0#endif#if !HAVE_DECL_ONLRET#define ONLRET  0#endif#if !HAVE_DECL_ONOCR#define ONOCR  0#endif#if !HAVE_DECL_TABDLY#define TABDLY  0#endif#if !HAVE_DECL_OLCUC#define OLCUC 0#endif#if !HAVE_DECL_ILCUC#define ILCUC 0#endif#if !HAVE_DECL_OCRNL#define OCRNL 0#endif#if !HAVE_DECL_IUCLC#define IUCLC   0#endif#if !HAVE_DECL_ECHOPRT#define ECHOPRT 0#endif/* * The size of the cooked buffer */#define CBUFSIZE	(rtems_termios_cbufsize)/* * The sizes of the raw message buffers. * On most architectures it is quite a bit more * efficient if these are powers of two. */#define RAW_INPUT_BUFFER_SIZE	(rtems_termios_raw_input_size)#define RAW_OUTPUT_BUFFER_SIZE	(rtems_termios_raw_output_size)/* fields for "flow_ctrl" status */#define FL_IREQXOF 1        /* input queue requests stop of incoming data */#define FL_ISNTXOF 2        /* XOFF has been sent to other side of line   */#define FL_IRTSOFF 4        /* RTS has been turned off for other side..   */#define FL_ORCVXOF 0x10     /* XOFF has been received                     */#define FL_OSTOP   0x20     /* output has been stopped due to XOFF        */#define FL_MDRTS   0x100    /* input controlled with RTS/CTS handshake    */#define FL_MDXON   0x200    /* input controlled with XON/XOFF protocol    */#define FL_MDXOF   0x400    /* output controlled with XON/XOFF protocol   */#define NODISC(n) \	{ NULL,	NULL,	NULL,	NULL, \	  NULL,	NULL,	NULL,	NULL }/* * FIXME: change linesw entries consistant with linesw entry usage... */struct	linesw linesw[MAXLDISC] ={	NODISC(0),		/* 0- termios-built-in */	NODISC(1),		/* 1- defunct */	NODISC(2),              /* 2- NTTYDISC */	NODISC(3),		/* TABLDISC */	NODISC(4),		/* SLIPDISC */	NODISC(5),		/* PPPDISC */	NODISC(6),		/* loadable */	NODISC(7),		/* loadable */};int	nlinesw = sizeof (linesw) / sizeof (linesw[0]);extern struct rtems_termios_tty *rtems_termios_ttyHead;extern struct rtems_termios_tty *rtems_termios_ttyTail;extern rtems_id rtems_termios_ttyMutex;static int rtems_termios_cbufsize = 256;static int rtems_termios_raw_input_size = 128;static int rtems_termios_raw_output_size = 64;static rtems_task rtems_termios_rxdaemon(rtems_task_argument argument);static rtems_task rtems_termios_txdaemon(rtems_task_argument argument);/* * some constants for I/O daemon task creation */#define TERMIOS_TXTASK_PRIO 10#define TERMIOS_RXTASK_PRIO 9#define TERMIOS_TXTASK_STACKSIZE 1024#define TERMIOS_RXTASK_STACKSIZE 1024/* * some events to be sent to the I/O tasks */#define TERMIOS_TX_START_EVENT     RTEMS_EVENT_1#define TERMIOS_TX_TERMINATE_EVENT RTEMS_EVENT_0#define TERMIOS_RX_PROC_EVENT      RTEMS_EVENT_1#define TERMIOS_RX_TERMINATE_EVENT RTEMS_EVENT_0/* * Open a termios device */rtems_status_codertems_termios_open (  rtems_device_major_number      major,  rtems_device_minor_number      minor,  void                          *arg,  const rtems_termios_callbacks *callbacks  ){	rtems_status_code sc;	rtems_libio_open_close_args_t *args = arg;	struct rtems_termios_tty *tty;	/*	 * See if the device has already been opened	 */	sc = rtems_semaphore_obtain (rtems_termios_ttyMutex,				     RTEMS_WAIT, RTEMS_NO_TIMEOUT);	if (sc != RTEMS_SUCCESSFUL)		return sc;	for (tty = rtems_termios_ttyHead ; tty != NULL ; tty = tty->forw) {		if ((tty->major == major) && (tty->minor == minor))			break;	}	if (tty == NULL) {		static char c = 'a';		/*		 * Create a new device		 */		tty = calloc (1, sizeof (struct rtems_termios_tty));		if (tty == NULL) {			rtems_semaphore_release (rtems_termios_ttyMutex);			return RTEMS_NO_MEMORY;		}		/*		 * allocate raw input buffer		 */		tty->rawInBuf.Size = RAW_INPUT_BUFFER_SIZE;		tty->rawInBuf.theBuf = malloc (tty->rawInBuf.Size);		if (tty->rawInBuf.theBuf == NULL) {		        free(tty);			rtems_semaphore_release (rtems_termios_ttyMutex);			return RTEMS_NO_MEMORY;		}		/*		 * allocate raw output buffer		 */		tty->rawOutBuf.Size = RAW_OUTPUT_BUFFER_SIZE;		tty->rawOutBuf.theBuf = malloc (tty->rawOutBuf.Size);		if (tty->rawOutBuf.theBuf == NULL) {		        free((void *)(tty->rawInBuf.theBuf));		        free(tty);			rtems_semaphore_release (rtems_termios_ttyMutex);			return RTEMS_NO_MEMORY;		}		/*		 * allocate cooked buffer		 */		tty->cbuf  = malloc (CBUFSIZE);		if (tty->cbuf == NULL) {		        free((void *)(tty->rawOutBuf.theBuf));		        free((void *)(tty->rawInBuf.theBuf));		        free(tty);			rtems_semaphore_release (rtems_termios_ttyMutex);			return RTEMS_NO_MEMORY;		}		/*		 * Initialize wakeup callbacks		 */		tty->tty_snd.sw_pfn = NULL;		tty->tty_snd.sw_arg = NULL;		tty->tty_rcv.sw_pfn = NULL;		tty->tty_rcv.sw_arg = NULL;		tty->tty_rcvwakeup  = 0;		/*		 * link tty		 */		tty->forw = rtems_termios_ttyHead;		tty->back = NULL;		if (rtems_termios_ttyHead != NULL)			rtems_termios_ttyHead->back = tty;		rtems_termios_ttyHead = tty;		if (rtems_termios_ttyTail == NULL)			rtems_termios_ttyTail = tty;		tty->minor = minor;		tty->major = major;		/*		 * Set up mutex semaphores		 */		sc = rtems_semaphore_create (			rtems_build_name ('T', 'R', 'i', c),			1,			RTEMS_BINARY_SEMAPHORE | RTEMS_INHERIT_PRIORITY | RTEMS_PRIORITY,			RTEMS_NO_PRIORITY,			&tty->isem);		if (sc != RTEMS_SUCCESSFUL)			rtems_fatal_error_occurred (sc);		sc = rtems_semaphore_create (			rtems_build_name ('T', 'R', 'o', c),			1,			RTEMS_BINARY_SEMAPHORE | RTEMS_INHERIT_PRIORITY | RTEMS_PRIORITY,			RTEMS_NO_PRIORITY,			&tty->osem);		if (sc != RTEMS_SUCCESSFUL)			rtems_fatal_error_occurred (sc);		sc = rtems_semaphore_create (			rtems_build_name ('T', 'R', 'x', c),			0,			RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_FIFO,			RTEMS_NO_PRIORITY,			&tty->rawOutBuf.Semaphore);		if (sc != RTEMS_SUCCESSFUL)			rtems_fatal_error_occurred (sc);		tty->rawOutBufState = rob_idle;		/*		 * Set callbacks		 */		tty->device = *callbacks;		/*		 * Create I/O tasks		 */		if (tty->device.outputUsesInterrupts == TERMIOS_TASK_DRIVEN) {			sc = rtems_task_create (                                   rtems_build_name ('T', 'x', 'T', c),				   TERMIOS_TXTASK_PRIO,				   TERMIOS_TXTASK_STACKSIZE,				   RTEMS_NO_PREEMPT | RTEMS_NO_TIMESLICE | 				   RTEMS_NO_ASR,				   RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL,				   &tty->txTaskId);			if (sc != RTEMS_SUCCESSFUL)				rtems_fatal_error_occurred (sc);			sc = rtems_task_create (                                   rtems_build_name ('R', 'x', 'T', c),				   TERMIOS_RXTASK_PRIO,				   TERMIOS_RXTASK_STACKSIZE,				   RTEMS_NO_PREEMPT | RTEMS_NO_TIMESLICE | 				   RTEMS_NO_ASR,				   RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL,				   &tty->rxTaskId);			if (sc != RTEMS_SUCCESSFUL)				rtems_fatal_error_occurred (sc);						}		if ((tty->device.pollRead == NULL) ||		    (tty->device.outputUsesInterrupts == TERMIOS_TASK_DRIVEN)){			sc = rtems_semaphore_create (				rtems_build_name ('T', 'R', 'r', c),				0,				RTEMS_COUNTING_SEMAPHORE | RTEMS_PRIORITY,				RTEMS_NO_PRIORITY,				&tty->rawInBuf.Semaphore);			if (sc != RTEMS_SUCCESSFUL)				rtems_fatal_error_occurred (sc);		}		/*		 * Set default parameters		 */		tty->termios.c_iflag = BRKINT | ICRNL | IXON | IMAXBEL;		tty->termios.c_oflag = OPOST | ONLCR | XTABS;		tty->termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL;		tty->termios.c_lflag = ISIG | ICANON | IEXTEN | ECHO | ECHOK | ECHOE | ECHOCTL;		tty->termios.c_cc[VINTR] = '\003';		tty->termios.c_cc[VQUIT] = '\034';		tty->termios.c_cc[VERASE] = '\177';		tty->termios.c_cc[VKILL] = '\025';		tty->termios.c_cc[VEOF] = '\004';		tty->termios.c_cc[VEOL] = '\000';		tty->termios.c_cc[VEOL2] = '\000';		tty->termios.c_cc[VSTART] = '\021';		tty->termios.c_cc[VSTOP] = '\023';		tty->termios.c_cc[VSUSP] = '\032';		tty->termios.c_cc[VREPRINT] = '\022';		tty->termios.c_cc[VDISCARD] = '\017';		tty->termios.c_cc[VWERASE] = '\027';		tty->termios.c_cc[VLNEXT] = '\026';		/* start with no flow control, clear flow control flags */		tty->flow_ctrl = 0;		/*		 * set low/highwater mark for XON/XOFF support		 */		tty->lowwater  = tty->rawInBuf.Size * 1/2;		tty->highwater = tty->rawInBuf.Size * 3/4;		/*		 * Bump name characer		 */		if (c++ == 'z')			c = 'a';	}	args->iop->data1 = tty;	if (!tty->refcount++) {	  if (tty->device.firstOpen)		(*tty->device.firstOpen)(major, minor, arg);	  /*	   * start I/O tasks, if needed	   */	  if (tty->device.outputUsesInterrupts == TERMIOS_TASK_DRIVEN) {	    sc = rtems_task_start(tty->rxTaskId,				  rtems_termios_rxdaemon,				  (rtems_task_argument)tty);	    if (sc != RTEMS_SUCCESSFUL)	      rtems_fatal_error_occurred (sc);	    	    sc = rtems_task_start(tty->txTaskId,				  rtems_termios_txdaemon,				  (rtems_task_argument)tty);	    if (sc != RTEMS_SUCCESSFUL)	      rtems_fatal_error_occurred (sc);	  }	}	rtems_semaphore_release (rtems_termios_ttyMutex);	return RTEMS_SUCCESSFUL;}/* * Drain output queue */static voiddrainOutput (struct rtems_termios_tty *tty){	rtems_interrupt_level level;	rtems_status_code sc;	if (tty->device.outputUsesInterrupts != TERMIOS_POLLED) {		rtems_interrupt_disable (level);		while (tty->rawOutBuf.Tail != tty->rawOutBuf.Head) {			tty->rawOutBufState = rob_wait;			rtems_interrupt_enable (level);			sc = rtems_semaphore_obtain (tty->rawOutBuf.Semaphore,							RTEMS_WAIT,							RTEMS_NO_TIMEOUT);			if (sc != RTEMS_SUCCESSFUL)				rtems_fatal_error_occurred (sc);			rtems_interrupt_disable (level);		}		rtems_interrupt_enable (level);	}}rtems_status_codertems_termios_close (void *arg){	rtems_libio_open_close_args_t *args = arg;	struct rtems_termios_tty *tty = args->iop->data1;	rtems_status_code sc;	sc = rtems_semaphore_obtain (rtems_termios_ttyMutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);	if (sc != RTEMS_SUCCESSFUL)		rtems_fatal_error_occurred (sc);	if (--tty->refcount == 0) {                if (linesw[tty->t_line].l_close != NULL) {			/*			 * call discipline-specific close			 */			sc = linesw[tty->t_line].l_close(tty);		}		else {			/*			 * default: just flush output buffer			 */		        drainOutput (tty);		}	  		if (tty->device.outputUsesInterrupts 		    == TERMIOS_TASK_DRIVEN) {			/*			 * send "terminate" to I/O tasks			 */			sc = rtems_event_send(                                  tty->rxTaskId,				  TERMIOS_RX_TERMINATE_EVENT);			if (sc != RTEMS_SUCCESSFUL)				rtems_fatal_error_occurred (sc);			sc = rtems_event_send(                                  tty->txTaskId,				  TERMIOS_TX_TERMINATE_EVENT);			if (sc != RTEMS_SUCCESSFUL)				rtems_fatal_error_occurred (sc);		}		if (tty->device.lastClose)			 (*tty->device.lastClose)(tty->major, tty->minor, arg);		if (tty->forw == NULL) {			rtems_termios_ttyTail = tty->back;			if ( rtems_termios_ttyTail != NULL ) {				rtems_termios_ttyTail->forw = NULL;			}		}		else {			tty->forw->back = tty->back;		}		if (tty->back == NULL) {			rtems_termios_ttyHead = tty->forw;			if ( rtems_termios_ttyHead != NULL ) {				rtems_termios_ttyHead->back = NULL;			}		}		else {			tty->back->forw = tty->forw;		}		rtems_semaphore_delete (tty->isem);		rtems_semaphore_delete (tty->osem);		rtems_semaphore_delete (tty->rawOutBuf.Semaphore);		if ((tty->device.pollRead == NULL) ||		    (tty->device.outputUsesInterrupts == TERMIOS_TASK_DRIVEN))			rtems_semaphore_delete (tty->rawInBuf.Semaphore);		free (tty->rawInBuf.theBuf);		free (tty->rawOutBuf.theBuf);		free (tty->cbuf);		free (tty);	}	rtems_semaphore_release (rtems_termios_ttyMutex);	return RTEMS_SUCCESSFUL;}rtems_status_code rtems_termios_bufsize (  int cbufsize,  int raw_input,  int raw_output){  rtems_termios_cbufsize        = cbufsize;  rtems_termios_raw_input_size  = raw_input;  rtems_termios_raw_output_size = raw_output;  return RTEMS_SUCCESSFUL;}static void termios_set_flowctrl(struct rtems_termios_tty *tty){  rtems_interrupt_level level;  /*    * check for flow control options to be switched off    */  /* check for outgoing XON/XOFF flow control switched off */  if (( tty->flow_ctrl & FL_MDXON) &&      !(tty->termios.c_iflag & IXON)) {    /* clear related flags in flow_ctrl */    tty->flow_ctrl &= ~(FL_MDXON | FL_ORCVXOF);    /* has output been stopped due to received XOFF? */    if (tty->flow_ctrl & FL_OSTOP) {      /* disable interrupts    */      rtems_interrupt_disable(level);      tty->flow_ctrl &= ~FL_OSTOP;      /* check for chars in output buffer (or rob_state?) */      if (tty->rawOutBufState != rob_idle) {	/* if chars available, call write function... */	(*tty->device.write)(tty->minor,		     (char *)&tty->rawOutBuf.theBuf[tty->rawOutBuf.Tail],1);      }      /* reenable interrupts */      rtems_interrupt_enable(level);    }  }  /* check for incoming XON/XOFF flow control switched off */  if (( tty->flow_ctrl & FL_MDXOF) &&      !(tty->termios.c_iflag & IXOFF)) {    /* clear related flags in flow_ctrl */    tty->flow_ctrl &= ~(FL_MDXOF);    /* FIXME: what happens, if we had sent XOFF but not yet XON? */    tty->flow_ctrl &= ~(FL_ISNTXOF);  }

⌨️ 快捷键说明

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