Exemple #1
0
/*
 * Send characters to device-specific code
 */
void
rtems_termios_puts (
  const void *_buf, size_t len, struct rtems_termios_tty *tty)
{
  const char *buf = _buf;
  unsigned int newHead;
  rtems_interrupt_lock_context lock_context;
  rtems_status_code sc;

  if (tty->handler.mode == TERMIOS_POLLED) {
    (*tty->handler.write)(tty, buf, len);
    return;
  }
  newHead = tty->rawOutBuf.Head;
  while (len) {
    /*
     * Performance improvement could be made here.
     * Copy multiple bytes to raw buffer:
     * if (len > 1) && (space to buffer end, or tail > 1)
     *  ncopy = MIN (len, space to buffer end or tail)
     *  memcpy (raw buffer, buf, ncopy)
     *  buf += ncopy
     *  len -= ncopy
     *
     * To minimize latency, the memcpy should be done
     * with interrupts enabled.
     */
    newHead = (newHead + 1) % tty->rawOutBuf.Size;
    rtems_termios_interrupt_lock_acquire (tty, &lock_context);
    while (newHead == tty->rawOutBuf.Tail) {
      tty->rawOutBufState = rob_wait;
      rtems_termios_interrupt_lock_release (tty, &lock_context);
      sc = rtems_semaphore_obtain(
        tty->rawOutBuf.Semaphore, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
      if (sc != RTEMS_SUCCESSFUL)
        rtems_fatal_error_occurred (sc);
      rtems_termios_interrupt_lock_acquire (tty, &lock_context);
    }
    tty->rawOutBuf.theBuf[tty->rawOutBuf.Head] = *buf++;
    tty->rawOutBuf.Head = newHead;
    if (tty->rawOutBufState == rob_idle) {
      /* check, whether XOFF has been received */
      if (!(tty->flow_ctrl & FL_ORCVXOF)) {
        (*tty->handler.write)(
          tty, &tty->rawOutBuf.theBuf[tty->rawOutBuf.Tail],1);
      } else {
        /* remember that output has been stopped due to flow ctrl*/
        tty->flow_ctrl |= FL_OSTOP;
      }
      tty->rawOutBufState = rob_busy;
    }
    rtems_termios_interrupt_lock_release (tty, &lock_context);
    len--;
  }
}
Exemple #2
0
static void
flushInput (struct rtems_termios_tty *tty)
{
  rtems_interrupt_lock_context lock_context;

  rtems_termios_interrupt_lock_acquire (tty, &lock_context);
  tty->rawInBuf.Tail = 0;
  tty->rawInBuf.Head = 0;
  rtems_termios_interrupt_lock_release (tty, &lock_context);
}
Exemple #3
0
static void
flushOutput (struct rtems_termios_tty *tty)
{
  rtems_interrupt_lock_context lock_context;

  rtems_termios_interrupt_lock_acquire (tty, &lock_context);
  tty->rawOutBuf.Tail = 0;
  tty->rawOutBuf.Head = 0;
  tty->rawOutBufState = rob_idle;
  rtems_termios_interrupt_lock_release (tty, &lock_context);
}
Exemple #4
0
/*
 * Drain output queue
 */
static void
drainOutput (struct rtems_termios_tty *tty)
{
  rtems_interrupt_lock_context lock_context;
  rtems_status_code sc;

  if (tty->handler.mode != TERMIOS_POLLED) {
    rtems_termios_interrupt_lock_acquire (tty, &lock_context);
    while (tty->rawOutBuf.Tail != tty->rawOutBuf.Head) {
      tty->rawOutBufState = rob_wait;
      rtems_termios_interrupt_lock_release (tty, &lock_context);
      sc = rtems_semaphore_obtain(
        tty->rawOutBuf.Semaphore, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
      if (sc != RTEMS_SUCCESSFUL)
        rtems_fatal_error_occurred (sc);
      rtems_termios_interrupt_lock_acquire (tty, &lock_context);
    }
    rtems_termios_interrupt_lock_release (tty, &lock_context);
  }
}
Exemple #5
0
static int leon3_console_last_close(int major, int minor, void *arg)
{
  struct rtems_termios_tty *tty = leon3_console_get_tty(arg);
  struct apbuart_priv *uart = leon3_console_get_uart(minor);
  rtems_interrupt_level level;

  /* Turn off RX interrupts */
  rtems_termios_interrupt_lock_acquire(tty, level);
  uart->regs->ctrl &= ~(LEON_REG_UART_CTRL_RI);
  rtems_termios_interrupt_lock_release(tty, level);

  /**** Flush device ****/
  while (uart->sending) {
    /* Wait until all data has been sent */
  }

  /* uninstall ISR */
  rtems_interrupt_handler_remove(uart->irq, leon3_console_isr, uart);

  return 0;
}
Exemple #6
0
static void
termios_set_flowctrl(struct rtems_termios_tty *tty)
{
  rtems_interrupt_lock_context lock_context;
  /*
   * 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_termios_interrupt_lock_acquire (tty, &lock_context);
      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->handler.write)(
          tty, &tty->rawOutBuf.theBuf[tty->rawOutBuf.Tail],1);
      }
      /* reenable interrupts */
      rtems_termios_interrupt_lock_release (tty, &lock_context);
    }
  }
  /* 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);
  }

  /* check for incoming RTS/CTS flow control switched off */
  if (( tty->flow_ctrl & FL_MDRTS) && !(tty->termios.c_cflag & CRTSCTS)) {
    /* clear related flags in flow_ctrl */
    tty->flow_ctrl &= ~(FL_MDRTS);

    /* restart remote Tx, if it was stopped */
    if ((tty->flow_ctrl & FL_IRTSOFF) &&
        (tty->handler.start_remote_tx != NULL)) {
      tty->handler.start_remote_tx(tty);
    }
    tty->flow_ctrl &= ~(FL_IRTSOFF);
  }

  /*
   * check for flow control options to be switched on
   */
  /* check for incoming RTS/CTS flow control switched on */
  if (tty->termios.c_cflag & CRTSCTS) {
    tty->flow_ctrl |= FL_MDRTS;
  }
  /* check for incoming XON/XOF flow control switched on */
  if (tty->termios.c_iflag & IXOFF) {
    tty->flow_ctrl |= FL_MDXOF;
  }
  /* check for outgoing XON/XOF flow control switched on */
  if (tty->termios.c_iflag & IXON) {
    tty->flow_ctrl |= FL_MDXON;
  }
}
Exemple #7
0
/*
 * in task-driven mode, this function is called in Tx task context
 * in interrupt-driven mode, this function is called in TxIRQ context
 */
