📄 termios.c
字号:
} } 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 + -