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

📄 termios.c

📁 RTEMS (Real-Time Executive for Multiprocessor Systems) is a free open source real-time operating sys
💻 C
📖 第 1 页 / 共 3 页
字号:
					}				}				rtems_task_wake_after (1);			}			else {				siproc (n, tty);				if (tty->ccount >= tty->termios.c_cc[VMIN])					break;				if (tty->termios.c_cc[VMIN] && tty->termios.c_cc[VTIME])					rtems_clock_get (RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &then);			}		}	}	return RTEMS_SUCCESSFUL;}/* * Fill the input buffer from the raw input queue */static rtems_status_codefillBufferQueue (struct rtems_termios_tty *tty){	rtems_interval timeout = tty->rawInBufSemaphoreFirstTimeout;	rtems_status_code sc;        int               wait = (int)1;	while ( wait ) {		/*		 * Process characters read from raw queue		 */		while (tty->rawInBuf.Head != tty->rawInBuf.Tail) {			unsigned char c;			unsigned int newHead;			newHead = (tty->rawInBuf.Head + 1) % tty->rawInBuf.Size;			c = tty->rawInBuf.theBuf[newHead];			tty->rawInBuf.Head = newHead;			if(((tty->rawInBuf.Tail-newHead+tty->rawInBuf.Size)			    % tty->rawInBuf.Size)			   < tty->lowwater) {			  tty->flow_ctrl &= ~FL_IREQXOF;			  /* if tx stopped and XON should be sent... */			  if (((tty->flow_ctrl & (FL_MDXON | FL_ISNTXOF))			       ==                (FL_MDXON | FL_ISNTXOF))			      && ((tty->rawOutBufState == rob_idle)				  || (tty->flow_ctrl & FL_OSTOP))) {			    /* XON should be sent now... */			    (*tty->device.write)(tty->minor, 						 &(tty->termios.c_cc[VSTART]),						 1);			  }			  else if (tty->flow_ctrl & FL_MDRTS) {		    			    tty->flow_ctrl &= ~FL_IRTSOFF;					    /* activate RTS line */			    if (tty->device.startRemoteTx != NULL) {			      tty->device.startRemoteTx(tty->minor);			    }			  }			}			/* continue processing new character */			if (tty->termios.c_lflag & ICANON) {				if  (siproc (c, tty))					wait = 0;			}			else {				siproc (c, tty);				if (tty->ccount >= tty->termios.c_cc[VMIN])					wait = 0;			}			timeout = tty->rawInBufSemaphoreTimeout;		}		/*		 * Wait for characters		 */		if ( wait ) {			sc = rtems_semaphore_obtain (tty->rawInBuf.Semaphore,				tty->rawInBufSemaphoreOptions,				timeout);			if (sc != RTEMS_SUCCESSFUL)				break;		}	}	return RTEMS_SUCCESSFUL;}rtems_status_codertems_termios_read (void *arg){	rtems_libio_rw_args_t *args = arg;	struct rtems_termios_tty *tty = args->iop->data1;	unsigned32 count = args->count;	unsigned8 *buffer = args->buffer;	rtems_status_code sc;	sc = rtems_semaphore_obtain (tty->isem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);	if (sc != RTEMS_SUCCESSFUL)		return sc;	if (linesw[tty->t_line].l_read != NULL) {		sc = linesw[tty->t_line].l_read(tty,args);		tty->tty_rcvwakeup = 0;		rtems_semaphore_release (tty->isem);		return sc;	}	if (tty->cindex == tty->ccount) {		tty->cindex = tty->ccount = 0;		tty->read_start_column = tty->column;		if (tty->device.pollRead != NULL		    && tty->device.outputUsesInterrupts == TERMIOS_POLLED)			sc = fillBufferPoll (tty);		else			sc = fillBufferQueue (tty);		if (sc != RTEMS_SUCCESSFUL)			tty->cindex = tty->ccount = 0;	}	while (count && (tty->cindex < tty->ccount)) {		*buffer++ = tty->cbuf[tty->cindex++];		count--;	}	args->bytes_moved = args->count - count;	tty->tty_rcvwakeup = 0;	rtems_semaphore_release (tty->isem);	return sc;}/* * signal receive interrupt to rx daemon * NOTE: This routine runs in the context of the *       device receive interrupt handler. */void rtems_termios_rxirq_occured(struct rtems_termios_tty *tty){	/*	 * send event to rx daemon task	 */	rtems_event_send(tty->rxTaskId,TERMIOS_RX_PROC_EVENT);}/* * Place characters on raw queue. * NOTE: This routine runs in the context of the *       device receive interrupt handler. * Returns the number of characters dropped because of overflow. */intrtems_termios_enqueue_raw_characters (void *ttyp, char *buf, int len){	struct rtems_termios_tty *tty = ttyp;	unsigned int newTail;	char c;	int dropped = 0;	boolean flow_rcv = FALSE; /* TRUE, if flow control char received */	rtems_interrupt_level level;	if (linesw[tty->t_line].l_rint != NULL) {	  while (len--) {	    c = *buf++;	    linesw[tty->t_line].l_rint(c,tty);	  }	    	  /*	   * check to see if rcv wakeup callback was set	   */	  if (( !tty->tty_rcvwakeup ) && ( tty->tty_rcv.sw_pfn != NULL )) {	    (*tty->tty_rcv.sw_pfn)(&tty->termios, tty->tty_rcv.sw_arg);	    tty->tty_rcvwakeup = 1;    	  }	  return 0;	}	while (len--) {	  c = *buf++;	  /* FIXME: implement IXANY: any character restarts output */	  /* if incoming XON/XOFF controls outgoing stream: */	  if (tty->flow_ctrl & FL_MDXON) {	    	    /* if received char is V_STOP and V_START (both are equal value) */	    if (c == tty->termios.c_cc[VSTOP]) {	      if (c == tty->termios.c_cc[VSTART]) {		/* received VSTOP and VSTART==VSTOP? */		/* then toggle "stop output" status  */		tty->flow_ctrl = tty->flow_ctrl ^ FL_ORCVXOF;	      }	      else {		/* VSTOP received (other code than VSTART) */		/* stop output                             */		tty->flow_ctrl |= FL_ORCVXOF;	      }	      flow_rcv = TRUE;	    }	    else if (c == tty->termios.c_cc[VSTART]) {	      /* VSTART received */	      /* restart output  */	      tty->flow_ctrl &= ~FL_ORCVXOF;	      flow_rcv = TRUE;	    }	  }	  if (flow_rcv) {	    /* restart output according to FL_ORCVXOF flag */	    if ((tty->flow_ctrl & (FL_ORCVXOF | FL_OSTOP)) == 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);	    }	  }		  else {		newTail = (tty->rawInBuf.Tail + 1) % tty->rawInBuf.Size;		/* if chars_in_buffer > highwater                */		rtems_interrupt_disable(level);		if ((((newTail - tty->rawInBuf.Head + tty->rawInBuf.Size)		      % tty->rawInBuf.Size)		     > tty->highwater) && 		    !(tty->flow_ctrl & FL_IREQXOF)) {		  /* incoming data stream should be stopped */		  tty->flow_ctrl |= FL_IREQXOF; 		  if ((tty->flow_ctrl & (FL_MDXOF | FL_ISNTXOF)) 		      ==                (FL_MDXOF             ) ){		    if ((tty->flow_ctrl & FL_OSTOP) || 			(tty->rawOutBufState == rob_idle)) {		      /* if tx is stopped due to XOFF or out of data */		      /*    call write function here                 */		      tty->flow_ctrl |= FL_ISNTXOF;		      (*tty->device.write)(tty->minor,					   &(tty->termios.c_cc[VSTOP]),					   1);		    }		  }		  else if ((tty->flow_ctrl & (FL_MDRTS | FL_IRTSOFF)) 			   ==                (FL_MDRTS             ) ) {		    tty->flow_ctrl |= FL_IRTSOFF;				    /* deactivate RTS line */		    if (tty->device.stopRemoteTx != NULL) {		      tty->device.stopRemoteTx(tty->minor);		    }		  }		}		/* reenable interrupts */		rtems_interrupt_enable(level);		if (newTail == tty->rawInBuf.Head) {		        dropped++;		}		else {		        tty->rawInBuf.theBuf[newTail] = c;		        tty->rawInBuf.Tail = newTail;	    			/*			 * check to see if rcv wakeup callback was set			 */			if (( !tty->tty_rcvwakeup ) && ( tty->tty_rcv.sw_pfn != NULL )) {			  (*tty->tty_rcv.sw_pfn)(&tty->termios, tty->tty_rcv.sw_arg);			  tty->tty_rcvwakeup = 1;			}		}			  }	}	tty->rawInBufDropped += dropped;	rtems_semaphore_release (tty->rawInBuf.Semaphore);	return dropped;}/* * in task-driven mode, this function is called in Tx task context * in interrupt-driven mode, this function is called in TxIRQ context */intrtems_termios_refill_transmitter (struct rtems_termios_tty *tty){	unsigned int newTail;	int nToSend;	rtems_interrupt_level level;	int len;	/* check for XOF/XON to send */	if ((tty->flow_ctrl & (FL_MDXOF | FL_IREQXOF | FL_ISNTXOF))	    == (FL_MDXOF | FL_IREQXOF)) {	  /* XOFF should be sent now... */	  (*tty->device.write)(tty->minor, 			       &(tty->termios.c_cc[VSTOP]), 1);	  rtems_interrupt_disable(level);	  tty->t_dqlen--;	  tty->flow_ctrl |= FL_ISNTXOF;	  rtems_interrupt_enable(level);	  nToSend = 1;	}	else if ((tty->flow_ctrl & (FL_IREQXOF | FL_ISNTXOF))		 == FL_ISNTXOF) {	  /* NOTE: send XON even, if no longer in XON/XOFF mode... */	  /* XON should be sent now... */		/*		 * FIXME: this .write call will generate another 		 * dequeue callback. This will advance the "Tail" in the data		 * buffer, although the corresponding data is not yet out!		 * Therefore the dequeue "length" should be reduced by 1		 */	  (*tty->device.write)(tty->minor, 			       &(tty->termios.c_cc[VSTART]), 1);	  rtems_interrupt_disable(level);	  tty->t_dqlen--;	  tty->flow_ctrl &= ~FL_ISNTXOF;	  rtems_interrupt_enable(level);	  nToSend = 1;	}	else {	  if ( tty->rawOutBuf.Head == tty->rawOutBuf.Tail ) {	    /*	     * buffer was empty	     */	    if (tty->rawOutBufState == rob_wait) {	      /* 	       * this should never happen... 	       */	      rtems_semaphore_release (tty->rawOutBuf.Semaphore);	    }	    return 0;		  }	  rtems_interrupt_disable(level);	  len = tty->t_dqlen;	  tty->t_dqlen = 0;	  rtems_interrupt_enable(level);	  newTail = (tty->rawOutBuf.Tail + len) % tty->rawOutBuf.Size;	  tty->rawOutBuf.Tail = newTail;	  if (tty->rawOutBufState == rob_wait) {	    /* 	     * wake up any pending writer task	     */	    rtems_semaphore_release (tty->rawOutBuf.Semaphore);	  }	  if (newTail == tty->rawOutBuf.Head) {	    /*	     * Buffer has become empty	     */	    tty->rawOutBufState = rob_idle;	    nToSend = 0;	    	    /*	     * check to see if snd wakeup callback was set	     */	    if ( tty->tty_snd.sw_pfn != NULL) {	      (*tty->tty_snd.sw_pfn)(&tty->termios, tty->tty_snd.sw_arg);	    }	  }	  /* check, whether output should stop due to received XOFF */	  else if ((tty->flow_ctrl & (FL_MDXON | FL_ORCVXOF)) 		   ==                (FL_MDXON | FL_ORCVXOF)) {		  /* Buffer not empty, but output stops due to XOFF */		  /* set flag, that output has been stopped */		  rtems_interrupt_disable(level);		  tty->flow_ctrl |= FL_OSTOP;		  tty->rawOutBufState = rob_busy; /*apm*/		  rtems_interrupt_enable(level);		  nToSend = 0;	  }	  else {	    /*	     * Buffer not empty, start tranmitter	     */	    if (newTail > tty->rawOutBuf.Head)		    nToSend = tty->rawOutBuf.Size - newTail;	    else		    nToSend = tty->rawOutBuf.Head - newTail;	    /* when flow control XON or XOF, don't send blocks of data     */	    /* to allow fast reaction on incoming flow ctrl and low latency*/	    /* for outgoing flow control                                   */	    if (tty->flow_ctrl & (FL_MDXON | FL_MDXOF)) {		    nToSend = 1;	    }	    tty->rawOutBufState = rob_busy; /*apm*/	    (*tty->device.write)(tty->minor, 				 (char *)&tty->rawOutBuf.theBuf[newTail], 				 nToSend);	  }	  tty->rawOutBuf.Tail = newTail; /*apm*/	}	return nToSend;}/* * Characters have been transmitted * NOTE: This routine runs in the context of the *       device transmit interrupt handler. * The second argument is the number of characters transmitted so far. * This value will always be 1 for devices which generate an interrupt * for each transmitted character.  * It returns number of characters left to transmit */intrtems_termios_dequeue_characters (void *ttyp, int len){	struct rtems_termios_tty *tty = ttyp;	rtems_status_code sc;	/*	 * sum up character count already sent	 */	tty->t_dqlen += len;	if (tty->device.outputUsesInterrupts == TERMIOS_TASK_DRIVEN) {		/*		 * send wake up to transmitter task		 */		sc = rtems_event_send(tty->txTaskId,				      TERMIOS_TX_START_EVENT);		if (sc != RTEMS_SUCCESSFUL)			rtems_fatal_error_occurred (sc);		return 0; /* nothing to output in IRQ... */	}	else if (tty->t_line == PPPDISC ) {		/*		 * call any line discipline start function		 */		if (linesw[tty->t_line].l_start != NULL) {			linesw[tty->t_line].l_start(tty);		}		return 0; /* nothing to output in IRQ... */	}	else {		return rtems_termios_refill_transmitter(tty);	}}/* * this task actually processes any transmit events */static rtems_task rtems_termios_txdaemon(rtems_task_argument argument){	struct rtems_termios_tty *tty = (struct rtems_termios_tty *)argument;	rtems_event_set the_event;	while (1) {		/*		 * wait for rtems event		 */		rtems_event_receive((TERMIOS_TX_START_EVENT | 				     TERMIOS_TX_TERMINATE_EVENT),				    RTEMS_EVENT_ANY | RTEMS_WAIT,				    RTEMS_NO_TIMEOUT,				    &the_event);		if ((the_event & TERMIOS_TX_TERMINATE_EVENT) != 0) {			tty->txTaskId = 0;			rtems_task_delete(RTEMS_SELF);		}		else {			/*			 * call any line discipline start function			 */			if (linesw[tty->t_line].l_start != NULL) {				linesw[tty->t_line].l_start(tty);			}			/*			 * try to push further characters to device			 */			rtems_termios_refill_transmitter(tty);		}	}}/* * this task actually processes any receive events */static rtems_task rtems_termios_rxdaemon(rtems_task_argument argument){	struct rtems_termios_tty *tty = (struct rtems_termios_tty *)argument;	rtems_event_set the_event;	int c;	char c_buf;	while (1) {		/*		 * wait for rtems event		 */		rtems_event_receive((TERMIOS_RX_PROC_EVENT | 				     TERMIOS_RX_TERMINATE_EVENT),				    RTEMS_EVENT_ANY | RTEMS_WAIT,				    RTEMS_NO_TIMEOUT,				    &the_event);		if ((the_event & TERMIOS_RX_TERMINATE_EVENT) != 0) {			tty->rxTaskId = 0;			rtems_task_delete(RTEMS_SELF);		}		else {			/*			 * do something			 */			c = tty->device.pollRead(tty->minor);			if (c != EOF) {				/*				 * pollRead did call enqueue on its own				 */				c_buf = c;				rtems_termios_enqueue_raw_characters (				      tty,&c_buf,1);			}		}	}}

⌨️ 快捷键说明

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