static int
rtems_termios_refill_transmitter (struct rtems_termios_tty *tty)
{
  bool wakeUpWriterTask = false;
  unsigned int newTail;
  int nToSend;
  rtems_interrupt_lock_context lock_context;
  int len;

  rtems_termios_interrupt_lock_acquire (tty, &lock_context);

  /* 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->handler.write)(tty, (void *)&(tty->termios.c_cc[VSTOP]), 1);

    tty->t_dqlen--;
    tty->flow_ctrl |= FL_ISNTXOF;

    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->handler.write)(tty, (void *)&(tty->termios.c_cc[VSTART]), 1);

    tty->t_dqlen--;
    tty->flow_ctrl &= ~FL_ISNTXOF;

    nToSend = 1;
  } else if ( tty->rawOutBuf.Head == tty->rawOutBuf.Tail ) {
    /*
     * buffer was empty
     */
    if (tty->rawOutBufState == rob_wait) {
      /*
       * this should never happen...
       */
      wakeUpWriterTask = true;
    }

    (*tty->handler.write) (tty, NULL, 0);
    nToSend = 0;
  } else {
    len = tty->t_dqlen;
    tty->t_dqlen = 0;

    newTail = (tty->rawOutBuf.Tail + len) % tty->rawOutBuf.Size;
    tty->rawOutBuf.Tail = newTail;
    if (tty->rawOutBufState == rob_wait) {
      /*
       * wake up any pending writer task
       */
      wakeUpWriterTask = true;
    }

    if (newTail == tty->rawOutBuf.Head) {
      /*
       * Buffer has become empty
       */
      tty->rawOutBufState = rob_idle;
      (*tty->handler.write) (tty, NULL, 0);
      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 */
      tty->flow_ctrl |= FL_OSTOP;
      tty->rawOutBufState = rob_busy; /*apm*/
      (*tty->handler.write) (tty, NULL, 0);
      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->handler.write)(
        tty, &tty->rawOutBuf.theBuf[newTail], nToSend);
    }
    tty->rawOutBuf.Tail = newTail; /*apm*/
  }

  rtems_termios_interrupt_lock_release (tty, &lock_context);

  if (wakeUpWriterTask) {
    rtems_semaphore_release (tty->rawOutBuf.Semaphore);
  }

  return nToSend;
}
Exemple #8
0
/*
 * 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.
 */
int
rtems_termios_enqueue_raw_characters (void *ttyp, const char *buf, int len)
{
  struct rtems_termios_tty *tty = ttyp;
  unsigned int newTail;
  char c;
  int dropped = 0;
  bool flow_rcv = false; /* true, if flow control char received */
  rtems_interrupt_lock_context lock_context;

  if (rtems_termios_linesw[tty->t_line].l_rint != NULL) {
    while (len--) {
      c = *buf++;
      rtems_termios_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_termios_interrupt_lock_acquire (tty, &lock_context);
        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->handler.write)(
            tty, &tty->rawOutBuf.theBuf[tty->rawOutBuf.Tail], 1);
        }
        /* reenable interrupts */
        rtems_termios_interrupt_lock_release (tty, &lock_context);
      }
    } else {
      newTail = (tty->rawInBuf.Tail + 1) % tty->rawInBuf.Size;
      /* if chars_in_buffer > highwater                */
      rtems_termios_interrupt_lock_acquire (tty, &lock_context);
      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->handler.write)(tty,
                (void *)&(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->handler.stop_remote_tx != NULL) {
            tty->handler.stop_remote_tx(tty);
          }
        }
      }

      /* reenable interrupts */
      rtems_termios_interrupt_lock_release (tty, &lock_context);

      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;
}