summaryrefslogtreecommitdiffstats
path: root/bsps/m68k
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2018-04-19 06:28:01 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2018-04-20 13:08:32 +0200
commitd7d66d7d4523b904c8ccc6aea3709dc0d5aa5bdc (patch)
treecaa54b4229e86a68c84ab5961af34e087dce5302 /bsps/m68k
parentbsps/powerpc: Move shared btimer support (diff)
downloadrtems-d7d66d7d4523b904c8ccc6aea3709dc0d5aa5bdc.tar.bz2
bsps: Move console drivers to bsps
This patch is a part of the BSP source reorganization. Update #3285.
Diffstat (limited to 'bsps/m68k')
-rw-r--r--bsps/m68k/av5282/console/console.c711
-rw-r--r--bsps/m68k/csb360/console/console-io.c97
-rw-r--r--bsps/m68k/gen68340/console/console.c690
-rw-r--r--bsps/m68k/gen68340/console/m340uart.c311
-rw-r--r--bsps/m68k/gen68360/console/console.c390
-rw-r--r--bsps/m68k/genmcf548x/console/console.c843
-rw-r--r--bsps/m68k/mcf5206elite/console/console.c431
-rw-r--r--bsps/m68k/mcf52235/console/console.c656
-rw-r--r--bsps/m68k/mcf52235/console/debugio.c32
-rw-r--r--bsps/m68k/mcf5225x/console/console.c689
-rw-r--r--bsps/m68k/mcf5225x/console/debugio.c35
-rw-r--r--bsps/m68k/mcf5235/console/console.c745
-rw-r--r--bsps/m68k/mcf5329/console/console.c668
-rw-r--r--bsps/m68k/mrm332/console/console.c155
-rw-r--r--bsps/m68k/mrm332/console/sci.c1586
-rw-r--r--bsps/m68k/mrm332/console/sci.h233
-rw-r--r--bsps/m68k/mvme147/console/console.c203
-rw-r--r--bsps/m68k/mvme162/console/console.c277
-rw-r--r--bsps/m68k/mvme167/console/console-recording.h572
-rw-r--r--bsps/m68k/mvme167/console/console.c1676
-rw-r--r--bsps/m68k/uC5282/console/console.c774
21 files changed, 11774 insertions, 0 deletions
diff --git a/bsps/m68k/av5282/console/console.c b/bsps/m68k/av5282/console/console.c
new file mode 100644
index 0000000000..dd557660f8
--- /dev/null
+++ b/bsps/m68k/av5282/console/console.c
@@ -0,0 +1,711 @@
+/*
+ * Multi UART console serial I/O.
+ *
+ * TO DO: Add DMA input/output
+ */
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <bsp.h>
+#include <malloc.h>
+
+#include <rtems/bspIo.h>
+#include <rtems/console.h>
+#include <rtems/libio.h>
+#include <rtems/termiostypes.h>
+
+#define UART_INTC0_IRQ_VECTOR(x) (64+13+(x))
+
+#define MCF5282_UART_USR_ERROR ( MCF5282_UART_USR_RB | \
+ MCF5282_UART_USR_FE | \
+ MCF5282_UART_USR_PE | \
+ MCF5282_UART_USR_OE )
+
+static ssize_t IntUartPollWrite(int minor, const char *buf, size_t len);
+static ssize_t IntUartInterruptWrite (int minor, const char *buf, size_t len);
+
+static void _BSP_null_char( char c )
+{
+ rtems_interrupt_level level;
+
+ rtems_interrupt_disable(level);
+ while ( (MCF5282_UART_USR(CONSOLE_PORT) & MCF5282_UART_USR_TXRDY) == 0 )
+ continue;
+
+ MCF5282_UART_UTB(CONSOLE_PORT) = c;
+ while ( (MCF5282_UART_USR(CONSOLE_PORT) & MCF5282_UART_USR_TXRDY) == 0 )
+ continue;
+
+ rtems_interrupt_enable(level);
+}
+BSP_output_char_function_type BSP_output_char = _BSP_null_char;
+BSP_polling_getchar_function_type BSP_poll_char = NULL;
+
+#define MAX_UART_INFO 3
+#define RX_BUFFER_SIZE 512
+
+struct IntUartInfoStruct
+{
+ int iomode;
+ volatile int uimr;
+ int baud;
+ int databits;
+ int parity;
+ int stopbits;
+ int hwflow;
+ int rx_in;
+ int rx_out;
+ char rx_buffer[RX_BUFFER_SIZE];
+ void *ttyp;
+};
+
+struct IntUartInfoStruct IntUartInfo[MAX_UART_INFO];
+
+/*
+ * Function : IntUartSet
+ *
+ * Description : This updates the hardware UART settings.
+ */
+static void IntUartSet(
+ int minor,
+ int baud,
+ int databits,
+ int parity,
+ int stopbits,
+ int hwflow
+)
+{
+ int divisor;
+ uint32_t clock_speed;
+ uint8_t umr1 = 0;
+ uint8_t umr2 = 0;
+ struct IntUartInfoStruct *info = &IntUartInfo[minor];
+ rtems_interrupt_level level;
+
+ rtems_interrupt_disable(level);
+
+ /* disable interrupts, clear RTS line, and disable the UARTS */
+ MCF5282_UART_UIMR(minor) = 0;
+ MCF5282_UART_UOP0(minor) = 1;
+ MCF5282_UART_UCR(minor) =
+ (MCF5282_UART_UCR_TX_DISABLED | MCF5282_UART_UCR_RX_DISABLED);
+
+ /* save the current values */
+ info->uimr = 0;
+ info->baud = baud;
+ info->databits = databits;
+ info->parity = parity;
+ info->stopbits = stopbits;
+ info->hwflow = hwflow;
+
+ clock_speed = get_CPU_clock_speed();
+ /* determine the baud divisor value */
+ divisor = (clock_speed / ( 32 * baud ));
+ if ( divisor < 2 )
+ divisor = 2;
+
+ /* check to see if doing hardware flow control */
+ if ( hwflow ) {
+ /* set hardware flow options */
+ umr1 |= MCF5282_UART_UMR1_RXRTS;
+ umr2 |= MCF5282_UART_UMR2_TXCTS;
+ }
+
+ /* determine the new umr values */
+ umr1 |= (parity | databits);
+ umr2 |= (stopbits);
+
+ /* reset the uart */
+ MCF5282_UART_UCR(minor) = MCF5282_UART_UCR_RESET_ERROR;
+ MCF5282_UART_UCR(minor) = MCF5282_UART_UCR_RESET_RX;
+ MCF5282_UART_UCR(minor) = MCF5282_UART_UCR_RESET_TX;
+
+ /* reset the uart mode register and update values */
+ MCF5282_UART_UCR(minor) = MCF5282_UART_UCR_RESET_MR;
+ MCF5282_UART_UMR(minor) = umr1;
+ MCF5282_UART_UMR(minor) = umr2;
+
+ /* set the baud rate values */
+ MCF5282_UART_UCSR(minor) =
+ (MCF5282_UART_UCSR_RCS_SYS_CLK | MCF5282_UART_UCSR_TCS_SYS_CLK);
+ MCF5282_UART_UBG1(minor) = (divisor & 0xff00) >> 8;
+ MCF5282_UART_UBG2(minor) = (divisor & 0x00ff);
+
+ /* enable the uart */
+ MCF5282_UART_UCR(minor) =
+ (MCF5282_UART_UCR_TX_ENABLED | MCF5282_UART_UCR_RX_ENABLED);
+
+ /* check to see if interrupts need to be enabled */
+ if ( info->iomode != TERMIOS_POLLED ) {
+ /* enable rx interrupts */
+ info->uimr |= MCF5282_UART_UIMR_FFULL;
+ MCF5282_UART_UIMR(minor) = info->uimr;
+ }
+
+ /* check to see if doing hardware flow control */
+ if ( hwflow ) {
+ /* assert the RTS line */
+ MCF5282_UART_UOP1(minor) = 1;
+ }
+
+ rtems_interrupt_enable(level);
+}
+
+/*
+ * Function : IntUartSetAttributes
+ *
+ * Description : This provides the hardware-dependent portion of tcsetattr().
+ * value and sets it. At the moment this just sets the baud rate.
+ *
+ * Note: The highest baudrate is 115200 as this stays within
+ * an error of +/- 5% at 25MHz processor clock
+ */
+static int IntUartSetAttributes(
+ int minor,
+ const struct termios *t
+)
+{
+ /* set default index values */
+ int baud = (int)19200;
+ int databits = (int)MCF5282_UART_UMR1_BC_8;
+ int parity = (int)MCF5282_UART_UMR1_PM_NONE;
+ int stopbits = (int)MCF5282_UART_UMR2_STOP_BITS_1;
+ int hwflow = (int)0;
+ struct IntUartInfoStruct *info = &IntUartInfo[minor];
+
+ /* check to see if input is valid */
+ if ( t != (const struct termios *)0 ) {
+ /* determine baud rate index */
+ baud = rtems_termios_baud_to_number(t->c_ospeed);
+
+ /* determine data bits */
+ switch ( t->c_cflag & CSIZE ) {
+ case CS5:
+ databits = (int)MCF5282_UART_UMR1_BC_5;
+ break;
+ case CS6:
+ databits = (int)MCF5282_UART_UMR1_BC_6;
+ break;
+ case CS7:
+ databits = (int)MCF5282_UART_UMR1_BC_7;
+ break;
+ case CS8:
+ databits = (int)MCF5282_UART_UMR1_BC_8;
+ break;
+ }
+
+ /* determine if parity is enabled */
+ if ( t->c_cflag & PARENB ) {
+ if ( t->c_cflag & PARODD ) {
+ /* odd parity */
+ parity = (int)MCF5282_UART_UMR1_PM_ODD;
+ } else {
+ /* even parity */
+ parity = (int)MCF5282_UART_UMR1_PM_EVEN;
+ }
+ }
+
+ /* determine stop bits */
+ if ( t->c_cflag & CSTOPB ) {
+ /* two stop bits */
+ stopbits = (int)MCF5282_UART_UMR2_STOP_BITS_2;
+ }
+
+ /* check to see if hardware flow control */
+ if ( t->c_cflag & CRTSCTS ) {
+ hwflow = 1;
+ }
+ }
+
+ /* check to see if values have changed */
+ if ( ( baud != info->baud ) ||
+ ( databits != info->databits ) ||
+ ( parity != info->parity ) ||
+ ( stopbits != info->stopbits ) ||
+ ( hwflow != info->hwflow ) ) {
+
+ /* call function to set values */
+ IntUartSet(minor, baud, databits, parity, stopbits, hwflow);
+ }
+
+ return RTEMS_SUCCESSFUL;
+}
+
+/*
+ * Function : IntUartInterruptHandler
+ *
+ * Description : This is the interrupt handler for the internal uart. It
+ * determines which channel caused the interrupt before queueing any received
+ * chars and dequeueing chars waiting for transmission.
+ */
+static rtems_isr IntUartInterruptHandler(rtems_vector_number v)
+{
+ unsigned int chan = v - UART_INTC0_IRQ_VECTOR(0);
+ struct IntUartInfoStruct *info = &IntUartInfo[chan];
+
+ /* check to see if received data */
+ if ( MCF5282_UART_UISR(chan) & MCF5282_UART_UISR_RXRDY ) {
+ /* read data and put into the receive buffer */
+ while ( MCF5282_UART_USR(chan) & MCF5282_UART_USR_RXRDY ) {
+
+ if ( MCF5282_UART_USR(chan) & MCF5282_UART_USR_ERROR ) {
+ /* clear the error */
+ MCF5282_UART_UCR(chan) = MCF5282_UART_UCR_RESET_ERROR;
+ }
+ /* put data in rx buffer and check for errors */
+ info->rx_buffer[info->rx_in] = MCF5282_UART_URB(chan);
+
+ /* update buffer values */
+ info->rx_in++;
+
+ if ( info->rx_in >= RX_BUFFER_SIZE ) {
+ info->rx_in = 0;
+ }
+ }
+
+ /* Make sure the port has been opened */
+ if ( info->ttyp ) {
+
+ /* check to see if task driven */
+ if ( info->iomode == TERMIOS_TASK_DRIVEN ) {
+ /* notify rx task that rx buffer has data */
+ rtems_termios_rxirq_occured(info->ttyp);
+ } else {
+ /* Push up the received data */
+ rtems_termios_enqueue_raw_characters(
+ info->ttyp, info->rx_buffer, info->rx_in);
+ info->rx_in = 0;
+ }
+ }
+ }
+
+ /* check to see if data needs to be transmitted */
+ if ( ( info->uimr & MCF5282_UART_UIMR_TXRDY ) &&
+ ( MCF5282_UART_UISR(chan) & MCF5282_UART_UISR_TXRDY ) )
+ {
+
+ /* disable tx interrupts */
+ info->uimr &= ~MCF5282_UART_UIMR_TXRDY;
+ MCF5282_UART_UIMR(chan) = info->uimr;
+
+ /* tell upper level that character has been sent */
+ if ( info->ttyp )
+ rtems_termios_dequeue_characters(info->ttyp, 1);
+ }
+}
+
+/*
+ * Function : IntUartInitialize
+ *
+ * Description : This initialises the internal uart hardware for all
+ * internal uarts. If the internal uart is to be interrupt driven then the
+ * interrupt vectors are hooked.
+ */
+static void IntUartInitialize(void)
+{
+ unsigned int chan;
+ struct IntUartInfoStruct *info;
+ rtems_isr_entry old_handler;
+ rtems_interrupt_level level;
+
+ for ( chan = 0; chan < MAX_UART_INFO; chan++ ) {
+ info = &IntUartInfo[chan];
+
+ info->ttyp = NULL;
+ info->rx_in = 0;
+ info->rx_out = 0;
+ info->baud = -1;
+ info->databits = -1;
+ info->parity = -1;
+ info->stopbits = -1;
+ info->hwflow = -1;
+ info->iomode = TERMIOS_POLLED;
+
+ MCF5282_UART_UACR(chan) = 0;
+ MCF5282_UART_UIMR(chan) = 0;
+ if ( info->iomode != TERMIOS_POLLED ) {
+ rtems_interrupt_catch (IntUartInterruptHandler,
+ UART_INTC0_IRQ_VECTOR(chan),
+ &old_handler);
+ }
+
+ /* set uart default values */
+ IntUartSetAttributes(chan, NULL);
+
+ /* unmask interrupt */
+ rtems_interrupt_disable(level);
+ switch(chan) {
+ case 0:
+ MCF5282_INTC0_ICR13 = MCF5282_INTC_ICR_IL(UART0_IRQ_LEVEL) |
+ MCF5282_INTC_ICR_IP(UART0_IRQ_PRIORITY);
+ MCF5282_INTC0_IMRL &= ~(MCF5282_INTC_IMRL_INT13 |
+ MCF5282_INTC_IMRL_MASKALL);
+ break;
+
+ case 1:
+ MCF5282_INTC0_ICR14 = MCF5282_INTC_ICR_IL(UART1_IRQ_LEVEL) |
+ MCF5282_INTC_ICR_IP(UART1_IRQ_PRIORITY);
+ MCF5282_INTC0_IMRL &= ~(MCF5282_INTC_IMRL_INT14 |
+ MCF5282_INTC_IMRL_MASKALL);
+ break;
+
+ case 2:
+ MCF5282_INTC0_ICR15 = MCF5282_INTC_ICR_IL(UART2_IRQ_LEVEL) |
+ MCF5282_INTC_ICR_IP(UART2_IRQ_PRIORITY);
+ MCF5282_INTC0_IMRL &= ~(MCF5282_INTC_IMRL_INT15 |
+ MCF5282_INTC_IMRL_MASKALL);
+ break;
+ }
+ rtems_interrupt_enable(level);
+
+ } /* of chan loop */
+
+
+} /* IntUartInitialise */
+
+
+/*
+ * Function : IntUartInterruptWrite
+ *
+ * Description : This writes a single character to the appropriate uart
+ * channel. This is either called during an interrupt or in the user's task
+ * to initiate a transmit sequence. Calling this routine enables Tx
+ * interrupts.
+ */
+static ssize_t IntUartInterruptWrite(
+ int minor,
+ const char *buf,
+ size_t len
+)
+{
+ if (len > 0) {
+ /* write out character */
+ MCF5282_UART_UTB(minor) = *buf;
+
+ /* enable tx interrupt */
+ IntUartInfo[minor].uimr |= MCF5282_UART_UIMR_TXRDY;
+ MCF5282_UART_UIMR(minor) = IntUartInfo[minor].uimr;
+ }
+
+ return 0;
+}
+
+/*
+ * Function : IntUartInterruptOpen
+ *
+ * Description : This enables interrupts when the tty is opened.
+ */
+static int IntUartInterruptOpen(
+ int major,
+ int minor,
+ void *arg
+)
+{
+ struct IntUartInfoStruct *info = &IntUartInfo[minor];
+
+ /* enable the uart */
+ MCF5282_UART_UCR(minor) = (MCF5282_UART_UCR_TX_ENABLED |
+ MCF5282_UART_UCR_RX_ENABLED);
+
+ /* check to see if interrupts need to be enabled */
+ if ( info->iomode != TERMIOS_POLLED ) {
+ /* enable rx interrupts */
+ info->uimr |= MCF5282_UART_UIMR_FFULL;
+ MCF5282_UART_UIMR(minor) = info->uimr;
+ }
+
+ /* check to see if doing hardware flow control */
+ if ( info->hwflow ) {
+ /* assert the RTS line */
+ MCF5282_UART_UOP1(minor) = 1;
+ }
+
+ return 0;
+}
+
+/*
+ * Function : IntUartInterruptClose
+ *
+ * Description : This disables interrupts when the tty is closed.
+ */
+static int IntUartInterruptClose(
+ int major,
+ int minor,
+ void *arg
+)
+{
+ struct IntUartInfoStruct *info = &IntUartInfo[minor];
+
+ /* disable the interrupts and the uart */
+ MCF5282_UART_UIMR(minor) = 0;
+ MCF5282_UART_UCR(minor) =
+ (MCF5282_UART_UCR_TX_DISABLED | MCF5282_UART_UCR_RX_DISABLED);
+
+ /* reset values */
+ info->ttyp = NULL;
+ info->uimr = 0;
+ info->rx_in = 0;
+ info->rx_out = 0;
+
+ return 0;
+}
+
+/*
+ * Function : IntUartTaskRead
+ *
+ * Description : This reads all available characters from the internal uart
+ * and places them into the termios buffer. The rx interrupts will be
+ * re-enabled after all data has been read.
+ */
+static int IntUartTaskRead(int minor)
+{
+ char buffer[RX_BUFFER_SIZE];
+ int count;
+ int rx_in;
+ int index = 0;
+ struct IntUartInfoStruct *info = &IntUartInfo[minor];
+
+ /* determine number of values to copy out */
+ rx_in = info->rx_in;
+ if ( info->rx_out <= rx_in ) {
+ count = rx_in - info->rx_out;
+ } else {
+ count = (RX_BUFFER_SIZE - info->rx_out) + rx_in;
+ }
+
+ /* copy data into local buffer from rx buffer */
+ while ( ( index < count ) && ( index < RX_BUFFER_SIZE ) ) {
+ /* copy data byte */
+ buffer[index] = info->rx_buffer[info->rx_out];
+ index++;
+
+ /* increment rx buffer values */
+ info->rx_out++;
+ if ( info->rx_out >= RX_BUFFER_SIZE ) {
+ info->rx_out = 0;
+ }
+ }
+
+ /* check to see if buffer is not empty */
+ if ( count > 0 ) {
+ /* set characters into termios buffer */
+ rtems_termios_enqueue_raw_characters(info->ttyp, buffer, count);
+ }
+
+ return EOF;
+}
+
+
+
+/*
+ * Function : IntUartPollRead
+ *
+ * Description : This reads a character from the internal uart. It returns
+ * to the caller without blocking if not character is waiting.
+ */
+static int IntUartPollRead(int minor)
+{
+ if ( (MCF5282_UART_USR(minor) & MCF5282_UART_USR_RXRDY) == 0 )
+ return-1;
+
+ return MCF5282_UART_URB(minor);
+}
+
+
+/*
+ * Function : IntUartPollWrite
+ *
+ * Description : This writes out each character in the buffer to the
+ * appropriate internal uart channel waiting till each one is sucessfully
+ * transmitted.
+ */
+static ssize_t IntUartPollWrite(
+ int minor,
+ const char *buf,
+ size_t len
+)
+{
+ size_t retval = len;
+ /* loop over buffer */
+
+ while ( len-- ) {
+ /* block until we can transmit */
+ while ( (MCF5282_UART_USR(minor) & MCF5282_UART_USR_TXRDY) == 0 )
+ continue;
+ /* transmit data byte */
+ MCF5282_UART_UTB(minor) = *buf++;
+ }
+ return retval;
+}
+
+/*
+ * Function : console_initialize
+ *
+ * Description : This initialises termios, both sets of uart hardware before
+ * registering /dev/tty devices for each channel and the system /dev/console.
+ */
+rtems_device_driver console_initialize(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg
+)
+{
+ rtems_status_code status;
+
+ /* Set up TERMIOS */
+ rtems_termios_initialize ();
+
+ /* set io modes for the different channels and initialize device */
+ IntUartInfo[minor].iomode = TERMIOS_IRQ_DRIVEN;
+ IntUartInitialize();
+
+ /* Register the console port */
+ status = rtems_io_register_name ("/dev/console", major, CONSOLE_PORT);
+ if ( status != RTEMS_SUCCESSFUL ) {
+ rtems_fatal_error_occurred (status);
+ }
+
+ /* Register the other port */
+ if ( CONSOLE_PORT != 0 ) {
+ status = rtems_io_register_name ("/dev/tty00", major, 0);
+ if ( status != RTEMS_SUCCESSFUL ) {
+ rtems_fatal_error_occurred (status);
+ }
+ }
+ if ( CONSOLE_PORT != 1 ) {
+ status = rtems_io_register_name ("/dev/tty01", major, 1);
+ if ( status != RTEMS_SUCCESSFUL ) {
+ rtems_fatal_error_occurred (status);
+ }
+ }
+
+ return RTEMS_SUCCESSFUL;
+}
+
+/*
+ * Function : console_open
+ *
+ * Description : This actually opens the device depending on the minor
+ * number set during initialisation. The device specific access routines are
+ * passed to termios when the devices is opened depending on whether it is
+ * polled or not.
+ */
+rtems_device_driver console_open(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+ rtems_status_code status = RTEMS_INVALID_NUMBER;
+ rtems_libio_open_close_args_t *args = (rtems_libio_open_close_args_t *)arg;
+ struct IntUartInfoStruct *info;
+
+ static const rtems_termios_callbacks IntUartPollCallbacks = {
+ NULL, /* firstOpen */
+ NULL, /* lastClose */
+ IntUartPollRead, /* pollRead */
+ IntUartPollWrite, /* write */
+ IntUartSetAttributes, /* setAttributes */
+ NULL, /* stopRemoteTx */
+ NULL, /* startRemoteTx */
+ TERMIOS_POLLED /* mode */
+ };
+ static const rtems_termios_callbacks IntUartIntrCallbacks = {
+ IntUartInterruptOpen, /* firstOpen */
+ IntUartInterruptClose, /* lastClose */
+ NULL, /* pollRead */
+ IntUartInterruptWrite, /* write */
+ IntUartSetAttributes, /* setAttributes */
+ NULL, /* stopRemoteTx */
+ NULL, /* startRemoteTx */
+ TERMIOS_IRQ_DRIVEN /* mode */
+ };
+
+ static const rtems_termios_callbacks IntUartTaskCallbacks = {
+ IntUartInterruptOpen, /* firstOpen */
+ IntUartInterruptClose, /* lastClose */
+ IntUartTaskRead, /* pollRead */
+ IntUartInterruptWrite, /* write */
+ IntUartSetAttributes, /* setAttributes */
+ NULL, /* stopRemoteTx */
+ NULL, /* startRemoteTx */
+ TERMIOS_TASK_DRIVEN /* mode */
+ };
+
+ /* open the port depending on the minor device number */
+ if ( ( minor >= 0 ) && ( minor < MAX_UART_INFO ) ) {
+ info = &IntUartInfo[minor];
+ switch ( info->iomode ) {
+ case TERMIOS_POLLED:
+ status = rtems_termios_open(major, minor, arg, &IntUartPollCallbacks);
+ break;
+ case TERMIOS_IRQ_DRIVEN:
+ status = rtems_termios_open(major, minor, arg, &IntUartIntrCallbacks);
+ info->ttyp = args->iop->data1;
+ break;
+ case TERMIOS_TASK_DRIVEN:
+ status = rtems_termios_open(major, minor, arg, &IntUartTaskCallbacks);
+ info->ttyp = args->iop->data1;
+ break;
+ }
+ }
+
+ return status;
+}
+
+/*
+ * Function : console_close
+ *
+ * Description : This closes the device via termios
+ */
+rtems_device_driver console_close(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+ return rtems_termios_close(arg);
+}
+
+/*
+ * Function : console_read
+ *
+ * Description : Read from the device via termios
+ */
+rtems_device_driver console_read(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg
+)
+{
+ return rtems_termios_read(arg);
+}
+
+/*
+ * Function : console_write
+ *
+ * Description : Write to the device via termios
+ */
+rtems_device_driver console_write(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg
+)
+{
+ return rtems_termios_write(arg);
+}
+
+/*
+ * Function : console_ioctl
+ *
+ * Description : Pass the IOCtl call to termios
+ */
+rtems_device_driver console_control(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg
+)
+{
+ return rtems_termios_ioctl(arg);
+}
diff --git a/bsps/m68k/csb360/console/console-io.c b/bsps/m68k/csb360/console/console-io.c
new file mode 100644
index 0000000000..9b0aeac5bb
--- /dev/null
+++ b/bsps/m68k/csb360/console/console-io.c
@@ -0,0 +1,97 @@
+/*
+ * This file contains the hardware specific portions of the TTY driver
+ * for the serial ports on the mcf5272
+ */
+
+/*
+ * COPYRIGHT (c) 1989-2000.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <bsp.h>
+#include <bsp/console-polled.h>
+#include <rtems/libio.h>
+#include <mcf5272/mcf5272.h>
+
+volatile int g_cnt = 0;
+
+/*
+ * console_initialize_hardware
+ *
+ * This routine initializes the console hardware.
+ *
+ */
+
+void console_initialize_hardware(void)
+{
+}
+
+
+/*
+ * console_outbyte_polled
+ *
+ * This routine transmits a character using polling.
+ */
+
+void console_outbyte_polled(
+ int port,
+ char ch
+)
+{
+ uart_regs_t *uart;
+ int i;
+ if (port == 0) {
+ uart = g_uart0_regs;
+ } else {
+ uart = g_uart1_regs;
+ }
+
+ /* wait for the fifo to make room */
+/* while ((uart->usr & MCF5272_USR_TXRDY) == 0) { */
+ while ((uart->ucsr & MCF5272_USR_TXRDY) == 0) {
+ continue;
+ }
+
+ uart->udata = ch;
+ for (i = 0; i < 1000; i++) g_cnt++;
+}
+
+/*
+ * console_inbyte_nonblocking
+ *
+ * This routine polls for a character.
+ */
+
+int console_inbyte_nonblocking(
+ int port
+)
+{
+ uart_regs_t *uart;
+ unsigned char c;
+
+ if (port == 0) {
+ uart = g_uart0_regs;
+ } else {
+ uart = g_uart1_regs;
+ }
+
+/* if (uart->usr & MCF5272_USR_RXRDY) { */
+ if (uart->ucsr & MCF5272_USR_RXRDY) {
+ c = (char)uart->udata;
+ return c;
+ } else {
+ return -1;
+ }
+}
+
+#include <rtems/bspIo.h>
+
+static void mcf5272_output_char(char c) { console_outbyte_polled( 0, c ); }
+
+BSP_output_char_function_type BSP_output_char = mcf5272_output_char;
+BSP_polling_getchar_function_type BSP_poll_char = NULL;
+
diff --git a/bsps/m68k/gen68340/console/console.c b/bsps/m68k/gen68340/console/console.c
new file mode 100644
index 0000000000..d6634b1079
--- /dev/null
+++ b/bsps/m68k/gen68340/console/console.c
@@ -0,0 +1,690 @@
+/*
+ * 68340/68349 console serial I/O.
+ */
+
+/*
+ * Author:
+ * Geoffroy Montel
+ * France Telecom - CNET/DSM/TAM/CAT
+ * 4, rue du Clos Courtel
+ * 35512 CESSON-SEVIGNE
+ * FRANCE
+ *
+ * e-mail: g_montel@yahoo.com
+ *
+ * COPYRIGHT (c) 1989-1999.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <termios.h>
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <bsp.h>
+#include <rtems/libio.h>
+#include <rtems/termiostypes.h>
+#include <rtems/console.h>
+#include <m68340.h>
+#include <m340uart.h>
+#include <m340timer.h>
+
+#define CONSOLE_VECTOR 121
+#define CONSOLE_IRQ_LEVEL 3
+#define CONSOLE_INTERRUPT_ARBITRATION 2
+
+static void *ttypA; /* to remember which tty has been opened on channel A
+ used when interrupts are enabled */
+
+static void *ttypB; /* to remember which tty has been opened on channel B
+ used when interrupts are enabled */
+
+unsigned char DUIER_mirror = 0 ; /* reflects the state of IER register, which is Write Only */
+unsigned char Error_Status_A = 0; /* error status on Channel A */
+unsigned char Error_Status_B = 0; /* error status on Channel A */
+
+/*
+ * Device-specific routines
+ */
+
+#define USE_INTERRUPTS_A (m340_uart_config[UART_CHANNEL_A].mode==UART_INTERRUPTS)
+#define USE_INTERRUPTS_B (m340_uart_config[UART_CHANNEL_B].mode==UART_INTERRUPTS)
+#define CHANNEL_ENABLED_A m340_uart_config[UART_CHANNEL_A].enable
+#define CHANNEL_ENABLED_B m340_uart_config[UART_CHANNEL_B].enable
+
+#define set_DUIER(a) DUIER_mirror |= (a); DUIER = DUIER_mirror
+#define unset_DUIER(a) DUIER_mirror &= ~(a); DUIER = DUIER_mirror
+
+#define Enable_Interrupts_Tx_A if (USE_INTERRUPTS_A) set_DUIER(m340_TxRDYA)
+#define Disable_Interrupts_Tx_A if (USE_INTERRUPTS_A) unset_DUIER(m340_TxRDYA)
+
+#define Enable_Interrupts_Tx_B if (USE_INTERRUPTS_B) set_DUIER(m340_TxRDYB)
+#define Disable_Interrupts_Tx_B if (USE_INTERRUPTS_B) unset_DUIER(m340_TxRDYB)
+
+/******************************************************
+ Name: InterruptHandler
+ Input parameters: vector number
+ Output parameters: -
+ Description: UART ISR Routine, called by _RTEMS_ISR
+ *****************************************************/
+rtems_isr
+InterruptHandler (rtems_vector_number v)
+{
+ char ch;
+
+ /*****************************************************************************
+ ** CHANNEL A **
+ *****************************************************************************/
+
+ /* check Received Break*/
+ if (DUSRA & m340_RB) {
+ Error_Status_A |= m340_RB;
+ /* reset error status */
+ DUCRA = m340_Reset_Error_Status;
+ }
+
+ /* buffer received ? */
+ if (DUSRA & m340_Rx_RDY) {
+ do {
+ /* error encountered? */
+ if (DUSRA & (m340_OE | m340_PE | m340_FE | m340_RB)) {
+ Error_Status_A |= DUSRA;
+ /* reset error status */
+ DUCRA = m340_Reset_Error_Status;
+ /* all the characters in the queue may not be good */
+ while (DUSRA & m340_Rx_RDY)
+ /* push them in a trash */
+ ch = DURBA;
+ }
+ else {
+ /* this is necessary, otherwise it blocks when FIFO is full */
+ ch = DURBA;
+ rtems_termios_enqueue_raw_characters(ttypA,&ch,1);
+ }
+ } while (DUSRA & m340_Rx_RDY);
+ Restart_Fifo_Full_A_Timer(); /* only if necessary (pointer to a fake function if
+ not in FIFO full mode) */
+ }
+
+ else /* if no character has been received */
+ Restart_Check_A_Timer(); /* same remark */
+
+ /* ready to accept a character ? */
+ if (DUISR & DUIER_mirror & m340_TxRDYA) {
+ Disable_Interrupts_Tx_A;
+ /* one character has been transmitted */
+ rtems_termios_dequeue_characters(ttypA,1);
+ }
+
+ /*****************************************************************************
+ ** CHANNEL B **
+ *****************************************************************************/
+
+ /* check Received Break*/
+ if (DUSRB & m340_RB) {
+ Error_Status_B |= m340_RB;
+ /* reset error status */
+ DUCRB = m340_Reset_Error_Status;
+ }
+
+ /* buffer received ? */
+ if (DUSRB & m340_Rx_RDY) {
+ do {
+ if (DUSRB & (m340_OE | m340_PE | m340_FE | m340_RB)) {
+ Error_Status_B |= DUSRB;
+ /* reset error status */
+ DUCRB = m340_Reset_Error_Status;
+ /* all the characters in the queue may not be good */
+ while (DUSRB & m340_Rx_RDY)
+ /* push them in a trash */
+ ch = DURBB;
+ }
+ else {
+ ch = DURBB;
+ rtems_termios_enqueue_raw_characters(ttypB,&ch,1);
+ }
+
+ } while (DUSRB & m340_Rx_RDY);
+ Restart_Fifo_Full_B_Timer();
+ }
+ else /* if no character has been received */
+ Restart_Check_B_Timer();
+
+ /* ready to accept a character ? */
+ if (DUISR & DUIER_mirror & m340_TxRDYB) {
+ Disable_Interrupts_Tx_B;
+ /* one character has been transmitted */
+ rtems_termios_dequeue_characters(ttypB,1);
+ }
+}
+
+/******************************************************
+ Name: InterruptWrite
+ Input parameters: minor = channel, pointer to buffer,
+ and length of buffer to transmit
+ Output parameters: -
+ Description: write the first character of buf only
+ may be called by either console_write
+ or rtems_termios_enqueue_raw_characters
+ *****************************************************/
+static ssize_t
+InterruptWrite (int minor, const char *buf, size_t len)
+{
+ if (minor==UART_CHANNEL_A) {
+ if (len>0) {
+ DUTBA=*buf;
+ Enable_Interrupts_Tx_A;
+ }
+ }
+ else if (minor==UART_CHANNEL_B) {
+ if (len>0) {
+ DUTBB=*buf;
+ Enable_Interrupts_Tx_B;
+ }
+ }
+ return 0;
+}
+
+/******************************************************
+ Name: dbug_out_char
+ Input parameters: channel, character to emit
+ Output parameters: -
+ Description: wait for the UART to be ready to emit
+ a character and send it
+ *****************************************************/
+void dbug_out_char( int minor, int ch )
+{
+ if (minor==UART_CHANNEL_A) {
+ while (!(DUSRA & m340_Tx_RDY)) continue;
+ DUTBA=ch;
+ }
+ else if (minor==UART_CHANNEL_B) {
+ while (!(DUSRB & m340_Tx_RDY)) continue;
+ DUTBB=ch;
+ }
+}
+
+/******************************************************
+ Name: dbug_in_char
+ Input parameters: -
+ Output parameters: received character
+ Description: return the character in the UART
+ *****************************************************/
+int dbug_in_char( int minor )
+{
+ if (minor==UART_CHANNEL_A) {
+ return DURBA;
+ }
+ else if (minor==UART_CHANNEL_B) {
+ return DURBB;
+ }
+ return 0;
+}
+
+/******************************************************
+ Name: dbug_char_present
+ Input parameters: channel #
+ Output parameters: TRUE or FALSE
+ Description: return whether there's a character
+ in the receive buffer
+ *****************************************************/
+int dbug_char_present( int minor )
+{
+ if (minor==UART_CHANNEL_A) {
+ return (DUSRA & m340_Rx_RDY);
+ }
+ else if (minor==UART_CHANNEL_B) {
+ return (DUSRB & m340_Rx_RDY);
+ }
+ return 0;
+}
+
+/******************************************************
+ Name: dbugInitialise
+ Input parameters: -
+ Output parameters: -
+ Description: Init the UART
+ *****************************************************/
+static void
+dbugInitialise (void)
+{
+ t_baud_speed_table uart_config; /* configuration of UARTS */
+
+ /*
+ * Reset Receiver
+ */
+ DUCRA = m340_Reset_Receiver;
+ DUCRB = m340_Reset_Receiver;
+
+ /*
+ * Reset Transmitter
+ */
+ DUCRA = m340_Reset_Transmitter;
+ DUCRB = m340_Reset_Transmitter;
+
+ /*
+ * Enable serial module for normal operation, ignore FREEZE, select the crystal clock,
+ * supervisor/user serial registers unrestricted
+ * interrupt arbitration at priority CONSOLE_INTERRUPT_ARBITRATION
+ * WARNING : 8 bits access only on this UART!
+ */
+ DUMCRH = 0x00;
+ DUMCRL = CONSOLE_INTERRUPT_ARBITRATION;
+
+ /*
+ * Interrupt level register
+ */
+ DUILR = CONSOLE_IRQ_LEVEL;
+
+ /* sets the IVR */
+ DUIVR = CONSOLE_VECTOR;
+
+ /* search for a correct m340 uart configuration */
+ uart_config = Find_Right_m340_UART_Config(m340_uart_config[UART_CHANNEL_A].rx_baudrate,
+ m340_uart_config[UART_CHANNEL_A].tx_baudrate,
+ CHANNEL_ENABLED_A,
+ m340_uart_config[UART_CHANNEL_B].rx_baudrate,
+ m340_uart_config[UART_CHANNEL_B].tx_baudrate,
+ CHANNEL_ENABLED_B);
+
+ /*****************************************************************************
+ ** CHANNEL A **
+ *****************************************************************************/
+ if (CHANNEL_ENABLED_A) {
+
+ if (USE_INTERRUPTS_A) {
+ rtems_isr_entry old_handler;
+
+ (void) rtems_interrupt_catch (InterruptHandler,
+ CONSOLE_VECTOR,
+ &old_handler);
+
+ /* uncomment this if you want to pass control to your own ISR handler
+ it may be usefull to do so to check for performances with an oscilloscope */
+ /*
+ {
+ proc_ptr ignored;
+ _CPU_ISR_install_raw_handler( CONSOLE_VECTOR, _Debug_ISR_Handler_Console, &ignored );
+ }
+ */
+
+ /*
+ * Interrupt Enable Register
+ * Enable Interrupts on Channel A Receiver Ready
+ */
+ set_DUIER(m340_RxRDYA);
+ }
+ else {
+ /*
+ * Disable Interrupts on channel A
+ */
+ unset_DUIER(m340_RxRDYA&m340_TxRDYA);
+ }
+
+ /*
+ * Change set of baud speeds
+ * disable input control
+ */
+ /* no good uart configuration ? */
+ if (uart_config.nb<1) rtems_fatal_error_occurred (-1);
+
+ if (uart_config.baud_speed_table[UART_CHANNEL_A].set==1)
+ DUACR = m340_BRG_Set1;
+ else
+ DUACR = m340_BRG_Set2;
+
+ /*
+ * make OPCR an auxiliary function serving the communication channels
+ */
+ DUOPCR = m340_OPCR_Aux;
+
+ /* poll the XTAL_RDY bit until it is cleared to ensure that an unstable crystal
+ input is not applied to the baud rate generator */
+ while (DUISR & m340_XTAL_RDY) continue;
+
+ /*
+ * Serial Channel Baud Speed
+ */
+ DUCSRA = (uart_config.baud_speed_table[UART_CHANNEL_A].rcs << 4)
+ | (uart_config.baud_speed_table[UART_CHANNEL_A].tcs);
+
+ /*
+ * Serial Channel Configuration
+ */
+ DUMR1A = m340_uart_config[UART_CHANNEL_A].parity_mode
+ | m340_uart_config[UART_CHANNEL_A].bits_per_char
+ | m340_RxRTS;
+
+ if (m340_uart_config[UART_CHANNEL_A].rx_mode==UART_FIFO_FULL) DUMR1A |= m340_R_F | m340_ERR;
+
+ /*
+ * Serial Channel Configuration 2
+ */
+ DUMR2A |= m340_normal;
+
+ /*
+ * Enable Channel A: transmitter and receiver
+ */
+ DUCRA = m340_Transmitter_Enable | m340_Receiver_Enable;
+ } /* channel A enabled */
+
+ /*****************************************************************************
+ ** CHANNEL B **
+ *****************************************************************************/
+ if (CHANNEL_ENABLED_B) {
+
+ /* we mustn't set the console vector twice! */
+ if ((USE_INTERRUPTS_B && !(CHANNEL_ENABLED_A))
+ || (USE_INTERRUPTS_B && CHANNEL_ENABLED_A && !USE_INTERRUPTS_A)) {
+ rtems_isr_entry old_handler;
+
+ (void) rtems_interrupt_catch (InterruptHandler,
+ CONSOLE_VECTOR,
+ &old_handler);
+
+ /* uncomment this if you want to pass control to your own ISR handler
+ it may be usefull to do so to check for performances with an oscilloscope */
+ /*
+ {
+ proc_ptr ignored;
+ _CPU_ISR_install_raw_handler( CONSOLE_VECTOR, _Debug_ISR_Handler_Console, &ignored );
+ }
+ */
+
+ /*
+ * Interrupt Enable Register
+ * Enable Interrupts on Channel A Receiver Ready
+ */
+ set_DUIER(m340_RxRDYB);
+ }
+ else {
+ /*
+ * Disable Interrupts on channel B
+ */
+ unset_DUIER(m340_RxRDYB&m340_TxRDYB);
+ }
+
+ /*
+ * Change set of baud speeds
+ * disable input control
+ */
+
+ /* no good uart configuration ? */
+ if (uart_config.nb<2) rtems_fatal_error_occurred (-1);
+
+ /* don't set DUACR twice! */
+ if (!CHANNEL_ENABLED_A) {
+ if (uart_config.baud_speed_table[UART_CHANNEL_B].set==1)
+ DUACR = m340_BRG_Set1;
+ else
+ DUACR = m340_BRG_Set2;
+ }
+
+ /*
+ * make OPCR an auxiliary function serving the communication channels
+ */
+ if (!CHANNEL_ENABLED_A) DUOPCR = m340_OPCR_Aux;
+
+ /* poll the XTAL_RDY bit until it is cleared to ensure that an unstable crystal
+ input is not applied to the baud rate generator */
+ while (DUISR & m340_XTAL_RDY) continue;
+
+ /*
+ * Serial Channel Baud Speed
+ */
+ DUCSRB = (uart_config.baud_speed_table[UART_CHANNEL_B].rcs << 4)
+ | (uart_config.baud_speed_table[UART_CHANNEL_B].tcs);
+
+ /*
+ * Serial Channel Configuration
+ */
+ DUMR1B = m340_uart_config[UART_CHANNEL_B].parity_mode
+ | m340_uart_config[UART_CHANNEL_B].bits_per_char
+ | m340_RxRTS;
+
+ if (m340_uart_config[UART_CHANNEL_B].rx_mode==UART_FIFO_FULL) DUMR1B |= m340_R_F | m340_ERR;
+
+ /*
+ * Serial Channel Configuration 2
+ */
+ DUMR2B |= m340_normal;
+
+ /*
+ * Enable Channel A: transmitter and receiver
+ */
+ DUCRB = m340_Transmitter_Enable | m340_Receiver_Enable;
+ } /* channel B enabled */
+}
+
+/******************************************************
+ Name: SetAttributes
+ Input parameters: termios structure, channel
+ Output parameters: -
+ Description: return whether there's a character
+ in the receive buffer
+ TO DO: add the channel # to check for!!
+ *****************************************************/
+static int
+SetAttributes (int minor, const struct termios *t)
+{
+ rtems_interrupt_level level;
+ float ispeed, ospeed;
+
+ /* convert it */
+ ispeed = rtems_termios_baud_to_number(t->c_ispeed);
+ ospeed = rtems_termios_baud_to_number(t->c_ospeed);
+
+ if (ispeed || ospeed) {
+ /* update config table */
+ m340_uart_config[UART_CHANNEL_A].rx_baudrate = ((minor==UART_CHANNEL_A)&&(ispeed!=0)) ? ispeed : m340_uart_config[UART_CHANNEL_A].rx_baudrate;
+ m340_uart_config[UART_CHANNEL_A].tx_baudrate = ((minor==UART_CHANNEL_A)&&(ospeed!=0)) ? ospeed : m340_uart_config[UART_CHANNEL_A].tx_baudrate;
+ m340_uart_config[UART_CHANNEL_B].rx_baudrate = ((minor==UART_CHANNEL_B)&&(ispeed!=0)) ? ispeed : m340_uart_config[UART_CHANNEL_B].rx_baudrate;
+ m340_uart_config[UART_CHANNEL_B].tx_baudrate = ((minor==UART_CHANNEL_B)&&(ospeed!=0)) ? ospeed : m340_uart_config[UART_CHANNEL_B].tx_baudrate;
+ }
+
+ /* change parity */
+ if (t->c_cflag & PARENB) {
+ if (t->c_cflag & PARODD) m340_uart_config[minor].parity_mode = m340_Odd_Parity;
+ else m340_uart_config[minor].parity_mode = m340_Even_Parity;
+ }
+
+ /* change bits per character */
+ if (t->c_cflag & CSIZE) {
+ switch (t->c_cflag & CSIZE) {
+ default: break;
+ case CS5: m340_uart_config[minor].bits_per_char = m340_5bpc; break;
+ case CS6: m340_uart_config[minor].bits_per_char = m340_6bpc; break;
+ case CS7: m340_uart_config[minor].bits_per_char = m340_7bpc; break;
+ case CS8: m340_uart_config[minor].bits_per_char = m340_8bpc; break;
+ }
+ }
+
+ /* if serial module configuration has been changed */
+ if (t->c_cflag & (CSIZE | PARENB)) {
+ rtems_interrupt_disable(level);
+ /* reinit the UART */
+ dbugInitialise();
+ rtems_interrupt_enable (level);
+ }
+
+ return 0;
+}
+
+/******************************************************
+ Name: console_initialize
+ Input parameters: MAJOR # of console_driver,
+ minor is always 0,
+ args are always NULL
+ Output parameters: -
+ Description: Reserve resources consumed by this driver
+ TODO: We should pass m340_uart_config table in arg
+ *****************************************************/
+rtems_device_driver console_initialize(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg
+)
+{
+ rtems_status_code status;
+ int i;
+
+ /*
+ * Set up TERMIOS
+ */
+ rtems_termios_initialize ();
+
+ /*
+ * Do device-specific initialization
+ */
+ Init_UART_Table();
+ dbugInitialise ();
+ Fifo_Full_benchmark_timer_initialize();
+
+ /*
+ * Register the devices
+ */
+ for (i=0; i<UART_NUMBER_OF_CHANNELS; i++) {
+ if (m340_uart_config[i].enable) {
+ status = rtems_io_register_name (m340_uart_config[i].name, major, i);
+ if (status != RTEMS_SUCCESSFUL)
+ rtems_fatal_error_occurred (status);
+ }
+ }
+
+ return RTEMS_SUCCESSFUL;
+}
+
+/******************************************************
+ Name: console_open
+ Input parameters: channel #, arg
+ Output parameters: -
+ Description: open the device
+ *****************************************************/
+rtems_device_driver console_open(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+ rtems_status_code sc = 0;
+
+ static const rtems_termios_callbacks intrCallbacks = {
+ NULL, /* firstOpen */
+ NULL, /* lastClose */
+ NULL, /* pollRead */
+ InterruptWrite, /* write */
+ SetAttributes, /* setAttributes */
+ NULL, /* stopRemoteTx */
+ NULL, /* startRemoteTx */
+ 1 /* outputUsesInterrupts */
+ };
+
+ static const rtems_termios_callbacks pollCallbacks = {
+ NULL, /* firstOpen */
+ NULL, /* lastClose */
+ dbugRead, /* pollRead */
+ dbugWrite, /* write */
+ SetAttributes, /* setAttributes */
+ NULL, /* stopRemoteTx */
+ NULL, /* startRemoteTx */
+ 0 /* outputUsesInterrupts */
+ };
+
+ if (minor==UART_CHANNEL_A) {
+ if (USE_INTERRUPTS_A) {
+ rtems_libio_open_close_args_t *args = arg;
+
+ sc |= rtems_termios_open (major, minor, arg, &intrCallbacks);
+ ttypA = args->iop->data1;
+ }
+ else {
+ sc |= rtems_termios_open (major, minor, arg, &pollCallbacks);
+ }
+ }
+
+ else if (minor==UART_CHANNEL_B) {
+ if (USE_INTERRUPTS_B) {
+ rtems_libio_open_close_args_t *args = arg;
+
+ sc |= rtems_termios_open (major, minor, arg, &intrCallbacks);
+ ttypB = args->iop->data1;
+ }
+ else {
+ sc |= rtems_termios_open (major, minor, arg, &pollCallbacks);
+ }
+ }
+
+ else return RTEMS_INVALID_NUMBER;
+
+ return sc;
+}
+
+/******************************************************
+ Name: console_close
+ Input parameters: channel #, termios args
+ Output parameters: -
+ Description: close the device
+ *****************************************************/
+rtems_device_driver console_close(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+ return rtems_termios_close (arg);
+}
+
+/******************************************************
+ Name: console_read
+ Input parameters: channel #, termios args
+ Output parameters: -
+ Description: read the device
+ *****************************************************/
+rtems_device_driver console_read(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+ return rtems_termios_read (arg);
+}
+
+/******************************************************
+ Name: console_write
+ Input parameters: channel #, termios args
+ Output parameters: -
+ Description: write to the device
+ *****************************************************/
+rtems_device_driver console_write(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+ return rtems_termios_write (arg);
+}
+
+/******************************************************
+ Name: console_control
+ Input parameters: channel #, termios args
+ Output parameters: -
+ Description: Handle ioctl request
+ *****************************************************/
+rtems_device_driver console_control(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+ rtems_libio_ioctl_args_t *args = arg;
+
+ if (args->command == TIOCSETA)
+ SetAttributes (minor, (struct termios *)args->buffer);
+
+ return rtems_termios_ioctl (arg);
+}
diff --git a/bsps/m68k/gen68340/console/m340uart.c b/bsps/m68k/gen68340/console/m340uart.c
new file mode 100644
index 0000000000..56ad29c256
--- /dev/null
+++ b/bsps/m68k/gen68340/console/m340uart.c
@@ -0,0 +1,311 @@
+/*
+ * M68340/349 UART management tools
+ */
+
+/*
+ * Author:
+ * Geoffroy Montel
+ * France Telecom - CNET/DSM/TAM/CAT
+ * 4, rue du Clos Courtel
+ * 35512 CESSON-SEVIGNE
+ * FRANCE
+ *
+ * e-mail: g_montel@yahoo.com
+ *
+ * COPYRIGHT (c) 1989-1999.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <termios.h>
+#include <bsp.h>
+#include <rtems/libio.h>
+#include <m68340.h>
+#include <m340uart.h>
+#include <stdarg.h>
+#include <string.h>
+
+/* this table shows compatible speed configurations for the MC68340:
+ the first row shows baud rates for baud speed set 1
+ the second row shows baud rates for baud speed set 2
+ look at Motorola's MC68340 Integrated Processor User's Manual
+ page 7-30 for more infos */
+
+float m340_Baud_Rates_Table[16][2] = {
+ { 50, 75 },
+ { 110, 110 },
+ { 134.5, 134.5 },
+ { 200, 150 },
+ { 300, 300 },
+ { 600, 600 },
+ { 1200, 1200 },
+ { 1050, 2000 },
+ { 2400, 2400 },
+ { 4800, 4800 },
+ { 7200, 1800 },
+ { 9600, 9600 },
+ { 38400, 19200 },
+ { 76800, 38400 },
+ { SCLK/16, SCLK/16},
+ { SCLK, SCLK },
+};
+
+/* config on both 340 channels */
+uart_channel_config m340_uart_config[UART_NUMBER_OF_CHANNELS];
+
+/*
+ * Init UART table
+ */
+
+#define NOT_IMPLEMENTED_YET 0
+
+/******************************************************
+ Name: Init_UART_Table
+ Input parameters: -
+ Output parameters: -
+ Description: Init the m340_uart_config
+ THIS SHOULD NOT BE HERE!
+ Its aim was to let the user configure
+ UARTs for each application.
+ As we can't pass args to the console
+ driver initialisation routine at the
+ moment, this was not done.
+ ATTENTION: TERMIOS init presupposes that the channel
+ baud rates is 9600/9600.
+ -> risks when using IOCTL
+ *****************************************************/
+void Init_UART_Table(void)
+{
+ m340_uart_config[UART_CHANNEL_A].enable = TRUE;
+ strcpy(m340_uart_config[UART_CHANNEL_A].name, UART_CONSOLE_NAME);
+ m340_uart_config[UART_CHANNEL_A].parity_mode = m340_No_Parity;
+ m340_uart_config[UART_CHANNEL_A].bits_per_char = m340_8bpc;
+ m340_uart_config[UART_CHANNEL_A].rx_baudrate = 9600;
+ m340_uart_config[UART_CHANNEL_A].tx_baudrate = 9600;
+ m340_uart_config[UART_CHANNEL_A].rx_mode = UART_CRR;
+ m340_uart_config[UART_CHANNEL_A].mode = UART_POLLING;
+
+ m340_uart_config[UART_CHANNEL_A].termios.enable = TRUE;
+ m340_uart_config[UART_CHANNEL_A].termios.rx_buffer_size = NOT_IMPLEMENTED_YET;
+ m340_uart_config[UART_CHANNEL_A].termios.tx_buffer_size = NOT_IMPLEMENTED_YET;
+
+ m340_uart_config[UART_CHANNEL_B].enable = FALSE;
+ strcpy(m340_uart_config[UART_CHANNEL_B].name, UART_RAW_IO_NAME);
+ m340_uart_config[UART_CHANNEL_B].parity_mode = m340_No_Parity;
+ m340_uart_config[UART_CHANNEL_B].bits_per_char = m340_8bpc;
+ m340_uart_config[UART_CHANNEL_B].rx_baudrate = 38400;
+ m340_uart_config[UART_CHANNEL_B].tx_baudrate = 38400;
+ m340_uart_config[UART_CHANNEL_B].rx_mode = UART_CRR;
+ m340_uart_config[UART_CHANNEL_B].mode = UART_INTERRUPTS;
+
+ m340_uart_config[UART_CHANNEL_B].termios.enable = TRUE;
+ m340_uart_config[UART_CHANNEL_B].termios.rx_buffer_size = NOT_IMPLEMENTED_YET;
+ m340_uart_config[UART_CHANNEL_B].termios.tx_buffer_size = NOT_IMPLEMENTED_YET;
+}
+
+/******************************************************
+ Name: Find_Right_m340_UART_Channel_Config
+ Input parameters: Send/Receive baud rates for a
+ given channel
+ Output parameters: UART compatible configs for this
+ channel
+ Description: returns which uart configurations fit
+ Receiver Baud Rate and Transmitter Baud
+ Rate for a given channel
+ For instance, according to the
+ m340_Baud_Rates_Table:
+ - Output Speed = 50, Input Speed = 75
+ is not a correct config, because
+ 50 bauds implies set 1 and 75 bauds
+ implies set 2
+ - Output Speed = 9600, Input Speed = 9600
+ two correct configs for this:
+ RCS=11, TCS=11, Set=1 or 2
+ *****************************************************/
+static t_baud_speed_table
+Find_Right_m340_UART_Channel_Config(
+ float ReceiverBaudRate,
+ float TransmitterBaudRate
+)
+{
+ t_baud_speed_table return_value;
+ int i,j;
+
+ struct {
+ int cs;
+ int set;
+ } Receiver[2], Transmitter[2];
+
+ int Receiver_nb_of_config = 0;
+ int Transmitter_nb_of_config = 0;
+
+ /* Receiver and Transmitter baud rates must be compatible, ie in the
+ * same set.
+ */
+
+ /* search for configurations for ReceiverBaudRate
+ * there can't be more than two (only two sets).
+ */
+ for (i=0;i<16;i++) {
+ for (j=0;j<2;j++) {
+ if (m340_Baud_Rates_Table[i][j]==ReceiverBaudRate) {
+ Receiver[Receiver_nb_of_config].cs=i;
+ Receiver[Receiver_nb_of_config].set=j;
+ Receiver_nb_of_config++;
+ }
+ }
+ }
+
+ /* search for configurations for TransmitterBaudRate
+ * there can't be more than two (only two sets)
+ */
+ for (i=0;i<16;i++) {
+ for (j=0;j<2;j++) {
+ if (m340_Baud_Rates_Table[i][j]==TransmitterBaudRate) {
+ Transmitter[Transmitter_nb_of_config].cs=i;
+ Transmitter[Transmitter_nb_of_config].set=j;
+ Transmitter_nb_of_config++;
+ }
+ }
+ }
+
+ /* now check if there's a compatible config */
+ return_value.nb=0;
+
+ for (i=0; i<Receiver_nb_of_config; i++) {
+ for (j=0;j<Transmitter_nb_of_config;j++) {
+ if (Receiver[i].set == Transmitter[j].set) {
+ return_value.baud_speed_table[return_value.nb].set = Receiver[i].set + 1;
+ /* we want set 1 or set 2, not 0 or 1 */
+ return_value.baud_speed_table[return_value.nb].rcs = Receiver[i].cs;
+ return_value.baud_speed_table[return_value.nb].tcs = Transmitter[j].cs;
+ return_value.nb++;
+ }
+ }
+ }
+
+ return return_value;
+}
+
+/******************************************************
+ Name: Find_Right_m340_UART_Config
+ Input parameters: Send/Receive baud rates for both
+ channels
+ Output parameters: UART compatible configs for
+ BOTH channels
+ Description: returns which uart configurations fit
+ Receiver Baud Rate and Transmitter Baud
+ Rate for both channels
+ For instance, if we want 9600/38400 on
+ channel A and 9600/19200 on channel B,
+ this is not a good m340 uart config
+ (channel A needs set 1 and channel B
+ needs set 2)
+ *****************************************************/
+t_baud_speed_table
+Find_Right_m340_UART_Config(
+ float ChannelA_ReceiverBaudRate,
+ float ChannelA_TransmitterBaudRate,
+ uint8_t enableA,
+ float ChannelB_ReceiverBaudRate,
+ float ChannelB_TransmitterBaudRate,
+ uint8_t enableB
+)
+{
+ t_baud_speed_table tableA, tableB;
+ t_baud_speed_table return_value, tmp;
+ int i,j;
+
+ memset( &return_value, '\0', sizeof(return_value) );
+ return_value.nb=0;
+
+ if (enableA && enableB) {
+ tableA = Find_Right_m340_UART_Channel_Config(
+ ChannelA_ReceiverBaudRate, ChannelA_TransmitterBaudRate);
+ tableB = Find_Right_m340_UART_Channel_Config(
+ ChannelB_ReceiverBaudRate, ChannelB_TransmitterBaudRate);
+
+ for (i=0;i<tableA.nb;i++) {
+ for (j=0;j<tableB.nb;j++) {
+ if (tableA.baud_speed_table[i].set==tableB.baud_speed_table[j].set) {
+ return_value.baud_speed_table[UART_CHANNEL_A].set =
+ tableA.baud_speed_table[i].set;
+ return_value.baud_speed_table[UART_CHANNEL_A].rcs =
+ tableA.baud_speed_table[i].rcs;
+ return_value.baud_speed_table[UART_CHANNEL_A].tcs =
+ tableA.baud_speed_table[i].tcs;
+ return_value.baud_speed_table[UART_CHANNEL_B].set =
+ tableB.baud_speed_table[j].set;
+ return_value.baud_speed_table[UART_CHANNEL_B].rcs =
+ tableB.baud_speed_table[j].rcs;
+ return_value.baud_speed_table[UART_CHANNEL_B].tcs =
+ tableB.baud_speed_table[j].tcs;
+ return_value.nb=2;
+ break;
+ }
+ }
+ }
+ return return_value;
+ }
+
+ if (enableA) {
+ return_value = Find_Right_m340_UART_Channel_Config(
+ ChannelA_ReceiverBaudRate, ChannelA_TransmitterBaudRate);
+ return return_value;
+ }
+
+ if (enableB) {
+ tmp = Find_Right_m340_UART_Channel_Config(
+ ChannelB_ReceiverBaudRate, ChannelB_TransmitterBaudRate);
+ if (tmp.nb!=0) {
+ return_value.nb = 2;
+ return_value.baud_speed_table[1].set = tmp.baud_speed_table[0].set;
+ return_value.baud_speed_table[1].rcs = tmp.baud_speed_table[0].rcs;
+ return_value.baud_speed_table[1].tcs = tmp.baud_speed_table[0].tcs;
+ }
+ }
+ return return_value;
+}
+
+
+/*
+ * very low level fmted output
+ */
+extern void dbug_out_char( int minor, int ch );
+extern int dbug_in_char( int minor );
+extern int dbug_char_present( int minor );
+
+/******************************************************
+ Name: dbugRead
+ Input parameters: channel
+ Output parameters: char read
+ Description: polled read
+ *****************************************************/
+int dbugRead (int minor)
+{
+ if (dbug_char_present(minor) == 0)
+ return -1;
+ return dbug_in_char(minor);
+}
+
+/******************************************************
+ Name: dbugWrite
+ Input parameters: channel, buffer and its length
+ Output parameters: always successfull
+ Description: polled write
+ *****************************************************/
+ssize_t dbugWrite (int minor, const char *buf, size_t len)
+{
+ static char txBuf;
+ size_t retval = len;
+
+ while (len--) {
+ txBuf = *buf++;
+ dbug_out_char( minor, (int)txBuf );
+ }
+ return retval;
+}
+
diff --git a/bsps/m68k/gen68360/console/console.c b/bsps/m68k/gen68360/console/console.c
new file mode 100644
index 0000000000..36d8470168
--- /dev/null
+++ b/bsps/m68k/gen68360/console/console.c
@@ -0,0 +1,390 @@
+/*
+ * SMC1 raw console serial I/O.
+ *
+ * This driver is an example of `POLLING' or `INTERRUPT' I/O.
+ *
+ * To run with interrupt-driven I/O, ensure m360_smc1_interrupt
+ * is set before calling the initialization routine.
+ */
+
+/*
+ * Author:
+ * W. Eric Norum
+ * Saskatchewan Accelerator Laboratory
+ * University of Saskatchewan
+ * Saskatoon, Saskatchewan, CANADA
+ * eric@skatter.usask.ca
+ *
+ * COPYRIGHT (c) 1989-1999.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <termios.h>
+#include <bsp.h>
+#include <rtems/libio.h>
+#include <rtems/console.h>
+#include <rtems/termiostypes.h>
+#include <rtems/m68k/m68360.h>
+
+/*
+ * Declare clock speed -- may be overwritten by downloader or debugger
+ */
+int m360_clock_rate = 25000000;
+
+/*
+ * Interrupt-driven input buffer
+ * Declare console baud rate -- may also be overwritten
+ */
+int console_baud_rate = 9600;
+
+/*
+ */
+#define RXBUFSIZE 16
+
+/*
+ * Interrupt-driven callback
+ */
+static int m360_smc1_interrupt = 1;
+static void *smc1ttyp;
+
+/*
+ * I/O buffers and pointers to buffer descriptors
+ */
+static volatile char rxBuf[RXBUFSIZE];
+static volatile m360BufferDescriptor_t *smcRxBd, *smcTxBd;
+
+/*
+ * Device-specific routines
+ */
+
+/*
+ * Compute baud-rate-generator configuration register value
+ */
+static int
+smc1BRGC (int baud)
+{
+ int divisor;
+ int div16 = 0;
+
+ divisor = ((m360_clock_rate / 16) + (baud / 2)) / baud;
+ if (divisor > 4096) {
+ div16 = 1;
+ divisor = (divisor + 8) / 16;
+ }
+ return M360_BRG_EN | M360_BRG_EXTC_BRGCLK | ((divisor - 1) << 1) | div16;
+}
+
+/*
+ * Hardware-dependent portion of tcsetattr().
+ */
+static int
+smc1SetAttributes (int minor, const struct termios *t)
+{
+ int baud;
+
+ baud = rtems_termios_baud_to_number(t->c_ospeed);
+ if (baud > 0)
+ m360.brgc1 = smc1BRGC (baud);
+ return 0;
+}
+
+/*
+ * Interrupt handler
+ */
+static rtems_isr
+smc1InterruptHandler (rtems_vector_number v)
+{
+ /*
+ * Buffer received?
+ */
+ if (m360.smc1.smce & 0x1) {
+ m360.smc1.smce = 0x1;
+ while ((smcRxBd->status & M360_BD_EMPTY) == 0) {
+ rtems_termios_enqueue_raw_characters (smc1ttyp,
+ (char *)smcRxBd->buffer,
+ smcRxBd->length);
+ smcRxBd->status = M360_BD_EMPTY | M360_BD_WRAP | M360_BD_INTERRUPT;
+ }
+ }
+
+ /*
+ * Buffer transmitted?
+ */
+ if (m360.smc1.smce & 0x2) {
+ m360.smc1.smce = 0x2;
+ if ((smcTxBd->status & M360_BD_READY) == 0)
+ rtems_termios_dequeue_characters (smc1ttyp, smcTxBd->length);
+ }
+ m360.cisr = 1UL << 4; /* Clear SMC1 interrupt-in-service bit */
+}
+
+static int
+smc1Initialize (int major, int minor, void *arg)
+{
+ /*
+ * Allocate buffer descriptors
+ */
+ smcRxBd = M360AllocateBufferDescriptors (1);
+ smcTxBd = M360AllocateBufferDescriptors (1);
+
+ /*
+ * Configure port B pins to enable SMTXD1 and SMRXD1 pins
+ */
+ m360.pbpar |= 0xC0;
+ m360.pbdir &= ~0xC0;
+ m360.pbodr &= ~0xC0;
+
+ /*
+ * Set up BRG1 (9,600 baud)
+ */
+ m360.brgc1 = M360_BRG_RST;
+ m360.brgc1 = smc1BRGC (console_baud_rate);
+
+ /*
+ * Put SMC1 in NMSI mode, connect SMC1 to BRG1
+ */
+ m360.simode |= M360_SI_SMC1_BRG1;
+
+ /*
+ * Set up SMC1 parameter RAM common to all protocols
+ */
+ m360.smc1p.rbase = (char *)smcRxBd - (char *)&m360;
+ m360.smc1p.tbase = (char *)smcTxBd - (char *)&m360;
+ m360.smc1p.rfcr = M360_RFCR_MOT | M360_RFCR_DMA_SPACE;
+ m360.smc1p.tfcr = M360_TFCR_MOT | M360_TFCR_DMA_SPACE;
+ if (m360_smc1_interrupt)
+ m360.smc1p.mrblr = RXBUFSIZE;
+ else
+ m360.smc1p.mrblr = 1;
+
+ /*
+ * Set up SMC1 parameter RAM UART-specific parameters
+ */
+ m360.smc1p.un.uart.max_idl = 10;
+ m360.smc1p.un.uart.brklen = 0;
+ m360.smc1p.un.uart.brkec = 0;
+ m360.smc1p.un.uart.brkcr = 0;
+
+ /*
+ * Set up the Receive Buffer Descriptor
+ */
+ smcRxBd->status = M360_BD_EMPTY | M360_BD_WRAP | M360_BD_INTERRUPT;
+ smcRxBd->length = 0;
+ smcRxBd->buffer = rxBuf;
+
+ /*
+ * Setup the Transmit Buffer Descriptor
+ */
+ smcTxBd->status = M360_BD_WRAP;
+
+ /*
+ * Set up SMC1 general and protocol-specific mode registers
+ */
+ m360.smc1.smce = ~0; /* Clear any pending events */
+ m360.smc1.smcm = 0; /* Mask all interrupt/event sources */
+ m360.smc1.smcmr = M360_SMCMR_CLEN(9) | M360_SMCMR_SM_UART;
+
+ /*
+ * Send "Init parameters" command
+ */
+ M360ExecuteRISC (M360_CR_OP_INIT_RX_TX | M360_CR_CHAN_SMC1);
+
+ /*
+ * Enable receiver and transmitter
+ */
+ m360.smc1.smcmr |= M360_SMCMR_TEN | M360_SMCMR_REN;
+
+ if (m360_smc1_interrupt) {
+ rtems_isr_entry old_handler;
+
+ (void) rtems_interrupt_catch (smc1InterruptHandler,
+ (m360.cicr & 0xE0) | 0x04,
+ &old_handler);
+ m360.smc1.smcm = 3; /* Enable SMC1 TX and RX interrupts */
+ m360.cimr |= 1UL << 4; /* Enable SMC1 interrupts */
+ }
+
+ return 0;
+}
+
+static int
+smc1PollRead (int minor)
+{
+ unsigned char c;
+
+ if (smcRxBd->status & M360_BD_EMPTY)
+ return -1;
+ c = rxBuf[0];
+ smcRxBd->status = M360_BD_EMPTY | M360_BD_WRAP;
+ return c;
+}
+
+/*
+ * Device-dependent write routine
+ * Interrupt-driven devices:
+ * Begin transmission of as many characters as possible (minimum is 1).
+ * Polling devices:
+ * Transmit all characters.
+ */
+static ssize_t
+smc1InterruptWrite (int minor, const char *buf, size_t len)
+{
+ if (len > 0) {
+ smcTxBd->buffer = (char *)buf;
+ smcTxBd->length = len;
+ smcTxBd->status = M360_BD_READY | M360_BD_WRAP | M360_BD_INTERRUPT;
+ }
+
+ return 0;
+}
+
+static ssize_t
+smc1PollWrite (int minor, const char *buf, size_t len)
+{
+ size_t retval = len;
+ while (len--) {
+ static char txBuf;
+ while (smcTxBd->status & M360_BD_READY)
+ continue;
+ txBuf = *buf++;
+ smcTxBd->buffer = &txBuf;
+ smcTxBd->length = 1;
+ smcTxBd->status = M360_BD_READY | M360_BD_WRAP;
+ }
+ return retval;
+}
+
+/*
+ ***************
+ * BOILERPLATE *
+ ***************
+ */
+
+/*
+ * Reserve resources consumed by this driver
+ *
+ * NOTE: This is in another file to reduce dependencies on the minimum size.
+ */
+
+/*
+ * Initialize and register the device
+ */
+rtems_device_driver console_initialize(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg
+)
+{
+ rtems_status_code status;
+
+ /*
+ * Set up TERMIOS
+ */
+ rtems_termios_initialize ();
+
+ /*
+ * Register the device
+ */
+ status = rtems_io_register_name ("/dev/console", major, 0);
+ if (status != RTEMS_SUCCESSFUL)
+ rtems_fatal_error_occurred (status);
+ return RTEMS_SUCCESSFUL;
+}
+
+/*
+ * Open the device
+ */
+rtems_device_driver console_open(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+ rtems_status_code sc;
+ static const rtems_termios_callbacks intrCallbacks = {
+ smc1Initialize, /* firstOpen */
+ NULL, /* lastClose */
+ NULL, /* pollRead */
+ smc1InterruptWrite, /* write */
+ smc1SetAttributes, /* setAttributes */
+ NULL, /* stopRemoteTx */
+ NULL, /* startRemoteTx */
+ 1 /* outputUsesInterrupts */
+ };
+ static const rtems_termios_callbacks pollCallbacks = {
+ smc1Initialize, /* firstOpen */
+ NULL, /* lastClose */
+ smc1PollRead, /* pollRead */
+ smc1PollWrite, /* write */
+ smc1SetAttributes, /* setAttributes */
+ NULL, /* stopRemoteTx */
+ NULL, /* startRemoteTx */
+ 0 /* outputUsesInterrupts */
+ };
+
+ /*
+ * Do generic termios initialization
+ */
+ if (m360_smc1_interrupt) {
+ rtems_libio_open_close_args_t *args = arg;
+
+ sc = rtems_termios_open (major, minor, arg, &intrCallbacks);
+ smc1ttyp = args->iop->data1;
+ }
+ else {
+ sc = rtems_termios_open (major, minor, arg, &pollCallbacks);
+ }
+ return sc;
+}
+
+/*
+ * Close the device
+ */
+rtems_device_driver console_close(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+ return rtems_termios_close (arg);
+}
+
+/*
+ * Read from the device
+ */
+rtems_device_driver console_read(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+ return rtems_termios_read (arg);
+}
+
+/*
+ * Write to the device
+ */
+rtems_device_driver console_write(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+ return rtems_termios_write (arg);
+}
+
+/*
+ * Handle ioctl request.
+ */
+rtems_device_driver console_control(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+ return rtems_termios_ioctl (arg);
+}
diff --git a/bsps/m68k/genmcf548x/console/console.c b/bsps/m68k/genmcf548x/console/console.c
new file mode 100644
index 0000000000..32e5601a17
--- /dev/null
+++ b/bsps/m68k/genmcf548x/console/console.c
@@ -0,0 +1,843 @@
+/*===============================================================*\
+| Project: RTEMS generic mcf548x BSP |
++-----------------------------------------------------------------+
+| File: console.c |
++-----------------------------------------------------------------+
+| The file contains the console driver code of generic MCF548x |
+| BSP. |
++-----------------------------------------------------------------+
+| Copyright (c) 2007 |
+| Embedded Brains GmbH |
+| Obere Lagerstr. 30 |
+| D-82178 Puchheim |
+| Germany |
+| rtems@embedded-brains.de |
++-----------------------------------------------------------------+
+| |
+| Parts of the code has been derived from the "dBUG source code" |
+| package Freescale is providing for M548X EVBs. The usage of |
+| the modified or unmodified code and it's integration into the |
+| generic mcf548x BSP has been done according to the Freescale |
+| license terms. |
+| |
+| The Freescale license terms can be reviewed in the file |
+| |
+| Freescale_license.txt |
+| |
++-----------------------------------------------------------------+
+| |
+| The generic mcf548x BSP has been developed on the basic |
+| structures and modules of the av5282 BSP. |
+| |
++-----------------------------------------------------------------+
+| |
+| The license and distribution terms for this file may be |
+| found in the file LICENSE in this distribution or at |
+| |
+| http://www.rtems.org/license/LICENSE. |
+| |
++-----------------------------------------------------------------+
+| |
+| date history ID |
+| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
+| 12.11.07 1.0 ras |
+| |
+\*===============================================================*/
+
+ /*
+ * Multi UART console serial I/O.
+ *
+ * TO DO: Add DMA input/output
+ */
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <malloc.h>
+
+#include <bsp.h>
+#include <bsp/irq-generic.h>
+#include <rtems/libio.h>
+#include <rtems/termiostypes.h>
+#include <rtems/console.h>
+#include <rtems/bspIo.h>
+
+#define UART_INTC0_IRQ_VECTOR(x) (64+35-(x))
+
+#define MCF548X_PSC_SR_ERROR ( MCF548X_PSC_SR_RB_NEOF | \
+ MCF548X_PSC_SR_FE_PHYERR | \
+ MCF548X_PSC_SR_PE_CRCERR | \
+ MCF548X_PSC_SR_OE )
+
+static ssize_t IntUartPollWrite(int minor, const char *buf, size_t len);
+static int IntUartPollRead (int minor);
+static int IntUartSetAttributes(int minor, const struct termios *t);
+
+static void
+psc_output_char( char c )
+{
+ rtems_interrupt_level level;
+
+ rtems_interrupt_disable(level);
+ while (!((MCF548X_PSC_SR(CONSOLE_PORT) & MCF548X_PSC_SR_TXRDY)))
+ continue;
+ *((uint8_t *) &MCF548X_PSC_TB(CONSOLE_PORT)) = c;
+ while (!((MCF548X_PSC_SR(CONSOLE_PORT) & MCF548X_PSC_SR_TXRDY)))
+ continue;
+ rtems_interrupt_enable(level);
+}
+
+static void
+psc_output_char_init(char c)
+{
+ IntUartSetAttributes(CONSOLE_PORT, NULL);
+ BSP_output_char = psc_output_char;
+ psc_output_char(c);
+}
+
+BSP_output_char_function_type BSP_output_char = psc_output_char_init;
+
+BSP_polling_getchar_function_type BSP_poll_char = NULL;
+
+#define MAX_UART_INFO 4
+#define RX_BUFFER_SIZE 248
+
+struct IntUartInfoStruct
+{
+ int iomode;
+ volatile int imr;
+ int baud;
+ int databits;
+ int parity;
+ int stopbits;
+ int hwflow;
+ int rx_in;
+ int rx_out;
+ char rx_buffer[RX_BUFFER_SIZE];
+ void *ttyp;
+};
+
+struct IntUartInfoStruct IntUartInfo[MAX_UART_INFO];
+
+static int GetBaud( int baudHandle )
+{
+ int baud = BSP_CONSOLE_BAUD;
+ switch(baudHandle)
+ {
+ case B0:
+ baud = (int)0;
+ break;
+ case B1200:
+ baud = (int)1200;
+ break;
+ case B2400:
+ baud = (int)2400;
+ break;
+ case B4800:
+ baud = (int)4800;
+ break;
+ case B9600:
+ baud = (int)9600;
+ break;
+ case B19200:
+ baud = (int)19200;
+ break;
+ case B38400:
+ baud = (int)38400;
+ break;
+ case B57600:
+ baud = (int)57600;
+ break;
+ case B115200:
+ baud = (int)115200;
+ break;
+ }
+ return baud;
+}
+
+/***************************************************************************
+ Function : IntUartSet
+
+ Description : This updates the hardware UART settings.
+ ***************************************************************************/
+static void
+IntUartSet(int minor, int baud, int databits, int parity, int stopbits, int hwflow)
+{
+ uint8_t psc_mode_1 = 0, psc_mode_2 = 0;
+ uint16_t divider;
+ int level;
+ struct IntUartInfoStruct *info = &IntUartInfo[minor];
+
+ rtems_interrupt_disable(level);
+
+ /* disable interrupts, clear RTS line, and disable the UARTS */
+ /* Mask all psc interrupts */
+ MCF548X_PSC_IMR(minor) = 0x0000;
+
+ /* Clear RTS to send */
+ MCF548X_PSC_OPSET(minor) &= ~(MCF548X_PSC_OPSET_RTS);
+
+ /* Disable receiver and transmitter */
+ MCF548X_PSC_CR(minor) &= ~(MCF548X_PSC_CR_RX_ENABLED | MCF548X_PSC_CR_TX_ENABLED);
+
+ /* provide gpio settings */
+ switch (minor)
+ {
+ case 0:
+ MCF548X_GPIO_PAR_PSC0 = (0 | MCF548X_GPIO_PAR_PSC0_PAR_TXD0 | MCF548X_GPIO_PAR_PSC0_PAR_RXD0);
+
+ if(hwflow)
+ {
+ MCF548X_GPIO_PAR_PSC0 |= (0 | MCF548X_GPIO_PAR_PSC0_PAR_CTS0_CTS | MCF548X_GPIO_PAR_PSC0_PAR_RTS0_RTS);
+ }
+ break;
+ case 1:
+ MCF548X_GPIO_PAR_PSC1 = (0 | MCF548X_GPIO_PAR_PSC1_PAR_TXD1 | MCF548X_GPIO_PAR_PSC1_PAR_RXD1);
+
+ if(hwflow)
+ {
+ MCF548X_GPIO_PAR_PSC1 |= (0 | MCF548X_GPIO_PAR_PSC1_PAR_CTS1_CTS | MCF548X_GPIO_PAR_PSC1_PAR_RTS1_RTS);
+ }
+ break;
+ case 2:
+ MCF548X_GPIO_PAR_PSC2 = (0 | MCF548X_GPIO_PAR_PSC2_PAR_TXD2 | MCF548X_GPIO_PAR_PSC2_PAR_RXD2);
+
+ if(hwflow)
+ {
+ MCF548X_GPIO_PAR_PSC2 |= (0 | MCF548X_GPIO_PAR_PSC2_PAR_CTS2_CTS | MCF548X_GPIO_PAR_PSC2_PAR_RTS2_RTS);
+ }
+ break;
+ case 3:
+ MCF548X_GPIO_PAR_PSC3 = (0 | MCF548X_GPIO_PAR_PSC3_PAR_TXD3 | MCF548X_GPIO_PAR_PSC3_PAR_RXD3);
+
+ if(hwflow)
+ {
+ MCF548X_GPIO_PAR_PSC3 |= (0 | MCF548X_GPIO_PAR_PSC3_PAR_CTS3_CTS | MCF548X_GPIO_PAR_PSC3_PAR_RTS3_RTS);
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* save the current values */
+ info->imr = 0;
+ info->baud = baud;
+ info->databits = databits;
+ info->parity = parity;
+ info->stopbits = stopbits;
+ info->hwflow = hwflow;
+
+ /* Put PSC in UART mode */
+ MCF548X_PSC_SICR(minor) = MCF548X_PSC_SICR_SIM_UART;
+
+ /* set the baud rate values */
+ MCF548X_PSC_CSR(minor) = (0 | MCF548X_PSC_CSR_RCSEL_SYS_CLK | MCF548X_PSC_CSR_TCSEL_SYS_CLK);
+
+ /* Calculate baud settings */
+ divider = (uint16_t)((get_CPU_clock_speed())/(baud * 32));
+ MCF548X_PSC_CTUR(minor) = (uint8_t) ((divider >> 8) & 0xFF);
+ MCF548X_PSC_CTLR(minor) = (uint8_t) (divider & 0xFF);
+
+ /* Reset transmitter, receiver, mode register, and error conditions */
+ MCF548X_PSC_CR(minor) = MCF548X_PSC_CR_RESET_RX;
+ MCF548X_PSC_CR(minor) = MCF548X_PSC_CR_RESET_TX;
+ MCF548X_PSC_CR(minor) = MCF548X_PSC_CR_RESET_ERROR;
+ MCF548X_PSC_CR(minor) = MCF548X_PSC_CR_BKCHGINT;
+ MCF548X_PSC_CR(minor) = MCF548X_PSC_CR_RESET_MR;
+
+ /* check to see if doing hardware flow control */
+ if ( hwflow )
+ {
+ /* set hardware flow options */
+ psc_mode_1 = MCF548X_PSC_MR_RXRTS;
+ psc_mode_2 = MCF548X_PSC_MR_TXCTS;
+ }
+
+ /* set mode registers */
+ psc_mode_1 |= (uint8_t)(parity | databits);
+ psc_mode_2 |= (uint8_t)(stopbits);
+
+ /* set mode registers */
+ MCF548X_PSC_MR(minor) = psc_mode_1;
+ MCF548X_PSC_MR(minor) = psc_mode_2;
+
+ /* Setup FIFO Alarms */
+ MCF548X_PSC_RFAR(minor) = MCF548X_PSC_RFAR_ALARM(248);
+ MCF548X_PSC_TFAR(minor) = MCF548X_PSC_TFAR_ALARM(248);
+
+ /* check to see if interrupts need to be enabled */
+ if ( info->iomode != TERMIOS_POLLED )
+ {
+ /* enable rx interrupts */
+ info->imr |= MCF548X_PSC_IMR_RXRDY_FU;
+ MCF548X_PSC_IMR(minor) = info->imr;
+ }
+
+ /* check to see if doing hardware flow control */
+ if ( hwflow )
+ {
+ /* assert the RTS line */
+ MCF548X_PSC_OPSET(minor) = MCF548X_PSC_OPSET_RTS;
+ }
+
+ rtems_interrupt_enable(level);
+
+ /* Enable receiver and transmitter */
+ MCF548X_PSC_CR(minor) =(0 | MCF548X_PSC_CR_RX_ENABLED | MCF548X_PSC_CR_TX_ENABLED);
+
+
+}
+
+/***************************************************************************
+ Function : IntUartSetAttributes
+
+ Description : This provides the hardware-dependent portion of tcsetattr().
+ value and sets it. At the moment this just sets the baud rate.
+
+ Note: The highest baudrate is 115200 as this stays within
+ an error of +/- 5% at 25MHz processor clock
+ ***************************************************************************/
+static int
+IntUartSetAttributes(int minor, const struct termios *t)
+{
+/* set default index values */
+#ifdef HAS_DBUG
+ int baud = DBUG_SETTINGS.console_baudrate;
+#else
+ int baud = (int)BSP_CONSOLE_BAUD;
+#endif
+ int databits = (int)MCF548X_PSC_MR_BC_8;
+ int parity = (int)MCF548X_PSC_MR_PM_NONE;
+ int stopbits = (int)MCF548X_PSC_MR_SB_STOP_BITS_1;
+ int hwflow = (int)1;
+ struct IntUartInfoStruct *info = &IntUartInfo[minor];
+
+ /* check to see if input is valid */
+ if ( t != (const struct termios *)0 )
+ {
+ /* determine baud rate index */
+ baud = GetBaud( t->c_ospeed );
+
+ /* determine data bits */
+ switch ( t->c_cflag & CSIZE )
+ {
+ case CS5:
+ databits = (int)MCF548X_PSC_MR_BC_5;
+ break;
+ case CS6:
+ databits = (int)MCF548X_PSC_MR_BC_6;
+ break;
+ case CS7:
+ databits = (int)MCF548X_PSC_MR_BC_7;
+ break;
+ case CS8:
+ databits = (int)MCF548X_PSC_MR_BC_8;
+ break;
+ }
+
+ /* determine if parity is enabled */
+ if ( t->c_cflag & PARENB )
+ {
+ if ( t->c_cflag & PARODD )
+ {
+ /* odd parity */
+ parity = (int)MCF548X_PSC_MR_PM_ODD;
+ }
+ else
+ {
+ /* even parity */
+ parity = (int)MCF548X_PSC_MR_PM_EVEN;
+ }
+ }
+
+ /* determine stop bits */
+ if ( t->c_cflag & CSTOPB )
+ {
+ /* two stop bits */
+ stopbits = (int)MCF548X_PSC_MR_SB_STOP_BITS_2;
+ }
+
+ /* check to see if hardware flow control */
+ if ( t->c_cflag & CRTSCTS )
+ {
+ hwflow = 1;
+ }
+ }
+
+ /* check to see if values have changed */
+ if ( ( baud != info->baud ) ||
+ ( databits != info->databits ) ||
+ ( parity != info->parity ) ||
+ ( stopbits != info->stopbits ) ||
+ ( hwflow != info->hwflow ) )
+ {
+
+ /* call function to set values */
+ IntUartSet(minor, baud, databits, parity, stopbits, hwflow);
+ }
+
+return RTEMS_SUCCESSFUL;
+
+}
+
+/***************************************************************************
+ Function : IntUartInterruptHandler
+
+ Description : This is the interrupt handler for the internal uart. It
+ determines which channel caused the interrupt before queueing any received
+ chars and dequeueing chars waiting for transmission.
+ ***************************************************************************/
+static rtems_isr
+IntUartInterruptHandler(rtems_vector_number v)
+{
+ unsigned int chan = v - UART_INTC0_IRQ_VECTOR(0);
+ struct IntUartInfoStruct *info = &IntUartInfo[chan];
+
+ /* check to see if received data */
+ if ( MCF548X_PSC_ISR(chan) & MCF548X_PSC_ISR_RXRDY_FU )
+ {
+ /* read data and put into the receive buffer */
+ while ( MCF548X_PSC_SR(chan) & MCF548X_PSC_SR_RXRDY )
+ {
+
+ /* put data in rx buffer */
+ info->rx_buffer[info->rx_in] = *((volatile uint8_t *)&MCF548X_PSC_RB(chan));
+
+ /* check for errors */
+ if ( MCF548X_PSC_SR(chan) & MCF548X_PSC_SR_ERROR )
+ {
+ /* clear the error */
+ MCF548X_PSC_CR(chan) = MCF548X_PSC_CR_RESET_ERROR;
+ }
+
+ /* update buffer values */
+ info->rx_in++;
+
+ if ( info->rx_in >= RX_BUFFER_SIZE )
+ {
+ info->rx_in = 0;
+ }
+ }
+ /* Make sure the port has been opened */
+ if ( info->ttyp )
+ {
+
+ /* check to see if task driven */
+ if ( info->iomode == TERMIOS_TASK_DRIVEN )
+ {
+ /* notify rx task that rx buffer has data */
+ rtems_termios_rxirq_occured(info->ttyp);
+ }
+ else
+ {
+ /* Push up the received data */
+ rtems_termios_enqueue_raw_characters(info->ttyp, info->rx_buffer, info->rx_in);
+ info->rx_in = 0;
+ }
+ }
+ }
+
+ /* check to see if data needs to be transmitted */
+ if ( ( info->imr & MCF548X_PSC_IMR_TXRDY ) &&
+ ( MCF548X_PSC_ISR(chan) & MCF548X_PSC_ISR_TXRDY ) )
+ {
+
+ /* disable tx interrupts */
+ info->imr &= ~MCF548X_PSC_IMR_TXRDY;
+ MCF548X_PSC_IMR(chan) = info->imr;
+
+ /* tell upper level that character has been sent */
+ if ( info->ttyp )
+ rtems_termios_dequeue_characters(info->ttyp, 1);
+ }
+
+}
+
+/***************************************************************************
+ Function : IntUartInitialize
+
+ Description : This initialises the internal uart hardware for all
+ internal uarts. If the internal uart is to be interrupt driven then the
+ interrupt vectors are hooked.
+ ***************************************************************************/
+static void
+IntUartInitialize(void)
+{
+ unsigned int chan;
+ struct IntUartInfoStruct *info;
+ rtems_isr_entry old_handler;
+
+ for ( chan = 0; chan < MAX_UART_INFO; chan++ )
+ {
+ info = &IntUartInfo[chan];
+
+ info->ttyp = NULL;
+ info->rx_in = 0;
+ info->rx_out = 0;
+ info->baud = -1;
+ info->databits = -1;
+ info->parity = -1;
+ info->stopbits = -1;
+ info->hwflow = -1;
+
+ MCF548X_PSC_ACR(chan) = 0;
+ MCF548X_PSC_IMR(chan) = 0;
+ if ( info->iomode != TERMIOS_POLLED )
+ {
+ rtems_interrupt_catch (IntUartInterruptHandler,
+ UART_INTC0_IRQ_VECTOR(chan),
+ &old_handler);
+ }
+
+ /* set uart default values */
+ IntUartSetAttributes(chan, NULL);
+
+ /* unmask interrupt */
+ bsp_interrupt_vector_enable(MCF548X_IRQ_PSC(chan));
+ } /* of chan loop */
+
+ BSP_output_char = psc_output_char;
+} /* IntUartInitialise */
+
+/***************************************************************************
+ Function : IntUartInterruptWrite
+
+ Description : This writes a single character to the appropriate uart
+ channel. This is either called during an interrupt or in the user's task
+ to initiate a transmit sequence. Calling this routine enables Tx
+ interrupts.
+ ***************************************************************************/
+static ssize_t
+IntUartInterruptWrite (int minor, const char *buf, size_t len)
+{
+ if (len > 0) {
+ /* write out character */
+ *(volatile uint8_t *)(&MCF548X_PSC_TB(minor)) = *buf;
+
+ /* enable tx interrupt */
+ IntUartInfo[minor].imr |= MCF548X_PSC_IMR_TXRDY;
+ MCF548X_PSC_IMR(minor) = IntUartInfo[minor].imr;
+ }
+
+ return 0;
+}
+
+/***************************************************************************
+ Function : IntUartInterruptOpen
+
+ Description : This enables interrupts when the tty is opened.
+ ***************************************************************************/
+static int
+IntUartInterruptOpen(int major, int minor, void *arg)
+{
+ struct IntUartInfoStruct *info = &IntUartInfo[minor];
+
+ /* enable the uart */
+ MCF548X_PSC_CR(minor) = (MCF548X_PSC_CR_TX_ENABLED | MCF548X_PSC_CR_RX_ENABLED);
+
+ /* check to see if interrupts need to be enabled */
+ if ( info->iomode != TERMIOS_POLLED )
+ {
+ /* enable rx interrupts */
+ info->imr |= MCF548X_PSC_IMR_RXRDY_FU;
+ MCF548X_PSC_IMR(minor) = info->imr;
+ }
+
+ /* check to see if doing hardware flow control */
+ if ( info->hwflow )
+ {
+ /* assert the RTS line */
+ MCF548X_PSC_OPSET(minor) = MCF548X_PSC_OPSET_RTS;
+ }
+
+ return 0;
+}
+
+
+/***************************************************************************
+ Function : IntUartInterruptClose
+
+ Description : This disables interrupts when the tty is closed.
+ ***************************************************************************/
+static int
+IntUartInterruptClose(int major, int minor, void *arg)
+{
+ struct IntUartInfoStruct *info = &IntUartInfo[minor];
+
+ /* disable the interrupts and the uart */
+ MCF548X_PSC_IMR(minor) = 0;
+ MCF548X_PSC_CR(minor) = (MCF548X_PSC_CR_TX_ENABLED | MCF548X_PSC_CR_RX_ENABLED);
+
+ /* reset values */
+ info->ttyp = NULL;
+ info->imr = 0;
+ info->rx_in = 0;
+ info->rx_out = 0;
+
+ return 0;
+}
+
+/***************************************************************************
+ Function : IntUartTaskRead
+
+ Description : This reads all available characters from the internal uart
+ and places them into the termios buffer. The rx interrupts will be
+ re-enabled after all data has been read.
+ ***************************************************************************/
+static int
+IntUartTaskRead(int minor)
+{
+ char buffer[RX_BUFFER_SIZE];
+ int count;
+ int rx_in;
+ int index = 0;
+ struct IntUartInfoStruct *info = &IntUartInfo[minor];
+
+ /* determine number of values to copy out */
+ rx_in = info->rx_in;
+ if ( info->rx_out <= rx_in )
+ {
+ count = rx_in - info->rx_out;
+ }
+ else
+ {
+ count = (RX_BUFFER_SIZE - info->rx_out) + rx_in;
+ }
+
+ /* copy data into local buffer from rx buffer */
+ while ( ( index < count ) && ( index < RX_BUFFER_SIZE ) )
+ {
+ /* copy data byte */
+ buffer[index] = info->rx_buffer[info->rx_out];
+ index++;
+
+ /* increment rx buffer values */
+ info->rx_out++;
+ if ( info->rx_out >= RX_BUFFER_SIZE )
+ {
+ info->rx_out = 0;
+ }
+ }
+
+ /* check to see if buffer is not empty */
+ if ( count > 0 )
+ {
+ /* set characters into termios buffer */
+ rtems_termios_enqueue_raw_characters(info->ttyp, buffer, count);
+ }
+
+ return EOF;
+}
+
+
+/***************************************************************************
+ Function : IntUartPollRead
+
+ Description : This reads a character from the internal uart. It returns
+ to the caller without blocking if not character is waiting.
+ ***************************************************************************/
+static int
+IntUartPollRead (int minor)
+{
+if (!((MCF548X_PSC_SR(minor) & MCF548X_PSC_SR_RXRDY)))
+ return(-1);
+
+ return *((uint8_t *)&MCF548X_PSC_RB(minor));
+}
+
+
+/***************************************************************************
+ Function : IntUartPollWrite
+
+ Description : This writes out each character in the buffer to the
+ appropriate internal uart channel waiting till each one is sucessfully
+ transmitted.
+ ***************************************************************************/
+static ssize_t
+IntUartPollWrite (int minor, const char *buf, size_t len)
+{
+ size_t retval = len;
+/* loop over buffer */
+ while ( len-- )
+ {
+ /* block until we can transmit */
+ while (!((MCF548X_PSC_SR(minor) & MCF548X_PSC_SR_TXRDY)))
+ continue;
+ /* transmit data byte */
+ *((uint8_t *)&MCF548X_PSC_TB(minor)) = *buf++;
+ }
+ return retval;
+}
+
+/***************************************************************************
+ Function : console_initialize
+
+ Description : This initialises termios, both sets of uart hardware before
+ registering /dev/tty devices for each channel and the system /dev/console.
+ ***************************************************************************/
+rtems_device_driver console_initialize(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg )
+{
+ rtems_status_code status;
+
+
+ /* Set up TERMIOS */
+ rtems_termios_initialize ();
+
+ /* set io modes for the different channels and initialize device */
+ IntUartInfo[minor].iomode = TERMIOS_IRQ_DRIVEN; //TERMIOS_POLLED;
+ IntUartInitialize();
+
+ /* Register the console port */
+ status = rtems_io_register_name ("/dev/console", major, CONSOLE_PORT);
+ if ( status != RTEMS_SUCCESSFUL )
+ {
+ rtems_fatal_error_occurred (status);
+ }
+
+ /* Register the other port */
+ if ( CONSOLE_PORT != 0 )
+ {
+ status = rtems_io_register_name ("/dev/tty00", major, 0);
+ if ( status != RTEMS_SUCCESSFUL )
+ {
+ rtems_fatal_error_occurred (status);
+ }
+ }
+ if ( CONSOLE_PORT != 1 )
+ {
+ status = rtems_io_register_name ("/dev/tty01", major, 1);
+ if ( status != RTEMS_SUCCESSFUL )
+ {
+ rtems_fatal_error_occurred (status);
+ }
+ }
+
+ return(RTEMS_SUCCESSFUL);
+}
+
+/***************************************************************************
+ Function : console_open
+
+ Description : This actually opens the device depending on the minor
+ number set during initialisation. The device specific access routines are
+ passed to termios when the devices is opened depending on whether it is
+ polled or not.
+ ***************************************************************************/
+rtems_device_driver console_open(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg)
+{
+ rtems_status_code status = RTEMS_INVALID_NUMBER;
+ rtems_libio_open_close_args_t *args = (rtems_libio_open_close_args_t *)arg;
+ struct IntUartInfoStruct *info;
+
+ static const rtems_termios_callbacks IntUartPollCallbacks = {
+ NULL, /* firstOpen */
+ NULL, /* lastClose */
+ IntUartPollRead, /* pollRead */
+ IntUartPollWrite, /* write */
+ IntUartSetAttributes, /* setAttributes */
+ NULL, /* stopRemoteTx */
+ NULL, /* startRemoteTx */
+ TERMIOS_POLLED /* mode */
+ };
+ static const rtems_termios_callbacks IntUartIntrCallbacks = {
+ IntUartInterruptOpen, /* firstOpen */
+ IntUartInterruptClose, /* lastClose */
+ NULL, /* pollRead */
+ IntUartInterruptWrite, /* write */
+ IntUartSetAttributes, /* setAttributes */
+ NULL, /* stopRemoteTx */
+ NULL, /* startRemoteTx */
+ TERMIOS_IRQ_DRIVEN /* mode */
+ };
+
+ static const rtems_termios_callbacks IntUartTaskCallbacks = {
+ IntUartInterruptOpen, /* firstOpen */
+ IntUartInterruptClose, /* lastClose */
+ IntUartTaskRead, /* pollRead */
+ IntUartInterruptWrite, /* write */
+ IntUartSetAttributes, /* setAttributes */
+ NULL, /* stopRemoteTx */
+ NULL, /* startRemoteTx */
+ TERMIOS_TASK_DRIVEN /* mode */
+ };
+
+ /* open the port depending on the minor device number */
+ if ( ( minor >= 0 ) && ( minor < MAX_UART_INFO ) )
+ {
+ info = &IntUartInfo[minor];
+ switch ( info->iomode )
+ {
+ case TERMIOS_POLLED:
+ status = rtems_termios_open(major, minor, arg, &IntUartPollCallbacks);
+ break;
+ case TERMIOS_IRQ_DRIVEN:
+ status = rtems_termios_open(major, minor, arg, &IntUartIntrCallbacks);
+ info->ttyp = args->iop->data1;
+ break;
+ case TERMIOS_TASK_DRIVEN:
+ status = rtems_termios_open(major, minor, arg, &IntUartTaskCallbacks);
+ info->ttyp = args->iop->data1;
+ break;
+ }
+ }
+
+ return( status );
+}
+
+/***************************************************************************
+ Function : console_close
+
+ Description : This closes the device via termios
+ ***************************************************************************/
+rtems_device_driver console_close(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg)
+{
+ return(rtems_termios_close (arg));
+}
+
+/***************************************************************************
+ Function : console_read
+
+ Description : Read from the device via termios
+ ***************************************************************************/
+rtems_device_driver console_read(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg)
+{
+ return(rtems_termios_read (arg));
+}
+
+/***************************************************************************
+ Function : console_write
+
+ Description : Write to the device via termios
+ ***************************************************************************/
+rtems_device_driver console_write(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg)
+{
+ return(rtems_termios_write (arg));
+}
+
+/***************************************************************************
+ Function : console_ioctl
+
+ Description : Pass the IOCtl call to termios
+ ***************************************************************************/
+rtems_device_driver console_control(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg)
+{
+ return( rtems_termios_ioctl (arg) );
+}
diff --git a/bsps/m68k/mcf5206elite/console/console.c b/bsps/m68k/mcf5206elite/console/console.c
new file mode 100644
index 0000000000..bbf343d0f3
--- /dev/null
+++ b/bsps/m68k/mcf5206elite/console/console.c
@@ -0,0 +1,431 @@
+/*
+ * Console driver for Motorola MCF5206E UART modules
+ */
+
+/*
+ * Copyright (C) 2000 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Victor V. Vengerov <vvv@oktet.ru>
+ *
+ * COPYRIGHT (c) 1989-1998.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <termios.h>
+#include <bsp.h>
+#include <rtems/libio.h>
+#include <rtems/console.h>
+#include "mcf5206/mcf5206e.h"
+#include "mcf5206/mcfuart.h"
+
+/* Descriptor structures for two on-chip UART channels */
+static mcfuart uart[2];
+
+/* Console operations mode:
+ * 0 - raw (non-termios) polled input/output
+ * 1 - termios-based polled input/output
+ * 2 - termios-based interrupt-driven input/output
+ */
+int console_mode = 2;
+#define CONSOLE_MODE_RAW (0)
+#define CONSOLE_MODE_POLL (1)
+#define CONSOLE_MODE_INT (2)
+
+/* Wrapper functions for MCF UART generic driver */
+
+/* console_poll_read --
+ * wrapper for poll read function
+ *
+ * PARAMETERS:
+ * minor - minor device number
+ *
+ * RETURNS:
+ * character code readed from UART, or -1 if there is no characters
+ * available
+ */
+static int
+console_poll_read(int minor)
+{
+ return mcfuart_poll_read(&uart[minor]);
+}
+
+/* console_interrupt_write --
+ * wrapper for interrupt write function
+ *
+ * PARAMETERS:
+ * minor - minor device number
+ * buf - output buffer
+ * len - output buffer length
+ *
+ * RETURNS:
+ * result code
+ */
+static ssize_t
+console_interrupt_write(int minor, const char *buf, size_t len)
+{
+ return mcfuart_interrupt_write(&uart[minor], buf, len);
+}
+
+/* console_poll_write --
+ * wrapper for polling mode write function
+ *
+ * PARAMETERS:
+ * minor - minor device number
+ * buf - output buffer
+ * len - output buffer length
+ *
+ * RETURNS:
+ * result code
+ */
+static ssize_t
+console_poll_write(int minor, const char *buf, size_t len)
+{
+ return mcfuart_poll_write(&uart[minor], buf, len);
+}
+
+/* console_set_attributes --
+ * wrapper for hardware-dependent termios attributes setting
+ *
+ * PARAMETERS:
+ * minor - minor device number
+ * t - pointer to the termios structure
+ *
+ * RETURNS:
+ * result code
+ */
+static int
+console_set_attributes(int minor, const struct termios *t)
+{
+ return mcfuart_set_attributes(&uart[minor], t);
+}
+
+/* console_stop_remote_tx --
+ * wrapper for stopping data flow from remote party.
+ *
+ * PARAMETERS:
+ * minor - minor device number
+ *
+ * RETURNS:
+ * result code
+ */
+static int
+console_stop_remote_tx(int minor)
+{
+ if (minor < sizeof(uart)/sizeof(uart[0]))
+ return mcfuart_stop_remote_tx(&uart[minor]);
+ else
+ return RTEMS_INVALID_NUMBER;
+}
+
+/* console_start_remote_tx --
+ * wrapper for resuming data flow from remote party.
+ *
+ * PARAMETERS:
+ * minor - minor device number
+ *
+ */
+static int
+console_start_remote_tx(int minor)
+{
+ if (minor < sizeof(uart)/sizeof(uart[0]))
+ return mcfuart_start_remote_tx(&uart[minor]);
+ else
+ return RTEMS_INVALID_NUMBER;
+}
+
+/* console_first_open --
+ * wrapper for UART controller initialization functions
+ *
+ * PARAMETERS:
+ * major - major device number
+ * minor - minor device number
+ * arg - libio device open argument
+ *
+ * RETURNS:
+ * error code
+ */
+static int
+console_first_open(int major, int minor, void *arg)
+{
+ rtems_libio_open_close_args_t *args = arg;
+ rtems_status_code sc;
+ uint8_t intvec;
+
+ switch (minor) {
+ case 0: intvec = BSP_INTVEC_UART1; break;
+ case 1: intvec = BSP_INTVEC_UART2; break;
+ default:
+ return RTEMS_INVALID_NUMBER;
+ }
+
+ if (console_mode != CONSOLE_MODE_INT) {
+ intvec = 0;
+ }
+
+ sc = mcfuart_init(
+ &uart[minor], /* uart */
+ args->iop->data1, /* tty */
+ intvec, /* interrupt vector number */
+ minor+1);
+
+ if (sc == RTEMS_SUCCESSFUL)
+ sc = mcfuart_reset(&uart[minor]);
+
+ return sc;
+}
+
+/* console_last_close --
+ * wrapper for UART controller close function
+ *
+ * PARAMETERS:
+ * major - major device number
+ * minor - minor device number
+ * arg - libio device close argument
+ *
+ * RETURNS:
+ * error code
+ */
+static int
+console_last_close(int major, int minor, void *arg)
+{
+ return mcfuart_disable(&uart[minor]);
+}
+
+/* console_initialize --
+ * This routine initializes the console IO drivers and register devices
+ * in RTEMS I/O system.
+ *
+ * PARAMETERS:
+ * major - major console device number
+ * minor - minor console device number (not used)
+ * arg - device initialize argument
+ *
+ * RETURNS:
+ * RTEMS error code (RTEMS_SUCCESSFUL if device initialized successfuly)
+ */
+rtems_device_driver console_initialize(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg)
+{
+ rtems_status_code status;
+
+ /*
+ * Set up TERMIOS
+ */
+ if (console_mode != CONSOLE_MODE_RAW)
+ rtems_termios_initialize ();
+
+ /*
+ * Register the devices
+ */
+ status = rtems_io_register_name ("/dev/console", major, 0);
+ if (status != RTEMS_SUCCESSFUL)
+ rtems_fatal_error_occurred (status);
+
+ status = rtems_io_register_name ("/dev/aux", major, 1);
+ if (status != RTEMS_SUCCESSFUL)
+ rtems_fatal_error_occurred (status);
+
+ if (console_mode == CONSOLE_MODE_RAW) {
+ rtems_status_code sc;
+ sc = mcfuart_init(&uart[0], /* uart */
+ NULL, /* tty */
+ 0, /* interrupt vector number */
+ 1); /* UART channel number */
+
+ if (sc == RTEMS_SUCCESSFUL)
+ sc = mcfuart_reset(&uart[0]);
+
+ sc = mcfuart_init(&uart[1], /* uart */
+ NULL, /* tty */
+ 0, /* interrupt vector number */
+ 2); /* UART channel number */
+
+ if (sc == RTEMS_SUCCESSFUL)
+ sc = mcfuart_reset(&uart[1]);
+ return sc;
+ }
+
+ return RTEMS_SUCCESSFUL;
+}
+
+/* console_open --
+ * Open console device driver. Pass appropriate termios callback
+ * functions to termios library.
+ *
+ * PARAMETERS:
+ * major - major device number for console devices
+ * minor - minor device number for console
+ * arg - device opening argument
+ *
+ * RETURNS:
+ * RTEMS error code
+ */
+rtems_device_driver
+console_open(rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg)
+{
+ static const rtems_termios_callbacks intr_callbacks = {
+ console_first_open, /* firstOpen */
+ console_last_close, /* lastClose */
+ NULL, /* pollRead */
+ console_interrupt_write, /* write */
+ console_set_attributes, /* setAttributes */
+ console_stop_remote_tx, /* stopRemoteTx */
+ console_start_remote_tx, /* startRemoteTx */
+ 1 /* outputUsesInterrupts */
+ };
+ static const rtems_termios_callbacks poll_callbacks = {
+ console_first_open, /* firstOpen */
+ console_last_close, /* lastClose */
+ console_poll_read, /* pollRead */
+ console_poll_write, /* write */
+ console_set_attributes, /* setAttributes */
+ console_stop_remote_tx, /* stopRemoteTx */
+ console_start_remote_tx, /* startRemoteTx */
+ 0 /* outputUsesInterrupts */
+ };
+
+ switch (console_mode) {
+ case CONSOLE_MODE_RAW:
+ return RTEMS_SUCCESSFUL;
+
+ case CONSOLE_MODE_INT:
+ return rtems_termios_open(major, minor, arg, &intr_callbacks);
+
+ case CONSOLE_MODE_POLL:
+ return rtems_termios_open(major, minor, arg, &poll_callbacks);
+
+ default:
+ rtems_fatal_error_occurred(0xC07A1310);
+ }
+ return RTEMS_INTERNAL_ERROR;
+}
+
+/* console_close --
+ * Close console device.
+ *
+ * PARAMETERS:
+ * major - major device number for console devices
+ * minor - minor device number for console
+ * arg - device close argument
+ *
+ * RETURNS:
+ * RTEMS error code
+ */
+rtems_device_driver
+console_close(rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg)
+{
+ if (console_mode != CONSOLE_MODE_RAW)
+ return rtems_termios_close (arg);
+ else
+ return RTEMS_SUCCESSFUL;
+}
+
+/* console_read --
+ * Read from the console device
+ *
+ * PARAMETERS:
+ * major - major device number for console devices
+ * minor - minor device number for console
+ * arg - device read argument
+ *
+ * RETURNS:
+ * RTEMS error code
+ */
+rtems_device_driver
+console_read(rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg)
+{
+ if (console_mode != CONSOLE_MODE_RAW) {
+ return rtems_termios_read (arg);
+ } else {
+ rtems_libio_rw_args_t *argp = arg;
+ char *buf = argp->buffer;
+ int count = argp->count;
+ int n = 0;
+ int c;
+
+ while (n < count) {
+ do {
+ c = mcfuart_poll_read(&uart[minor]);
+ } while (c == -1);
+ if (c == '\r')
+ c = '\n';
+ *(buf++) = c;
+ n++;
+ if (c == '\n')
+ break;
+ }
+ argp->bytes_moved = n;
+ return RTEMS_SUCCESSFUL;
+ }
+}
+
+/* console_write --
+ * Write to the console device
+ *
+ * PARAMETERS:
+ * major - major device number for console devices
+ * minor - minor device number for console
+ * arg - device write argument
+ *
+ * RETURNS:
+ * RTEMS error code
+ */
+rtems_device_driver
+console_write(rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg
+)
+{
+ if (console_mode != CONSOLE_MODE_RAW) {
+ return rtems_termios_write (arg);
+ } else {
+ rtems_libio_rw_args_t *argp = arg;
+ char cr = '\r';
+ char *buf = argp->buffer;
+ int count = argp->count;
+ int i;
+
+ for (i = 0; i < count; i++) {
+ if (*buf == '\n')
+ mcfuart_poll_write(&uart[minor], &cr, 1);
+ mcfuart_poll_write(&uart[minor], buf, 1);
+ buf++;
+ }
+ argp->bytes_moved = count;
+ return RTEMS_SUCCESSFUL;
+ }
+}
+
+/* console_control --
+ * Handle console device I/O control (IOCTL)
+ *
+ * PARAMETERS:
+ * major - major device number for console devices
+ * minor - minor device number for console
+ * arg - device ioctl argument
+ *
+ * RETURNS:
+ * RTEMS error code
+ */
+rtems_device_driver
+console_control(rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg)
+{
+ if (console_mode != CONSOLE_MODE_RAW) {
+ return rtems_termios_ioctl (arg);
+ } else {
+ return RTEMS_SUCCESSFUL;
+ }
+}
diff --git a/bsps/m68k/mcf52235/console/console.c b/bsps/m68k/mcf52235/console/console.c
new file mode 100644
index 0000000000..c2b6e36bfa
--- /dev/null
+++ b/bsps/m68k/mcf52235/console/console.c
@@ -0,0 +1,656 @@
+ /*
+ * Multi UART console serial I/O.
+ *
+ * TO DO: Add DMA input/output
+ */
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <malloc.h>
+
+#include <rtems/libio.h>
+#include <rtems/console.h>
+#include <rtems/termiostypes.h>
+#include <bsp.h>
+
+#include <rtems/bspIo.h>
+
+#define UART_INTC0_IRQ_VECTOR(x) (64+13+(x))
+
+#define MCF_UART_USR_ERROR ( MCF_UART_USR_RB | \
+ MCF_UART_USR_FE | \
+ MCF_UART_USR_PE | \
+ MCF_UART_USR_OE )
+
+static ssize_t IntUartPollWrite(int minor, const char *buf, size_t len);
+static ssize_t IntUartInterruptWrite(int minor, const char *buf, size_t len);
+
+#define MAX_UART_INFO 3
+#define RX_BUFFER_SIZE 512
+
+struct IntUartInfoStruct
+{
+ int iomode;
+ volatile int uimr;
+ int baud;
+ int databits;
+ int parity;
+ int stopbits;
+ int hwflow;
+ int rx_in;
+ int rx_out;
+ char rx_buffer[RX_BUFFER_SIZE];
+ void *ttyp;
+};
+
+struct IntUartInfoStruct IntUartInfo[MAX_UART_INFO];
+
+/***************************************************************************
+ Function : IntUartSet
+
+ Description : This updates the hardware UART settings.
+ ***************************************************************************/
+static void
+IntUartSet(int minor, int baud, int databits, int parity, int stopbits,
+ int hwflow)
+{
+ int divisor;
+ uint32_t clock_speed;
+ uint8_t umr1 = 0;
+ uint8_t umr2 = 0;
+ struct IntUartInfoStruct *info = &IntUartInfo[minor];
+ int level;
+
+ rtems_interrupt_disable(level);
+
+ /* disable interrupts, clear RTS line, and disable the UARTS */
+ MCF_UART_UIMR(minor) = 0;
+ MCF_UART_UOP0(minor) = 1;
+ MCF_UART_UCR(minor) = (MCF_UART_UCR_TX_DISABLED | MCF_UART_UCR_RX_DISABLED);
+
+ /* save the current values */
+ info->uimr = 0;
+ info->baud = baud;
+ info->databits = databits;
+ info->parity = parity;
+ info->stopbits = stopbits;
+ info->hwflow = hwflow;
+
+ clock_speed = bsp_get_CPU_clock_speed();
+ /* determine the baud divisor value */
+ divisor = ((clock_speed) / (32 * baud));
+ if (divisor < 2)
+ divisor = 2;
+
+ /* check to see if doing hardware flow control */
+ if (hwflow) {
+ /* set hardware flow options */
+ umr1 |= MCF_UART_UMR_RXRTS;
+ umr2 |= MCF_UART_UMR_TXCTS;
+ }
+
+ /* determine the new umr values */
+ umr1 |= (parity | databits);
+ umr2 |= (stopbits);
+
+ /* reset the uart */
+ MCF_UART_UCR(minor) = MCF_UART_UCR_RESET_ERROR;
+ MCF_UART_UCR(minor) = MCF_UART_UCR_RESET_RX;
+ MCF_UART_UCR(minor) = MCF_UART_UCR_RESET_TX;
+
+ /* reset the uart mode register and update values */
+ MCF_UART_UCR(minor) = MCF_UART_UCR_RESET_MR;
+ MCF_UART_UMR(minor) = umr1;
+ MCF_UART_UMR(minor) = umr2;
+
+ /* set the baud rate values */
+ MCF_UART_UCSR(minor) =
+ (MCF_UART_UCSR_RCS_SYS_CLK | MCF_UART_UCSR_TCS_SYS_CLK);
+ MCF_UART_UBG1(minor) = (divisor & 0xff00) >> 8;
+ MCF_UART_UBG2(minor) = (divisor & 0x00ff);
+
+ /* enable the uart */
+ MCF_UART_UCR(minor) = (MCF_UART_UCR_TX_ENABLED | MCF_UART_UCR_RX_ENABLED);
+
+ /* check to see if interrupts need to be enabled */
+ if (info->iomode != TERMIOS_POLLED) {
+ /* enable rx interrupts */
+ info->uimr |= MCF_UART_UIMR_RXRDY_FU;
+ MCF_UART_UIMR(minor) = info->uimr;
+ }
+
+ /* check to see if doing hardware flow control */
+ if (hwflow) {
+ /* assert the RTS line */
+ MCF_UART_UOP1(minor) = 1;
+ }
+
+ rtems_interrupt_enable(level);
+
+}
+
+/***************************************************************************
+ Function : IntUartSetAttributes
+
+ Description : This provides the hardware-dependent portion of tcsetattr().
+ value and sets it. At the moment this just sets the baud rate.
+
+ Note: The highest baudrate is 115200 as this stays within
+ an error of +/- 5% at 25MHz processor clock
+ ***************************************************************************/
+static int IntUartSetAttributes(int minor, const struct termios *t)
+{
+ /* set default index values */
+ int baud = (int) 19200;
+ int databits = (int) MCF_UART_UMR_BC_8;
+ int parity = (int) MCF_UART_UMR_PM_NONE;
+ int stopbits = (int) MCF_UART_UMR_SB_STOP_BITS_1;
+ int hwflow = (int) 0;
+ struct IntUartInfoStruct *info = &IntUartInfo[minor];
+
+ /* check to see if input is valid */
+ if (t != (const struct termios *) 0) {
+ /* determine baud rate index */
+ baud = rtems_termios_baud_to_number(t->c_ospeed);
+
+ /* determine data bits */
+ switch (t->c_cflag & CSIZE) {
+ case CS5:
+ databits = (int) MCF_UART_UMR_BC_5;
+ break;
+ case CS6:
+ databits = (int) MCF_UART_UMR_BC_6;
+ break;
+ case CS7:
+ databits = (int) MCF_UART_UMR_BC_7;
+ break;
+ case CS8:
+ databits = (int) MCF_UART_UMR_BC_8;
+ break;
+ }
+
+ /* determine if parity is enabled */
+ if (t->c_cflag & PARENB) {
+ if (t->c_cflag & PARODD) {
+ /* odd parity */
+ parity = (int) MCF_UART_UMR_PM_ODD;
+ } else {
+ /* even parity */
+ parity = (int) MCF_UART_UMR_PM_EVEN;
+ }
+ }
+
+ /* determine stop bits */
+ if (t->c_cflag & CSTOPB) {
+ /* two stop bits */
+ stopbits = (int) MCF_UART_UMR_SB_STOP_BITS_2;
+ }
+
+ /* check to see if hardware flow control */
+ if (t->c_cflag & CRTSCTS) {
+ hwflow = 1;
+ }
+ }
+
+ /* check to see if values have changed */
+ if ((baud != info->baud) ||
+ (databits != info->databits) ||
+ (parity != info->parity) ||
+ (stopbits != info->stopbits) || (hwflow != info->hwflow)) {
+
+ /* call function to set values */
+ IntUartSet(minor, baud, databits, parity, stopbits, hwflow);
+ }
+
+ return (RTEMS_SUCCESSFUL);
+
+}
+
+/***************************************************************************
+ Function : IntUartInterruptHandler
+
+ Description : This is the interrupt handler for the internal uart. It
+ determines which channel caused the interrupt before queueing any received
+ chars and dequeueing chars waiting for transmission.
+ ***************************************************************************/
+static rtems_isr IntUartInterruptHandler(rtems_vector_number v)
+{
+ unsigned int chan = v - UART_INTC0_IRQ_VECTOR(0);
+ struct IntUartInfoStruct *info = &IntUartInfo[chan];
+
+ /* check to see if received data */
+ if (MCF_UART_UISR(chan) & MCF_UART_UISR_RXRDY_FU) {
+ /* read data and put into the receive buffer */
+ while (MCF_UART_USR(chan) & MCF_UART_USR_RXRDY) {
+
+ if (MCF_UART_USR(chan) & MCF_UART_USR_ERROR) {
+ /* clear the error */
+ MCF_UART_UCR(chan) = MCF_UART_UCR_RESET_ERROR;
+ }
+ /* put data in rx buffer and check for errors */
+ info->rx_buffer[info->rx_in] = MCF_UART_URB(chan);
+
+ /* update buffer values */
+ info->rx_in++;
+
+ if (info->rx_in >= RX_BUFFER_SIZE) {
+ info->rx_in = 0;
+ }
+ }
+ /* Make sure the port has been opened */
+ if (info->ttyp) {
+
+ /* check to see if task driven */
+ if (info->iomode == TERMIOS_TASK_DRIVEN) {
+ /* notify rx task that rx buffer has data */
+ rtems_termios_rxirq_occured(info->ttyp);
+ } else {
+ /* Push up the received data */
+ rtems_termios_enqueue_raw_characters(info->ttyp, info->rx_buffer,
+ info->rx_in);
+ info->rx_in = 0;
+ }
+ }
+ }
+
+ /* check to see if data needs to be transmitted */
+ if ((info->uimr & MCF_UART_UIMR_TXRDY) &&
+ (MCF_UART_UISR(chan) & MCF_UART_UISR_TXRDY)) {
+
+ /* disable tx interrupts */
+ info->uimr &= ~MCF_UART_UIMR_TXRDY;
+ MCF_UART_UIMR(chan) = info->uimr;
+
+ /* tell upper level that character has been sent */
+ if (info->ttyp)
+ rtems_termios_dequeue_characters(info->ttyp, 1);
+ }
+}
+
+/***************************************************************************
+ Function : IntUartInitialize
+
+ Description : This initialises the internal uart hardware for all
+ internal uarts. If the internal uart is to be interrupt driven then the
+ interrupt vectors are hooked.
+ ***************************************************************************/
+static void IntUartInitialize(void)
+{
+ unsigned int chan;
+ struct IntUartInfoStruct *info;
+ rtems_isr_entry old_handler;
+ int level;
+
+ for (chan = 0; chan < MAX_UART_INFO; chan++) {
+ info = &IntUartInfo[chan];
+
+ info->ttyp = NULL;
+ info->rx_in = 0;
+ info->rx_out = 0;
+ info->baud = -1;
+ info->databits = -1;
+ info->parity = -1;
+ info->stopbits = -1;
+ info->hwflow = -1;
+ info->iomode = TERMIOS_POLLED; /*polled console io */
+
+ MCF_UART_UACR(chan) = 0;
+ MCF_UART_UIMR(chan) = 0;
+ if (info->iomode != TERMIOS_POLLED) {
+ rtems_interrupt_catch(IntUartInterruptHandler,
+ UART_INTC0_IRQ_VECTOR(chan), &old_handler);
+ }
+
+ /* set uart default values */
+ IntUartSetAttributes(chan, NULL);
+
+ /* unmask interrupt */
+ rtems_interrupt_disable(level);
+ switch (chan) {
+ case 0:
+ MCF_INTC0_ICR13 = MCF_INTC_ICR_IL(UART0_IRQ_LEVEL) |
+ MCF_INTC_ICR_IP(UART0_IRQ_PRIORITY);
+ MCF_INTC0_IMRL &= ~(MCF_INTC_IMRL_MASK13 | MCF_INTC_IMRL_MASKALL);
+ break;
+
+ case 1:
+ MCF_INTC0_ICR14 = MCF_INTC_ICR_IL(UART1_IRQ_LEVEL) |
+ MCF_INTC_ICR_IP(UART1_IRQ_PRIORITY);
+ MCF_INTC0_IMRL &= ~(MCF_INTC_IMRL_MASK14 | MCF_INTC_IMRL_MASKALL);
+ break;
+
+ case 2:
+ MCF_INTC0_ICR15 = MCF_INTC_ICR_IL(UART2_IRQ_LEVEL) |
+ MCF_INTC_ICR_IP(UART2_IRQ_PRIORITY);
+ MCF_INTC0_IMRL &= ~(MCF_INTC_IMRL_MASK15 | MCF_INTC_IMRL_MASKALL);
+ break;
+ }
+ rtems_interrupt_enable(level);
+
+ } /* of chan loop */
+
+} /* IntUartInitialise */
+
+/***************************************************************************
+ Function : IntUartInterruptWrite
+
+ Description : This writes a single character to the appropriate uart
+ channel. This is either called during an interrupt or in the user's task
+ to initiate a transmit sequence. Calling this routine enables Tx
+ interrupts.
+ ***************************************************************************/
+static ssize_t IntUartInterruptWrite(int minor, const char *buf, size_t len)
+{
+ if (len > 0) {
+ /* write out character */
+ MCF_UART_UTB(minor) = *buf;
+
+ /* enable tx interrupt */
+ IntUartInfo[minor].uimr |= MCF_UART_UIMR_TXRDY;
+ MCF_UART_UIMR(minor) = IntUartInfo[minor].uimr;
+ }
+
+ return (0);
+}
+
+/***************************************************************************
+ Function : IntUartInterruptOpen
+
+ Description : This enables interrupts when the tty is opened.
+ ***************************************************************************/
+static int IntUartInterruptOpen(int major, int minor, void *arg)
+{
+ struct IntUartInfoStruct *info = &IntUartInfo[minor];
+
+ /* enable the uart */
+ MCF_UART_UCR(minor) = (MCF_UART_UCR_TX_ENABLED | MCF_UART_UCR_RX_ENABLED);
+
+ /* check to see if interrupts need to be enabled */
+ if (info->iomode != TERMIOS_POLLED) {
+ /* enable rx interrupts */
+ info->uimr |= MCF_UART_UIMR_RXRDY_FU;
+ MCF_UART_UIMR(minor) = info->uimr;
+ }
+
+ /* check to see if doing hardware flow control */
+ if (info->hwflow) {
+ /* assert the RTS line */
+ MCF_UART_UOP1(minor) = 1;
+ }
+
+ return (0);
+}
+
+/***************************************************************************
+ Function : IntUartInterruptClose
+
+ Description : This disables interrupts when the tty is closed.
+ ***************************************************************************/
+static int IntUartInterruptClose(int major, int minor, void *arg)
+{
+ struct IntUartInfoStruct *info = &IntUartInfo[minor];
+
+ /* disable the interrupts and the uart */
+ MCF_UART_UIMR(minor) = 0;
+ MCF_UART_UCR(minor) = (MCF_UART_UCR_TX_DISABLED | MCF_UART_UCR_RX_DISABLED);
+
+ /* reset values */
+ info->ttyp = NULL;
+ info->uimr = 0;
+ info->rx_in = 0;
+ info->rx_out = 0;
+
+ return (0);
+}
+
+/***************************************************************************
+ Function : IntUartTaskRead
+
+ Description : This reads all available characters from the internal uart
+ and places them into the termios buffer. The rx interrupts will be
+ re-enabled after all data has been read.
+ ***************************************************************************/
+static int IntUartTaskRead(int minor)
+{
+ char buffer[RX_BUFFER_SIZE];
+ int count;
+ int rx_in;
+ int index = 0;
+ struct IntUartInfoStruct *info = &IntUartInfo[minor];
+
+ /* determine number of values to copy out */
+ rx_in = info->rx_in;
+ if (info->rx_out <= rx_in) {
+ count = rx_in - info->rx_out;
+ } else {
+ count = (RX_BUFFER_SIZE - info->rx_out) + rx_in;
+ }
+
+ /* copy data into local buffer from rx buffer */
+ while ((index < count) && (index < RX_BUFFER_SIZE)) {
+ /* copy data byte */
+ buffer[index] = info->rx_buffer[info->rx_out];
+ index++;
+
+ /* increment rx buffer values */
+ info->rx_out++;
+ if (info->rx_out >= RX_BUFFER_SIZE) {
+ info->rx_out = 0;
+ }
+ }
+
+ /* check to see if buffer is not empty */
+ if (count > 0) {
+ /* set characters into termios buffer */
+ rtems_termios_enqueue_raw_characters(info->ttyp, buffer, count);
+ }
+
+ return (EOF);
+}
+
+/***************************************************************************
+ Function : IntUartPollRead
+
+ Description : This reads a character from the internal uart. It returns
+ to the caller without blocking if not character is waiting.
+ ***************************************************************************/
+static int IntUartPollRead(int minor)
+{
+ if ((MCF_UART_USR(minor) & MCF_UART_USR_RXRDY) == 0)
+ return (-1);
+
+ return (MCF_UART_URB(minor));
+}
+
+/***************************************************************************
+ Function : IntUartPollWrite
+
+ Description : This writes out each character in the buffer to the
+ appropriate internal uart channel waiting till each one is sucessfully
+ transmitted.
+ ***************************************************************************/
+static ssize_t IntUartPollWrite(int minor, const char *buf, size_t len)
+{
+ size_t retval = len;
+ /* loop over buffer */
+ while (len--) {
+ /* block until we can transmit */
+ while ((MCF_UART_USR(minor) & MCF_UART_USR_TXRDY) == 0)
+ continue;
+ /* transmit data byte */
+ MCF_UART_UTB(minor) = *buf++;
+ }
+ return retval;
+}
+
+/***************************************************************************
+ Function : console_initialize
+
+ Description : This initialises termios, both sets of uart hardware before
+ registering /dev/tty devices for each channel and the system /dev/console.
+ ***************************************************************************/
+rtems_device_driver console_initialize(rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg)
+{
+ rtems_status_code status;
+
+ /* Set up TERMIOS */
+ rtems_termios_initialize();
+
+ /* set io modes for the different channels and initialize device */
+ IntUartInfo[minor].iomode = TERMIOS_IRQ_DRIVEN;
+ IntUartInitialize();
+
+ /* Register the console port */
+ status = rtems_io_register_name("/dev/console", major, CONSOLE_PORT);
+ if (status != RTEMS_SUCCESSFUL) {
+ rtems_fatal_error_occurred(status);
+ }
+
+ /* Register the other port */
+ if (CONSOLE_PORT != 0) {
+ status = rtems_io_register_name("/dev/tty00", major, 0);
+ if (status != RTEMS_SUCCESSFUL) {
+ rtems_fatal_error_occurred(status);
+ }
+ }
+ if (CONSOLE_PORT != 1) {
+ status = rtems_io_register_name("/dev/tty01", major, 1);
+ if (status != RTEMS_SUCCESSFUL) {
+ rtems_fatal_error_occurred(status);
+ }
+ }
+
+ return (RTEMS_SUCCESSFUL);
+}
+
+/***************************************************************************
+ Function : console_open
+
+ Description : This actually opens the device depending on the minor
+ number set during initialisation. The device specific access routines are
+ passed to termios when the devices is opened depending on whether it is
+ polled or not.
+ ***************************************************************************/
+rtems_device_driver console_open(rtems_device_major_number major,
+ rtems_device_minor_number minor, void *arg)
+{
+ rtems_status_code status = RTEMS_INVALID_NUMBER;
+ rtems_libio_open_close_args_t *args = (rtems_libio_open_close_args_t *) arg;
+ struct IntUartInfoStruct *info;
+
+ static const rtems_termios_callbacks IntUartPollCallbacks = {
+ NULL, /* firstOpen */
+ NULL, /* lastClose */
+ IntUartPollRead, /* pollRead */
+ IntUartPollWrite, /* write */
+ IntUartSetAttributes, /* setAttributes */
+ NULL, /* stopRemoteTx */
+ NULL, /* startRemoteTx */
+ TERMIOS_POLLED /* mode */
+ };
+ static const rtems_termios_callbacks IntUartIntrCallbacks = {
+ IntUartInterruptOpen, /* firstOpen */
+ IntUartInterruptClose, /* lastClose */
+ NULL, /* pollRead */
+ IntUartInterruptWrite, /* write */
+ IntUartSetAttributes, /* setAttributes */
+ NULL, /* stopRemoteTx */
+ NULL, /* startRemoteTx */
+ TERMIOS_IRQ_DRIVEN /* mode */
+ };
+
+ static const rtems_termios_callbacks IntUartTaskCallbacks = {
+ IntUartInterruptOpen, /* firstOpen */
+ IntUartInterruptClose, /* lastClose */
+ IntUartTaskRead, /* pollRead */
+ IntUartInterruptWrite, /* write */
+ IntUartSetAttributes, /* setAttributes */
+ NULL, /* stopRemoteTx */
+ NULL, /* startRemoteTx */
+ TERMIOS_TASK_DRIVEN /* mode */
+ };
+
+ /* open the port depending on the minor device number */
+ if ((minor >= 0) && (minor < MAX_UART_INFO)) {
+ info = &IntUartInfo[minor];
+ switch (info->iomode) {
+ case TERMIOS_POLLED:
+ status = rtems_termios_open(major, minor, arg, &IntUartPollCallbacks);
+ break;
+ case TERMIOS_IRQ_DRIVEN:
+ status = rtems_termios_open(major, minor, arg, &IntUartIntrCallbacks);
+ info->ttyp = args->iop->data1;
+ break;
+ case TERMIOS_TASK_DRIVEN:
+ status = rtems_termios_open(major, minor, arg, &IntUartTaskCallbacks);
+ info->ttyp = args->iop->data1;
+ break;
+ }
+ }
+
+ if (status == RTEMS_SUCCESSFUL) {
+ /*
+ * Reset the default baudrate.
+ */
+ struct termios term;
+
+ if (tcgetattr(STDIN_FILENO, &term) >= 0) {
+ term.c_cflag &= ~(CSIZE);
+ term.c_cflag |= CS8;
+ term.c_ispeed = B19200;
+ term.c_ospeed = B19200;
+ tcsetattr(STDIN_FILENO, TCSANOW, &term);
+ }
+ }
+
+ return (status);
+}
+
+/***************************************************************************
+ Function : console_close
+
+ Description : This closes the device via termios
+ ***************************************************************************/
+rtems_device_driver console_close(rtems_device_major_number major,
+ rtems_device_minor_number minor, void *arg)
+{
+ return (rtems_termios_close(arg));
+}
+
+/******************
+*********************************************************
+ Function : console_read
+
+ Description : Read from the device via termios
+ ***************************************************************************/
+rtems_device_driver console_read(rtems_device_major_number major,
+ rtems_device_minor_number minor, void *arg)
+{
+ return (rtems_termios_read(arg));
+}
+
+/***************************************************************************
+ Function : console_write
+
+ Description : Write to the device via termios
+ ***************************************************************************/
+rtems_device_driver console_write(rtems_device_major_number major,
+ rtems_device_minor_number minor, void *arg)
+{
+ return (rtems_termios_write(arg));
+}
+
+/***************************************************************************
+ Function : console_ioctl
+
+ Description : Pass the IOCtl call to termios
+ ***************************************************************************/
+rtems_device_driver console_control(rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg)
+{
+ return (rtems_termios_ioctl(arg));
+}
diff --git a/bsps/m68k/mcf52235/console/debugio.c b/bsps/m68k/mcf52235/console/debugio.c
new file mode 100644
index 0000000000..1fbf4b09d7
--- /dev/null
+++ b/bsps/m68k/mcf52235/console/debugio.c
@@ -0,0 +1,32 @@
+ /*
+ * Multi UART console serial I/O.
+ *
+ * TO DO: Add DMA input/output
+ */
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <rtems/libio.h>
+#include <rtems/termiostypes.h>
+#include <termios.h>
+#include <bsp.h>
+#include <malloc.h>
+
+#include <rtems/bspIo.h>
+
+static void _BSP_null_char(char c)
+{
+ int level;
+
+ rtems_interrupt_disable(level);
+ while ((MCF_UART_USR(CONSOLE_PORT) & MCF_UART_USR_TXRDY) == 0)
+ continue;
+ MCF_UART_UTB(CONSOLE_PORT) = c;
+ while ((MCF_UART_USR(CONSOLE_PORT) & MCF_UART_USR_TXRDY) == 0)
+ continue;
+ rtems_interrupt_enable(level);
+}
+
+BSP_output_char_function_type BSP_output_char = _BSP_null_char;
+BSP_polling_getchar_function_type BSP_poll_char = NULL;
+
diff --git a/bsps/m68k/mcf5225x/console/console.c b/bsps/m68k/mcf5225x/console/console.c
new file mode 100644
index 0000000000..9e36e3945a
--- /dev/null
+++ b/bsps/m68k/mcf5225x/console/console.c
@@ -0,0 +1,689 @@
+/*
+ * Multi UART console serial I/O.
+ *
+ * TO DO: Add DMA input/output
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <malloc.h>
+
+#include <rtems/libio.h>
+#include <rtems/termiostypes.h>
+#include <rtems/console.h>
+#include <rtems/bspIo.h>
+#include <bsp.h>
+
+#define UART_INTC0_IRQ_VECTOR(x) (64+13+(x))
+
+#define MCF_UART_USR_ERROR ( MCF_UART_USR_RB | \
+ MCF_UART_USR_FE | \
+ MCF_UART_USR_PE | \
+ MCF_UART_USR_OE )
+
+static ssize_t IntUartPollWrite(int minor, const char *buf, size_t len);
+static ssize_t IntUartInterruptWrite(int minor, const char *buf, size_t len);
+
+#define MAX_UART_INFO 3
+#define RX_BUFFER_SIZE 512
+
+struct IntUartInfoStruct
+{
+ int iomode;
+ volatile int uimr;
+ int baud;
+ int databits;
+ int parity;
+ int stopbits;
+ int hwflow;
+ int rx_in;
+ int rx_out;
+ char rx_buffer[RX_BUFFER_SIZE];
+ void *ttyp;
+};
+
+struct IntUartInfoStruct IntUartInfo[MAX_UART_INFO];
+
+/***************************************************************************
+ Function : IntUartSet
+
+ Description : This updates the hardware UART settings.
+ ***************************************************************************/
+static void
+IntUartSet(int minor, int baud, int databits, int parity, int stopbits,
+ int hwflow)
+{
+ int divisor;
+ uint32_t clock_speed;
+ uint8_t umr1 = 0;
+ uint8_t umr2 = 0;
+ struct IntUartInfoStruct *info = &IntUartInfo[minor];
+ rtems_interrupt_level level=UART0_IRQ_LEVEL;
+
+ rtems_interrupt_disable(level);
+
+ /* disable interrupts, clear RTS line, and disable the UARTS */
+ MCF_UART_UIMR(minor) = 0;
+ MCF_UART_UOP0(minor) = 1;
+ MCF_UART_UCR(minor) = (MCF_UART_UCR_TX_DISABLED | MCF_UART_UCR_RX_DISABLED);
+
+ /* save the current values */
+ info->uimr = 0;
+ info->baud = baud;
+ info->databits = databits;
+ info->parity = parity;
+ info->stopbits = stopbits;
+ info->hwflow = hwflow;
+
+ clock_speed = bsp_get_CPU_clock_speed();
+ /* determine the baud divisor value */
+ divisor = ((clock_speed) / (32 * baud));
+ if (divisor < 2)
+ divisor = 2;
+
+ /* check to see if doing hardware flow control */
+ if (hwflow) {
+ /* set hardware flow options */
+ umr1 |= MCF_UART_UMR_RXRTS;
+ umr2 |= MCF_UART_UMR_TXCTS;
+ }
+
+ /* determine the new umr values */
+ umr1 |= (parity | databits);
+
+#if 1 /* TZN: maybe needed for santec bus modul handling */
+ if (minor==STATIONS_PORT)
+ umr2 |= (stopbits) | 0x20; /* 0x20 ... set TXRTS just4testing */
+ else
+ umr2 |= (stopbits);
+#else
+ umr2 |= (stopbits);
+#endif
+
+ /* reset the uart */
+ MCF_UART_UCR(minor) = MCF_UART_UCR_RESET_ERROR;
+ MCF_UART_UCR(minor) = MCF_UART_UCR_RESET_RX;
+ MCF_UART_UCR(minor) = MCF_UART_UCR_RESET_TX;
+
+ /* reset the uart mode register and update values */
+ MCF_UART_UCR(minor) = MCF_UART_UCR_RESET_MR;
+ MCF_UART_UMR(minor) = umr1;
+ MCF_UART_UMR(minor) = umr2;
+
+ /* set the baud rate values */
+ MCF_UART_UCSR(minor) =
+ (MCF_UART_UCSR_RCS_SYS_CLK | MCF_UART_UCSR_TCS_SYS_CLK);
+ MCF_UART_UBG1(minor) = (divisor & 0xff00) >> 8;
+ MCF_UART_UBG2(minor) = (divisor & 0x00ff);
+
+ /* enable the uart */
+ MCF_UART_UCR(minor) = (MCF_UART_UCR_TX_ENABLED | MCF_UART_UCR_RX_ENABLED);
+
+ /* check to see if interrupts need to be enabled */
+ if (info->iomode != TERMIOS_POLLED) {
+ /* enable rx interrupts */
+ info->uimr |= MCF_UART_UIMR_RXRDY_FU;
+ MCF_UART_UIMR(minor) = info->uimr;
+ }
+
+ /* check to see if doing hardware flow control */
+ if (hwflow) {
+ /* assert the RTS line */
+ MCF_UART_UOP1(minor) = 1;
+ }
+
+ if (minor==STATIONS_PORT) //maybe needed for santec handling
+ MCF_UART_UOP0(minor) = 1;
+
+ rtems_interrupt_enable(level);
+
+}
+
+/***************************************************************************
+ Function : IntUartSetAttributes
+
+ Description : This provides the hardware-dependent portion of tcsetattr().
+ value and sets it. At the moment this just sets the baud rate.
+
+ Note: The highest baudrate is 115200 as this stays within
+ an error of +/- 5% at 25MHz processor clock
+ ***************************************************************************/
+static int IntUartSetAttributes(int minor, const struct termios *t)
+{
+ /* set default index values */
+ int baud = (int) 19200;
+ int databits = (int) MCF_UART_UMR_BC_8;
+ int parity = (int) MCF_UART_UMR_PM_NONE;
+ int stopbits = (int) MCF_UART_UMR_SB_STOP_BITS_1;
+ int hwflow = (int) 0;
+ struct IntUartInfoStruct *info = &IntUartInfo[minor];
+
+ /* check to see if input is valid */
+ if (t != (const struct termios *) 0) {
+ /* determine baud rate index */
+ baud = rtems_termios_baud_to_number(t->c_ospeed);
+
+ /* determine data bits */
+ switch (t->c_cflag & CSIZE) {
+ case CS5:
+ databits = (int) MCF_UART_UMR_BC_5;
+ break;
+ case CS6:
+ databits = (int) MCF_UART_UMR_BC_6;
+ break;
+ case CS7:
+ databits = (int) MCF_UART_UMR_BC_7;
+ break;
+ case CS8:
+ databits = (int) MCF_UART_UMR_BC_8;
+ break;
+ }
+
+ /* determine if parity is enabled */
+ if (t->c_cflag & PARENB) {
+ if (t->c_cflag & PARODD) {
+ /* odd parity */
+ parity = (int) MCF_UART_UMR_PM_ODD;
+ } else {
+ /* even parity */
+ parity = (int) MCF_UART_UMR_PM_EVEN;
+ }
+ }
+
+ /* determine stop bits */
+ if (t->c_cflag & CSTOPB) {
+ /* two stop bits */
+ stopbits = (int) MCF_UART_UMR_SB_STOP_BITS_2;
+ }
+
+ /* check to see if hardware flow control */
+ if (t->c_cflag & CRTSCTS) {
+ hwflow = 1;
+ }
+ }
+
+ /* check to see if values have changed */
+ if ((baud != info->baud) ||
+ (databits != info->databits) ||
+ (parity != info->parity) ||
+ (stopbits != info->stopbits) || (hwflow != info->hwflow)) {
+
+ /* call function to set values */
+ IntUartSet(minor, baud, databits, parity, stopbits, hwflow);
+ }
+
+ return (RTEMS_SUCCESSFUL);
+
+}
+
+/***************************************************************************
+ Function : IntUartInterruptHandler
+
+ Description : This is the interrupt handler for the internal uart. It
+ determines which channel caused the interrupt before queueing any received
+ chars and dequeueing chars waiting for transmission.
+ ***************************************************************************/
+static rtems_isr IntUartInterruptHandler(rtems_vector_number v)
+{
+ unsigned int chan = v - UART_INTC0_IRQ_VECTOR(0);
+ struct IntUartInfoStruct *info = &IntUartInfo[chan];
+
+
+ /* check to see if received data */
+ if (MCF_UART_UISR(chan) & MCF_UART_UISR_RXRDY_FU) {
+
+#if 0 /* TZN ... just4testing */
+ if (MCF_GPIO_PORTTC&MCF_GPIO_PORTTC_PORTTC0)
+ MCF_GPIO_PORTTC &= ~MCF_GPIO_PORTTC_PORTTC0;
+ else
+ MCF_GPIO_PORTTC |= MCF_GPIO_PORTTC_PORTTC0;
+#endif
+
+ /* read data and put into the receive buffer */
+ while (MCF_UART_USR(chan) & MCF_UART_USR_RXRDY) {
+
+ if (MCF_UART_USR(chan) & MCF_UART_USR_ERROR) {
+ /* clear the error */
+ MCF_UART_UCR(chan) = MCF_UART_UCR_RESET_ERROR;
+ }
+ /* put data in rx buffer and check for errors */
+ info->rx_buffer[info->rx_in] = MCF_UART_URB(chan);
+
+ /* update buffer values */
+ info->rx_in++;
+
+ if (info->rx_in >= RX_BUFFER_SIZE) {
+ info->rx_in = 0;
+ }
+ }
+ /* Make sure the port has been opened */
+ if (info->ttyp) {
+
+ /* check to see if task driven */
+ if (info->iomode == TERMIOS_TASK_DRIVEN) {
+ /* notify rx task that rx buffer has data */
+ rtems_termios_rxirq_occured(info->ttyp);
+ } else {
+ /* Push up the received data */
+ rtems_termios_enqueue_raw_characters(info->ttyp, info->rx_buffer,
+ info->rx_in);
+ info->rx_in = 0;
+ }
+ }
+ }
+
+ /* check to see if data needs to be transmitted */
+ if ((info->uimr & MCF_UART_UIMR_TXRDY) &&
+ (MCF_UART_UISR(chan) & MCF_UART_UISR_TXRDY)) {
+
+ /* disable tx interrupts */
+ info->uimr &= ~MCF_UART_UIMR_TXRDY;
+ MCF_UART_UIMR(chan) = info->uimr;
+
+ /* tell upper level that character has been sent */
+ if (info->ttyp)
+ rtems_termios_dequeue_characters(info->ttyp, 1);
+ }
+}
+
+/***************************************************************************
+ Function : IntUartInitialize
+
+ Description : This initialises the internal uart hardware for all
+ internal uarts. If the internal uart is to be interrupt driven then the
+ interrupt vectors are hooked.
+ ***************************************************************************/
+static void IntUartInitialize(void)
+{
+ unsigned int chan;
+ struct IntUartInfoStruct *info;
+ rtems_isr_entry old_handler;
+ rtems_interrupt_level level=UART0_IRQ_LEVEL;
+
+ for (chan = 0; chan < MAX_UART_INFO; chan++) {
+ info = &IntUartInfo[chan];
+
+ info->ttyp = NULL;
+ info->rx_in = 0;
+ info->rx_out = 0;
+ info->baud = -1;
+ info->databits = -1;
+ info->parity = -1;
+ info->stopbits = -1;
+ info->hwflow = -1;
+ info->iomode = TERMIOS_IRQ_DRIVEN; /*TZN, irq driven console io */
+ //info->iomode = TERMIOS_POLLED; /*TZN, just4testint, use polling mode for all UARTS */
+
+ MCF_UART_UACR(chan) = 0;
+ MCF_UART_UIMR(chan) = 0;
+ if (info->iomode != TERMIOS_POLLED) {
+ rtems_interrupt_catch(IntUartInterruptHandler,
+ UART_INTC0_IRQ_VECTOR(chan), &old_handler);
+ }
+
+ /* set uart default values */
+ IntUartSetAttributes(chan, NULL);
+
+ /* unmask interrupt */
+ rtems_interrupt_disable(level);
+ switch (chan) {
+ case 0:
+ MCF_INTC0_ICR13 = MCF_INTC_ICR_IL(UART0_IRQ_LEVEL) |
+ MCF_INTC_ICR_IP(UART0_IRQ_PRIORITY);
+ MCF_INTC0_IMRL &= ~(MCF_INTC_IMRL_MASK13 | MCF_INTC_IMRL_MASKALL);
+ break;
+
+ case 1:
+ MCF_INTC0_ICR14 = MCF_INTC_ICR_IL(UART1_IRQ_LEVEL) |
+ MCF_INTC_ICR_IP(UART1_IRQ_PRIORITY);
+ MCF_INTC0_IMRL &= ~(MCF_INTC_IMRL_MASK14 | MCF_INTC_IMRL_MASKALL);
+ break;
+
+ case 2:
+ MCF_INTC0_ICR15 = MCF_INTC_ICR_IL(UART2_IRQ_LEVEL) |
+ MCF_INTC_ICR_IP(UART2_IRQ_PRIORITY);
+ MCF_INTC0_IMRL &= ~(MCF_INTC_IMRL_MASK15 | MCF_INTC_IMRL_MASKALL);
+ break;
+ }
+ rtems_interrupt_enable(level);
+
+ } /* of chan loop */
+
+} /* IntUartInitialise */
+
+/***************************************************************************
+ Function : IntUartInterruptWrite
+
+ Description : This writes a single character to the appropriate uart
+ channel. This is either called during an interrupt or in the user's task
+ to initiate a transmit sequence. Calling this routine enables Tx
+ interrupts.
+ ***************************************************************************/
+static ssize_t IntUartInterruptWrite(int minor, const char *buf, size_t len)
+{
+ if (len > 0) {
+ /* write out character */
+ MCF_UART_UTB(minor) = *buf;
+
+ /* enable tx interrupt */
+ IntUartInfo[minor].uimr |= MCF_UART_UIMR_TXRDY;
+ MCF_UART_UIMR(minor) = IntUartInfo[minor].uimr;
+ }
+
+ return (0);
+}
+
+/***************************************************************************
+ Function : IntUartInterruptOpen
+
+ Description : This enables interrupts when the tty is opened.
+ ***************************************************************************/
+static int IntUartInterruptOpen(int major, int minor, void *arg)
+{
+ struct IntUartInfoStruct *info = &IntUartInfo[minor];
+
+ /* enable the uart */
+ MCF_UART_UCR(minor) = (MCF_UART_UCR_TX_ENABLED | MCF_UART_UCR_RX_ENABLED);
+
+ /* check to see if interrupts need to be enabled */
+ if (info->iomode != TERMIOS_POLLED) {
+ /* enable rx interrupts */
+ info->uimr |= MCF_UART_UIMR_RXRDY_FU;
+ MCF_UART_UIMR(minor) = info->uimr;
+ }
+
+ /* check to see if doing hardware flow control */
+ if (info->hwflow) {
+ /* assert the RTS line */
+ MCF_UART_UOP1(minor) = 1;
+ }
+
+ return (0);
+}
+
+/***************************************************************************
+ Function : IntUartInterruptClose
+
+ Description : This disables interrupts when the tty is closed.
+ ***************************************************************************/
+static int IntUartInterruptClose(int major, int minor, void *arg)
+{
+ struct IntUartInfoStruct *info = &IntUartInfo[minor];
+
+ /* disable the interrupts and the uart */
+ MCF_UART_UIMR(minor) = 0;
+ MCF_UART_UCR(minor) = (MCF_UART_UCR_TX_DISABLED | MCF_UART_UCR_RX_DISABLED);
+
+ /* reset values */
+ info->ttyp = NULL;
+ info->uimr = 0;
+ info->rx_in = 0;
+ info->rx_out = 0;
+
+ return (0);
+}
+
+/***************************************************************************
+ Function : IntUartTaskRead
+
+ Description : This reads all available characters from the internal uart
+ and places them into the termios buffer. The rx interrupts will be
+ re-enabled after all data has been read.
+ ***************************************************************************/
+static int IntUartTaskRead(int minor)
+{
+ char buffer[RX_BUFFER_SIZE];
+ int count;
+ int rx_in;
+ int index = 0;
+ struct IntUartInfoStruct *info = &IntUartInfo[minor];
+
+ /* determine number of values to copy out */
+ rx_in = info->rx_in;
+ if (info->rx_out <= rx_in) {
+ count = rx_in - info->rx_out;
+ } else {
+ count = (RX_BUFFER_SIZE - info->rx_out) + rx_in;
+ }
+
+ /* copy data into local buffer from rx buffer */
+ while ((index < count) && (index < RX_BUFFER_SIZE)) {
+ /* copy data byte */
+ buffer[index] = info->rx_buffer[info->rx_out];
+ index++;
+
+ /* increment rx buffer values */
+ info->rx_out++;
+ if (info->rx_out >= RX_BUFFER_SIZE) {
+ info->rx_out = 0;
+ }
+ }
+
+ /* check to see if buffer is not empty */
+ if (count > 0) {
+ /* set characters into termios buffer */
+ rtems_termios_enqueue_raw_characters(info->ttyp, buffer, count);
+ }
+
+ return (EOF);
+}
+
+/***************************************************************************
+ Function : IntUartPollRead
+
+ Description : This reads a character from the internal uart. It returns
+ to the caller without blocking if not character is waiting.
+ ***************************************************************************/
+static
+int IntUartPollRead(int minor)
+{
+ if ((MCF_UART_USR(minor) & MCF_UART_USR_RXRDY) == 0)
+ return (-1);
+
+ return (MCF_UART_URB(minor));
+}
+
+/***************************************************************************
+ Function : IntUartPollWrite
+
+ Description : This writes out each character in the buffer to the
+ appropriate internal uart channel waiting till each one is sucessfully
+ transmitted.
+ ***************************************************************************/
+static ssize_t IntUartPollWrite(int minor, const char *buf, size_t len)
+{
+ /* loop over buffer */
+ while (len--) {
+ /* block until we can transmit */
+ while ((MCF_UART_USR(minor) & MCF_UART_USR_TXRDY) == 0)
+ continue;
+ /* transmit data byte */
+ MCF_UART_UTB(minor) = *buf++;
+ }
+ return (0);
+}
+
+/***************************************************************************
+ Function : console_initialize
+
+ Description : This initialises termios, both sets of uart hardware before
+ registering /dev/tty devices for each channel and the system /dev/console.
+ ***************************************************************************/
+rtems_device_driver console_initialize(rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg)
+{
+ rtems_status_code status;
+
+ /* Set up TERMIOS */
+ rtems_termios_initialize();
+
+ /* set io modes for the different channels and initialize device */
+ IntUartInitialize();
+
+ /* Register the console port */
+ status = rtems_io_register_name("/dev/console", major, CONSOLE_PORT);
+ if (status != RTEMS_SUCCESSFUL) {
+ rtems_fatal_error_occurred(status);
+ }
+
+ /* Register the RS485 port to communicate with SANTEC stations */
+ if ((STATIONS_PORT!=CONSOLE_PORT) && (STATIONS_PORT!=BLUETOOTH_PORT)) {
+ status = rtems_io_register_name("/dev/tty00", major,STATIONS_PORT);
+ if (status != RTEMS_SUCCESSFUL) {
+ rtems_fatal_error_occurred(status);
+ }
+ }
+ else {
+ status=RTEMS_TOO_MANY;
+ rtems_fatal_error_occurred(status);
+ }
+
+ /* Register the Bluetooth port */
+ if ((BLUETOOTH_PORT!=CONSOLE_PORT) && (BLUETOOTH_PORT!=STATIONS_PORT)) {
+ status = rtems_io_register_name("/dev/tty01", major, BLUETOOTH_PORT);
+ if (status != RTEMS_SUCCESSFUL) {
+ rtems_fatal_error_occurred(status);
+ }
+ }
+ else {
+ status=RTEMS_TOO_MANY;
+ rtems_fatal_error_occurred(status);
+ }
+
+ return (RTEMS_SUCCESSFUL);
+}
+
+/***************************************************************************
+ Function : console_open
+
+ Description : This actually opens the device depending on the minor
+ number set during initialisation. The device specific access routines are
+ passed to termios when the devices is opened depending on whether it is
+ polled or not.
+ ***************************************************************************/
+rtems_device_driver console_open(rtems_device_major_number major,
+ rtems_device_minor_number minor, void *arg)
+{
+ rtems_status_code status = RTEMS_INVALID_NUMBER;
+ rtems_libio_open_close_args_t *args = (rtems_libio_open_close_args_t *) arg;
+ struct IntUartInfoStruct *info;
+
+ static const rtems_termios_callbacks IntUartPollCallbacks = {
+ NULL, /* firstOpen */
+ NULL, /* lastClose */
+ IntUartPollRead, /* pollRead */
+ IntUartPollWrite, /* write */
+ IntUartSetAttributes, /* setAttributes */
+ NULL, /* stopRemoteTx */
+ NULL, /* startRemoteTx */
+ TERMIOS_POLLED /* mode */
+ };
+ static const rtems_termios_callbacks IntUartIntrCallbacks = {
+ IntUartInterruptOpen, /* firstOpen */
+ IntUartInterruptClose, /* lastClose */
+ NULL, /* pollRead */
+ IntUartInterruptWrite, /* write */
+ IntUartSetAttributes, /* setAttributes */
+ NULL, /* stopRemoteTx */
+ NULL, /* startRemoteTx */
+ TERMIOS_IRQ_DRIVEN /* mode */
+ };
+
+ static const rtems_termios_callbacks IntUartTaskCallbacks = {
+ IntUartInterruptOpen, /* firstOpen */
+ IntUartInterruptClose, /* lastClose */
+ IntUartTaskRead, /* pollRead */
+ IntUartInterruptWrite, /* write */
+ IntUartSetAttributes, /* setAttributes */
+ NULL, /* stopRemoteTx */
+ NULL, /* startRemoteTx */
+ TERMIOS_TASK_DRIVEN /* mode */
+ };
+
+ /* open the port depending on the minor device number */
+ if ((minor >= 0) && (minor < MAX_UART_INFO)) {
+ info = &IntUartInfo[minor];
+ switch (info->iomode) {
+ case TERMIOS_POLLED:
+ status = rtems_termios_open(major, minor, arg, &IntUartPollCallbacks);
+ break;
+ case TERMIOS_IRQ_DRIVEN:
+ status = rtems_termios_open(major, minor, arg, &IntUartIntrCallbacks);
+ info->ttyp = args->iop->data1;
+ break;
+ case TERMIOS_TASK_DRIVEN:
+ status = rtems_termios_open(major, minor, arg, &IntUartTaskCallbacks);
+ info->ttyp = args->iop->data1;
+ break;
+ }
+ }
+
+ if (status == RTEMS_SUCCESSFUL) {
+ /*
+ * Reset the default baudrate.
+ */
+ struct termios term;
+
+ if (tcgetattr(STDIN_FILENO, &term) >= 0) {
+ term.c_cflag &= ~(CSIZE);
+ term.c_cflag |= CS8;
+ term.c_ispeed = B115200;
+ term.c_ospeed = B115200;
+ tcsetattr(STDIN_FILENO, TCSANOW, &term);
+ }
+ }
+
+ return (status);
+}
+
+/***************************************************************************
+ Function : console_close
+
+ Description : This closes the device via termios
+ ***************************************************************************/
+rtems_device_driver console_close(rtems_device_major_number major,
+ rtems_device_minor_number minor, void *arg)
+{
+ return (rtems_termios_close(arg));
+}
+
+/******************
+*********************************************************
+ Function : console_read
+
+ Description : Read from the device via termios
+ ***************************************************************************/
+rtems_device_driver console_read(rtems_device_major_number major,
+ rtems_device_minor_number minor, void *arg)
+{
+ return (rtems_termios_read(arg));
+}
+
+/***************************************************************************
+ Function : console_write
+
+ Description : Write to the device via termios
+ ***************************************************************************/
+rtems_device_driver console_write(rtems_device_major_number major,
+ rtems_device_minor_number minor, void *arg)
+{
+ return (rtems_termios_write(arg));
+}
+
+/***************************************************************************
+ Function : console_ioctl
+
+ Description : Pass the IOCtl call to termios
+ ***************************************************************************/
+rtems_device_driver console_control(rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg)
+{
+ return (rtems_termios_ioctl(arg));
+}
diff --git a/bsps/m68k/mcf5225x/console/debugio.c b/bsps/m68k/mcf5225x/console/debugio.c
new file mode 100644
index 0000000000..b91048a310
--- /dev/null
+++ b/bsps/m68k/mcf5225x/console/debugio.c
@@ -0,0 +1,35 @@
+/*
+ * Multi UART console serial I/O.
+ *
+ * TO DO: Add DMA input/output
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <rtems/libio.h>
+#include <rtems/termiostypes.h>
+#include <termios.h>
+#include <bsp.h>
+#include <malloc.h>
+
+#include <rtems/bspIo.h>
+
+static void _BSP_null_char(char c)
+{
+ rtems_interrupt_level level=UART0_IRQ_LEVEL;
+
+ rtems_interrupt_disable(level);
+ while ((MCF_UART_USR(CONSOLE_PORT) & MCF_UART_USR_TXRDY) == 0)
+ continue;
+ MCF_UART_UTB(CONSOLE_PORT) = c;
+ while ((MCF_UART_USR(CONSOLE_PORT) & MCF_UART_USR_TXRDY) == 0)
+ continue;
+ rtems_interrupt_enable(level);
+}
+
+BSP_output_char_function_type BSP_output_char = _BSP_null_char;
+BSP_polling_getchar_function_type BSP_poll_char = NULL;
diff --git a/bsps/m68k/mcf5235/console/console.c b/bsps/m68k/mcf5235/console/console.c
new file mode 100644
index 0000000000..38317130cb
--- /dev/null
+++ b/bsps/m68k/mcf5235/console/console.c
@@ -0,0 +1,745 @@
+ /*
+ * Multi UART console serial I/O.
+ *
+ * TO DO: Add DMA input/output
+ */
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <malloc.h>
+
+#include <rtems/libio.h>
+#include <rtems/termiostypes.h>
+#include <rtems/bspIo.h>
+#include <rtems/console.h>
+#include <bsp.h>
+
+#define UART_INTC0_IRQ_VECTOR(x) (64+13+(x))
+
+#define MCF5235_UART_USR_ERROR ( MCF5235_UART_USR_RB | \
+ MCF5235_UART_USR_FE | \
+ MCF5235_UART_USR_PE | \
+ MCF5235_UART_USR_OE )
+
+static ssize_t IntUartPollWrite(int minor, const char *buf, size_t len);
+static ssize_t IntUartInterruptWrite (int minor, const char *buf, size_t len);
+
+static void
+_BSP_null_char( char c )
+{
+ int level;
+
+ rtems_interrupt_disable(level);
+ while ( (MCF5235_UART_USR(CONSOLE_PORT) & MCF5235_UART_USR_TXRDY) == 0 )
+ continue;
+ MCF5235_UART_UTB(CONSOLE_PORT) = c;
+ while ( (MCF5235_UART_USR(CONSOLE_PORT) & MCF5235_UART_USR_TXRDY) == 0 )
+ continue;
+ rtems_interrupt_enable(level);
+}
+BSP_output_char_function_type BSP_output_char = _BSP_null_char;
+BSP_polling_getchar_function_type BSP_poll_char = NULL;
+
+#define MAX_UART_INFO 3
+#define RX_BUFFER_SIZE 512
+
+struct IntUartInfoStruct
+{
+ int iomode;
+ volatile int uimr;
+ int baud;
+ int databits;
+ int parity;
+ int stopbits;
+ int hwflow;
+ int rx_in;
+ int rx_out;
+ char rx_buffer[RX_BUFFER_SIZE];
+ void *ttyp;
+};
+
+struct IntUartInfoStruct IntUartInfo[MAX_UART_INFO];
+
+/***************************************************************************
+ Function : IntUartSet
+
+ Description : This updates the hardware UART settings.
+ ***************************************************************************/
+static void
+IntUartSet(int minor, int baud, int databits, int parity, int stopbits, int hwflow)
+{
+ int divisor;
+ uint32_t clock_speed;
+ uint8_t umr1 = 0;
+ uint8_t umr2 = 0;
+ struct IntUartInfoStruct *info = &IntUartInfo[minor];
+ int level;
+
+ rtems_interrupt_disable(level);
+
+
+ /* disable interrupts, clear RTS line, and disable the UARTS */
+ MCF5235_UART_UIMR(minor) = 0;
+ MCF5235_UART_UOP0(minor) = 1;
+ MCF5235_UART_UCR(minor) = (MCF5235_UART_UCR_TX_DISABLED | MCF5235_UART_UCR_RX_DISABLED);
+
+ /* save the current values */
+ info->uimr = 0;
+ info->baud = baud;
+ info->databits = databits;
+ info->parity = parity;
+ info->stopbits = stopbits;
+ info->hwflow = hwflow;
+
+ clock_speed = get_CPU_clock_speed();
+ /* determine the baud divisor value */
+ divisor = ((clock_speed/2) / ( 32 * baud ));
+ if ( divisor < 2 ) {
+ divisor = 2;
+ }
+
+ /* check to see if doing hardware flow control */
+ if ( hwflow )
+ {
+ /* set hardware flow options */
+ umr1 |= MCF5235_UART_UMR_RXRTS;
+ umr2 |= MCF5235_UART_UMR_TXCTS;
+ }
+
+ /* determine the new umr values */
+ umr1 |= (parity | databits);
+ umr2 |= (stopbits);
+
+ /* reset the uart */
+ MCF5235_UART_UCR(minor) = MCF5235_UART_UCR_RESET_ERROR;
+ MCF5235_UART_UCR(minor) = MCF5235_UART_UCR_RESET_RX;
+ MCF5235_UART_UCR(minor) = MCF5235_UART_UCR_RESET_TX;
+
+ /* reset the uart mode register and update values */
+ MCF5235_UART_UCR(minor) = MCF5235_UART_UCR_RESET_MR;
+ MCF5235_UART_UMR(minor) = umr1;
+ MCF5235_UART_UMR(minor) = umr2;
+
+ /* set the baud rate values */
+ MCF5235_UART_UCSR(minor) = (MCF5235_UART_UCSR_RCS_SYS_CLK | MCF5235_UART_UCSR_TCS_SYS_CLK);
+ MCF5235_UART_UBG1(minor) = (divisor & 0xff00) >> 8;
+ MCF5235_UART_UBG2(minor) = (divisor & 0x00ff);
+
+ /* enable the uart */
+ MCF5235_UART_UCR(minor) = (MCF5235_UART_UCR_TX_ENABLED | MCF5235_UART_UCR_RX_ENABLED);
+
+ /* check to see if interrupts need to be enabled */
+ if ( info->iomode != TERMIOS_POLLED )
+ {
+ /* enable rx interrupts */
+ info->uimr |= MCF5235_UART_UIMR_FFULL;
+ MCF5235_UART_UIMR(minor) = info->uimr;
+ }
+
+ /* check to see if doing hardware flow control */
+ if ( hwflow )
+ {
+ /* assert the RTS line */
+ MCF5235_UART_UOP1(minor) = 1;
+ }
+
+ rtems_interrupt_enable(level);
+
+}
+
+
+/***************************************************************************
+ Function : IntUartSetAttributes
+
+ Description : This provides the hardware-dependent portion of tcsetattr().
+ value and sets it. At the moment this just sets the baud rate.
+
+ Note: The highest baudrate is 115200 as this stays within
+ an error of +/- 5% at 25MHz processor clock
+ ***************************************************************************/
+static int
+IntUartSetAttributes(int minor, const struct termios *t)
+{
+ /* set default index values */
+ int baud = (int)19200;
+ int databits = (int)MCF5235_UART_UMR_BC_8;
+ int parity = (int)MCF5235_UART_UMR_PM_NONE;
+ int stopbits = (int)MCF5235_UART_UMR_STOP_BITS_1;
+ int hwflow = (int)0;
+ struct IntUartInfoStruct *info = &IntUartInfo[minor];
+
+ /* check to see if input is valid */
+ if ( t != (const struct termios *)0 )
+ {
+ /* determine baud rate index */
+ baud = rtems_termios_baud_to_number(t->c_ospeed);
+
+ /* determine data bits */
+ switch ( t->c_cflag & CSIZE )
+ {
+ case CS5:
+ databits = (int)MCF5235_UART_UMR_BC_5;
+ break;
+ case CS6:
+ databits = (int)MCF5235_UART_UMR_BC_6;
+ break;
+ case CS7:
+ databits = (int)MCF5235_UART_UMR_BC_7;
+ break;
+ case CS8:
+ databits = (int)MCF5235_UART_UMR_BC_8;
+ break;
+ }
+
+ /* determine if parity is enabled */
+ if ( t->c_cflag & PARENB )
+ {
+ if ( t->c_cflag & PARODD )
+ {
+ /* odd parity */
+ parity = (int)MCF5235_UART_UMR_PM_ODD;
+ }
+ else
+ {
+ /* even parity */
+ parity = (int)MCF5235_UART_UMR_PM_EVEN;
+ }
+ }
+
+ /* determine stop bits */
+ if ( t->c_cflag & CSTOPB )
+ {
+ /* two stop bits */
+ stopbits = (int)MCF5235_UART_UMR_STOP_BITS_2;
+ }
+
+ /* check to see if hardware flow control */
+ if ( t->c_cflag & CRTSCTS )
+ {
+ hwflow = 1;
+ }
+ }
+
+ /* check to see if values have changed */
+ if ( ( baud != info->baud ) ||
+ ( databits != info->databits ) ||
+ ( parity != info->parity ) ||
+ ( stopbits != info->stopbits ) ||
+ ( hwflow != info->hwflow ) )
+ {
+
+ /* call function to set values */
+ IntUartSet(minor, baud, databits, parity, stopbits, hwflow);
+ }
+
+ return( RTEMS_SUCCESSFUL );
+
+}
+
+/***************************************************************************
+ Function : IntUartInterruptHandler
+
+ Description : This is the interrupt handler for the internal uart. It
+ determines which channel caused the interrupt before queueing any received
+ chars and dequeueing chars waiting for transmission.
+ ***************************************************************************/
+static rtems_isr
+IntUartInterruptHandler(rtems_vector_number v)
+{
+ unsigned int chan = v - UART_INTC0_IRQ_VECTOR(0);
+ struct IntUartInfoStruct *info = &IntUartInfo[chan];
+
+ /* check to see if received data */
+ if ( MCF5235_UART_UISR(chan) & MCF5235_UART_UISR_RXRDY )
+ {
+ /* read data and put into the receive buffer */
+ while ( MCF5235_UART_USR(chan) & MCF5235_UART_USR_RXRDY )
+ {
+
+ if ( MCF5235_UART_USR(chan) & MCF5235_UART_USR_ERROR )
+ {
+ /* clear the error */
+ MCF5235_UART_UCR(chan) = MCF5235_UART_UCR_RESET_ERROR;
+ }
+ /* put data in rx buffer and check for errors */
+ info->rx_buffer[info->rx_in] = MCF5235_UART_URB(chan);
+
+ /* update buffer values */
+ info->rx_in++;
+
+ if ( info->rx_in >= RX_BUFFER_SIZE )
+ {
+ info->rx_in = 0;
+ }
+ }
+ /* Make sure the port has been opened */
+ if ( info->ttyp )
+ {
+
+ /* check to see if task driven */
+ if ( info->iomode == TERMIOS_TASK_DRIVEN )
+ {
+ /* notify rx task that rx buffer has data */
+ rtems_termios_rxirq_occured(info->ttyp);
+ }
+ else
+ {
+ /* Push up the received data */
+ rtems_termios_enqueue_raw_characters(info->ttyp, info->rx_buffer, info->rx_in);
+ info->rx_in = 0;
+ }
+ }
+ }
+
+ /* check to see if data needs to be transmitted */
+ if ( ( info->uimr & MCF5235_UART_UIMR_TXRDY ) &&
+ ( MCF5235_UART_UISR(chan) & MCF5235_UART_UISR_TXRDY ) )
+ {
+
+ /* disable tx interrupts */
+ info->uimr &= ~MCF5235_UART_UIMR_TXRDY;
+ MCF5235_UART_UIMR(chan) = info->uimr;
+
+ /* tell upper level that character has been sent */
+ if ( info->ttyp )
+ rtems_termios_dequeue_characters(info->ttyp, 1);
+ }
+}
+
+
+
+/***************************************************************************
+ Function : IntUartInitialize
+
+ Description : This initialises the internal uart hardware for all
+ internal uarts. If the internal uart is to be interrupt driven then the
+ interrupt vectors are hooked.
+ ***************************************************************************/
+static void
+IntUartInitialize(void)
+{
+ unsigned int chan;
+ struct IntUartInfoStruct *info;
+ rtems_isr_entry old_handler;
+ int level;
+
+ for ( chan = 0; chan < MAX_UART_INFO; chan++ )
+ {
+ info = &IntUartInfo[chan];
+
+ info->ttyp = NULL;
+ info->rx_in = 0;
+ info->rx_out = 0;
+ info->baud = -1;
+ info->databits = -1;
+ info->parity = -1;
+ info->stopbits = -1;
+ info->hwflow = -1;
+ info->iomode = TERMIOS_POLLED; /*polled console io */
+
+ MCF5235_UART_UACR(chan) = 0;
+ MCF5235_UART_UIMR(chan) = 0;
+ if ( info->iomode != TERMIOS_POLLED )
+ {
+ rtems_interrupt_catch (IntUartInterruptHandler,
+ UART_INTC0_IRQ_VECTOR(chan),
+ &old_handler);
+ }
+
+ /* set uart default values */
+ IntUartSetAttributes(chan, NULL);
+
+ /* unmask interrupt */
+ rtems_interrupt_disable(level);
+ switch(chan) {
+ case 0:
+ MCF5235_INTC0_ICR13 = MCF5235_INTC_ICR_IL(UART0_IRQ_LEVEL) |
+ MCF5235_INTC_ICR_IP(UART0_IRQ_PRIORITY);
+ MCF5235_INTC0_IMRL &= ~(MCF5235_INTC0_IMRL_INT13 |
+ MCF5235_INTC0_IMRL_MASKALL);
+ break;
+
+ case 1:
+ MCF5235_INTC0_ICR14 = MCF5235_INTC_ICR_IL(UART1_IRQ_LEVEL) |
+ MCF5235_INTC_ICR_IP(UART1_IRQ_PRIORITY);
+ MCF5235_INTC0_IMRL &= ~(MCF5235_INTC0_IMRL_INT14 |
+ MCF5235_INTC0_IMRL_MASKALL);
+ break;
+
+ case 2:
+ MCF5235_INTC0_ICR15 = MCF5235_INTC_ICR_IL(UART2_IRQ_LEVEL) |
+ MCF5235_INTC_ICR_IP(UART2_IRQ_PRIORITY);
+ MCF5235_INTC0_IMRL &= ~(MCF5235_INTC0_IMRL_INT15 |
+ MCF5235_INTC0_IMRL_MASKALL);
+ break;
+ }
+ rtems_interrupt_enable(level);
+
+ } /* of chan loop */
+
+
+} /* IntUartInitialise */
+
+
+/***************************************************************************
+ Function : IntUartInterruptWrite
+
+ Description : This writes a single character to the appropriate uart
+ channel. This is either called during an interrupt or in the user's task
+ to initiate a transmit sequence. Calling this routine enables Tx
+ interrupts.
+ ***************************************************************************/
+static ssize_t
+IntUartInterruptWrite (int minor, const char *buf, size_t len)
+{
+ if (len > 0) {
+ /* write out character */
+ MCF5235_UART_UTB(minor) = *buf;
+
+ /* enable tx interrupt */
+ IntUartInfo[minor].uimr |= MCF5235_UART_UIMR_TXRDY;
+ MCF5235_UART_UIMR(minor) = IntUartInfo[minor].uimr;
+ }
+
+ return( 0 );
+}
+
+/***************************************************************************
+ Function : IntUartInterruptOpen
+
+ Description : This enables interrupts when the tty is opened.
+ ***************************************************************************/
+static int
+IntUartInterruptOpen(int major, int minor, void *arg)
+{
+ struct IntUartInfoStruct *info = &IntUartInfo[minor];
+
+ /* enable the uart */
+ MCF5235_UART_UCR(minor) = (MCF5235_UART_UCR_TX_ENABLED | MCF5235_UART_UCR_RX_ENABLED);
+
+ /* check to see if interrupts need to be enabled */
+ if ( info->iomode != TERMIOS_POLLED )
+ {
+ /* enable rx interrupts */
+ info->uimr |= MCF5235_UART_UIMR_FFULL;
+ MCF5235_UART_UIMR(minor) = info->uimr;
+ }
+
+ /* check to see if doing hardware flow control */
+ if ( info->hwflow )
+ {
+ /* assert the RTS line */
+ MCF5235_UART_UOP1(minor) = 1;
+ }
+
+ return( 0 );
+}
+
+
+
+/***************************************************************************
+ Function : IntUartInterruptClose
+
+ Description : This disables interrupts when the tty is closed.
+ ***************************************************************************/
+static int
+IntUartInterruptClose(int major, int minor, void *arg)
+{
+ struct IntUartInfoStruct *info = &IntUartInfo[minor];
+
+ /* disable the interrupts and the uart */
+ MCF5235_UART_UIMR(minor) = 0;
+ MCF5235_UART_UCR(minor) = (MCF5235_UART_UCR_TX_DISABLED | MCF5235_UART_UCR_RX_DISABLED);
+
+ /* reset values */
+ info->ttyp = NULL;
+ info->uimr = 0;
+ info->rx_in = 0;
+ info->rx_out = 0;
+
+ return( 0 );
+}
+
+/***************************************************************************
+ Function : IntUartTaskRead
+
+ Description : This reads all available characters from the internal uart
+ and places them into the termios buffer. The rx interrupts will be
+ re-enabled after all data has been read.
+ ***************************************************************************/
+static int
+IntUartTaskRead(int minor)
+{
+ char buffer[RX_BUFFER_SIZE];
+ int count;
+ int rx_in;
+ int index = 0;
+ struct IntUartInfoStruct *info = &IntUartInfo[minor];
+
+ /* determine number of values to copy out */
+ rx_in = info->rx_in;
+ if ( info->rx_out <= rx_in )
+ {
+ count = rx_in - info->rx_out;
+ }
+ else
+ {
+ count = (RX_BUFFER_SIZE - info->rx_out) + rx_in;
+ }
+
+ /* copy data into local buffer from rx buffer */
+ while ( ( index < count ) && ( index < RX_BUFFER_SIZE ) )
+ {
+ /* copy data byte */
+ buffer[index] = info->rx_buffer[info->rx_out];
+ index++;
+
+ /* increment rx buffer values */
+ info->rx_out++;
+ if ( info->rx_out >= RX_BUFFER_SIZE )
+ {
+ info->rx_out = 0;
+ }
+ }
+
+ /* check to see if buffer is not empty */
+ if ( count > 0 )
+ {
+ /* set characters into termios buffer */
+ rtems_termios_enqueue_raw_characters(info->ttyp, buffer, count);
+ }
+
+ return( EOF );
+}
+
+
+
+/***************************************************************************
+ Function : IntUartPollRead
+
+ Description : This reads a character from the internal uart. It returns
+ to the caller without blocking if not character is waiting.
+ ***************************************************************************/
+static int
+IntUartPollRead (int minor)
+{
+ if ( (MCF5235_UART_USR(minor) & MCF5235_UART_USR_RXRDY) == 0 )
+ return(-1);
+
+ return(MCF5235_UART_URB(minor));
+}
+
+
+/***************************************************************************
+ Function : IntUartPollWrite
+
+ Description : This writes out each character in the buffer to the
+ appropriate internal uart channel waiting till each one is sucessfully
+ transmitted.
+ ***************************************************************************/
+static ssize_t
+IntUartPollWrite (int minor, const char *buf, size_t len)
+{
+ size_t retval = len;
+ /* loop over buffer */
+ while ( len-- )
+ {
+ /* block until we can transmit */
+ while ( (MCF5235_UART_USR(minor) & MCF5235_UART_USR_TXRDY) == 0 )
+ continue;
+ /* transmit data byte */
+ MCF5235_UART_UTB(minor) = *buf++;
+ }
+ return retval;
+}
+
+/***************************************************************************
+ Function : console_initialize
+
+ Description : This initialises termios, both sets of uart hardware before
+ registering /dev/tty devices for each channel and the system /dev/console.
+ ***************************************************************************/
+rtems_device_driver console_initialize(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg )
+{
+ rtems_status_code status;
+
+
+ /* Set up TERMIOS */
+ rtems_termios_initialize ();
+
+ /* set io modes for the different channels and initialize device */
+ IntUartInfo[minor].iomode = TERMIOS_IRQ_DRIVEN;
+ IntUartInitialize();
+
+ /* Register the console port */
+ status = rtems_io_register_name ("/dev/console", major, CONSOLE_PORT);
+ if ( status != RTEMS_SUCCESSFUL )
+ {
+ rtems_fatal_error_occurred (status);
+ }
+
+ /* Register the other port */
+ if ( CONSOLE_PORT != 0 )
+ {
+ status = rtems_io_register_name ("/dev/tty00", major, 0);
+ if ( status != RTEMS_SUCCESSFUL )
+ {
+ rtems_fatal_error_occurred (status);
+ }
+ }
+ if ( CONSOLE_PORT != 1 )
+ {
+ status = rtems_io_register_name ("/dev/tty01", major, 1);
+ if ( status != RTEMS_SUCCESSFUL )
+ {
+ rtems_fatal_error_occurred (status);
+ }
+ }
+
+ return(RTEMS_SUCCESSFUL);
+}
+
+/***************************************************************************
+ Function : console_open
+
+ Description : This actually opens the device depending on the minor
+ number set during initialisation. The device specific access routines are
+ passed to termios when the devices is opened depending on whether it is
+ polled or not.
+ ***************************************************************************/
+rtems_device_driver console_open(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg)
+{
+ rtems_status_code status = RTEMS_INVALID_NUMBER;
+ rtems_libio_open_close_args_t *args = (rtems_libio_open_close_args_t *)arg;
+ struct IntUartInfoStruct *info;
+
+ static const rtems_termios_callbacks IntUartPollCallbacks = {
+ NULL, /* firstOpen */
+ NULL, /* lastClose */
+ IntUartPollRead, /* pollRead */
+ IntUartPollWrite, /* write */
+ IntUartSetAttributes, /* setAttributes */
+ NULL, /* stopRemoteTx */
+ NULL, /* startRemoteTx */
+ TERMIOS_POLLED /* mode */
+ };
+ static const rtems_termios_callbacks IntUartIntrCallbacks = {
+ IntUartInterruptOpen, /* firstOpen */
+ IntUartInterruptClose, /* lastClose */
+ NULL, /* pollRead */
+ IntUartInterruptWrite, /* write */
+ IntUartSetAttributes, /* setAttributes */
+ NULL, /* stopRemoteTx */
+ NULL, /* startRemoteTx */
+ TERMIOS_IRQ_DRIVEN /* mode */
+ };
+
+ static const rtems_termios_callbacks IntUartTaskCallbacks = {
+ IntUartInterruptOpen, /* firstOpen */
+ IntUartInterruptClose, /* lastClose */
+ IntUartTaskRead, /* pollRead */
+ IntUartInterruptWrite, /* write */
+ IntUartSetAttributes, /* setAttributes */
+ NULL, /* stopRemoteTx */
+ NULL, /* startRemoteTx */
+ TERMIOS_TASK_DRIVEN /* mode */
+ };
+
+ /* open the port depending on the minor device number */
+ if ( ( minor >= 0 ) && ( minor < MAX_UART_INFO ) )
+ {
+ info = &IntUartInfo[minor];
+ switch ( info->iomode )
+ {
+ case TERMIOS_POLLED:
+ status = rtems_termios_open(major, minor, arg, &IntUartPollCallbacks);
+ break;
+ case TERMIOS_IRQ_DRIVEN:
+ status = rtems_termios_open(major, minor, arg, &IntUartIntrCallbacks);
+ info->ttyp = args->iop->data1;
+ break;
+ case TERMIOS_TASK_DRIVEN:
+ status = rtems_termios_open(major, minor, arg, &IntUartTaskCallbacks);
+ info->ttyp = args->iop->data1;
+ break;
+ }
+ }
+
+ if (status == RTEMS_SUCCESSFUL)
+ {
+ /*
+ * Reset the default baudrate.
+ */
+ struct termios term;
+ if (tcgetattr (STDIN_FILENO, &term) >= 0)
+ {
+ term.c_cflag &= ~(CSIZE);
+ term.c_cflag |= CS8;
+ term.c_ispeed = B19200;
+ term.c_ospeed = B19200;
+ tcsetattr (STDIN_FILENO, TCSANOW, &term);
+ }
+ }
+
+ return( status );
+}
+
+/***************************************************************************
+ Function : console_close
+
+ Description : This closes the device via termios
+ ***************************************************************************/
+rtems_device_driver console_close(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg)
+{
+ return(rtems_termios_close (arg));
+}
+
+/******************
+*********************************************************
+ Function : console_read
+
+ Description : Read from the device via termios
+ ***************************************************************************/
+rtems_device_driver console_read(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg)
+{
+ return(rtems_termios_read (arg));
+}
+
+/***************************************************************************
+ Function : console_write
+
+ Description : Write to the device via termios
+ ***************************************************************************/
+rtems_device_driver console_write(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg)
+{
+ return(rtems_termios_write (arg));
+}
+
+/***************************************************************************
+ Function : console_ioctl
+
+ Description : Pass the IOCtl call to termios
+ ***************************************************************************/
+rtems_device_driver console_control(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg)
+{
+ return( rtems_termios_ioctl (arg) );
+}
diff --git a/bsps/m68k/mcf5329/console/console.c b/bsps/m68k/mcf5329/console/console.c
new file mode 100644
index 0000000000..797e5b0606
--- /dev/null
+++ b/bsps/m68k/mcf5329/console/console.c
@@ -0,0 +1,668 @@
+ /*
+ * Multi UART console serial I/O.
+ *
+ * TO DO: Add DMA input/output
+ */
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <malloc.h>
+
+#include <rtems/libio.h>
+#include <rtems/termiostypes.h>
+#include <rtems/console.h>
+#include <rtems/bspIo.h>
+
+#include <bsp.h>
+
+#define UART_INTC0_IRQ_VECTOR(x) (64+26+(x))
+
+#define MCF_UART_USR_ERROR ( MCF_UART_USR_RB | \
+ MCF_UART_USR_FE | \
+ MCF_UART_USR_PE | \
+ MCF_UART_USR_OE )
+
+static ssize_t IntUartPollWrite(int minor, const char *buf, size_t len);
+static ssize_t IntUartInterruptWrite(int minor, const char *buf, size_t len);
+
+static void _BSP_null_char(char c)
+{
+ int level;
+
+ rtems_interrupt_disable(level);
+ while ((MCF_UART_USR(CONSOLE_PORT) & MCF_UART_USR_TXRDY) == 0)
+ continue;
+ MCF_UART_UTB(CONSOLE_PORT) = c;
+ while ((MCF_UART_USR(CONSOLE_PORT) & MCF_UART_USR_TXRDY) == 0)
+ continue;
+ rtems_interrupt_enable(level);
+}
+
+BSP_output_char_function_type BSP_output_char = _BSP_null_char;
+BSP_polling_getchar_function_type BSP_poll_char = NULL;
+
+#define MAX_UART_INFO 3
+#define RX_BUFFER_SIZE 512
+
+struct IntUartInfoStruct
+{
+ int iomode;
+ volatile int uimr;
+ int baud;
+ int databits;
+ int parity;
+ int stopbits;
+ int hwflow;
+ int rx_in;
+ int rx_out;
+ char rx_buffer[RX_BUFFER_SIZE];
+ void *ttyp;
+};
+
+struct IntUartInfoStruct IntUartInfo[MAX_UART_INFO];
+
+/***************************************************************************
+ Function : IntUartSet
+
+ Description : This updates the hardware UART settings.
+ ***************************************************************************/
+static void
+IntUartSet(int minor, int baud, int databits, int parity, int stopbits,
+ int hwflow)
+{
+ int divisor;
+ uint32_t clock_speed;
+ uint8_t umr1 = 0;
+ uint8_t umr2 = 0;
+ struct IntUartInfoStruct *info = &IntUartInfo[minor];
+ int level;
+
+ rtems_interrupt_disable(level);
+
+ /* disable interrupts, clear RTS line, and disable the UARTS */
+ MCF_UART_UIMR(minor) = 0;
+ MCF_UART_UOP0(minor) = 1;
+ MCF_UART_UCR(minor) = (MCF_UART_UCR_TX_DISABLED | MCF_UART_UCR_RX_DISABLED);
+
+ /* save the current values */
+ info->uimr = 0;
+ info->baud = baud;
+ info->databits = databits;
+ info->parity = parity;
+ info->stopbits = stopbits;
+ info->hwflow = hwflow;
+
+ clock_speed = bsp_get_BUS_clock_speed();
+ /* determine the baud divisor value */
+ divisor = ((clock_speed) / (32 * baud));
+ if (divisor < 2)
+ divisor = 2;
+
+ /* check to see if doing hardware flow control */
+ if (hwflow) {
+ /* set hardware flow options */
+ umr1 |= MCF_UART_UMR_RXRTS;
+ umr2 |= MCF_UART_UMR_TXCTS;
+ }
+
+ /* determine the new umr values */
+ umr1 |= (parity | databits);
+ umr2 |= (stopbits);
+
+ /* reset the uart */
+ MCF_UART_UCR(minor) = MCF_UART_UCR_RESET_ERROR;
+ MCF_UART_UCR(minor) = MCF_UART_UCR_RESET_RX;
+ MCF_UART_UCR(minor) = MCF_UART_UCR_RESET_TX;
+
+ /* reset the uart mode register and update values */
+ MCF_UART_UCR(minor) = MCF_UART_UCR_RESET_MR;
+ MCF_UART_UMR(minor) = umr1;
+ MCF_UART_UMR(minor) = umr2;
+
+ /* set the baud rate values */
+ MCF_UART_UCSR(minor) =
+ (MCF_UART_UCSR_RCS_SYS_CLK | MCF_UART_UCSR_TCS_SYS_CLK);
+ MCF_UART_UBG1(minor) = (divisor & 0xff00) >> 8;
+ MCF_UART_UBG2(minor) = (divisor & 0x00ff);
+
+ /* enable the uart */
+ MCF_UART_UCR(minor) = (MCF_UART_UCR_TX_ENABLED | MCF_UART_UCR_RX_ENABLED);
+
+ /* check to see if interrupts need to be enabled */
+ if (info->iomode != TERMIOS_POLLED) {
+ /* enable rx interrupts */
+ info->uimr |= MCF_UART_UIMR_RXRDY_FU;
+ MCF_UART_UIMR(minor) = info->uimr;
+ }
+
+ /* check to see if doing hardware flow control */
+ if (hwflow) {
+ /* assert the RTS line */
+ MCF_UART_UOP1(minor) = 1;
+ }
+
+ rtems_interrupt_enable(level);
+
+}
+
+/***************************************************************************
+ Function : IntUartSetAttributes
+
+ Description : This provides the hardware-dependent portion of tcsetattr().
+ value and sets it. At the moment this just sets the baud rate.
+
+ Note: The highest baudrate is 115200 as this stays within
+ an error of +/- 5% at 25MHz processor clock
+ ***************************************************************************/
+static int IntUartSetAttributes(int minor, const struct termios *t)
+{
+ /* set default index values */
+ int baud = (int) 19200;
+ int databits = (int) MCF_UART_UMR_BC_8;
+ int parity = (int) MCF_UART_UMR_PM_NONE;
+ int stopbits = (int) MCF_UART_UMR_SB_STOP_BITS_1;
+ int hwflow = (int) 0;
+ struct IntUartInfoStruct *info = &IntUartInfo[minor];
+
+ /* check to see if input is valid */
+ if (t != (const struct termios *) 0) {
+ /* determine baud rate index */
+ baud = rtems_termios_baud_to_number(t->c_ospeed);
+
+ /* determine data bits */
+ switch (t->c_cflag & CSIZE) {
+ case CS5:
+ databits = (int) MCF_UART_UMR_BC_5;
+ break;
+ case CS6:
+ databits = (int) MCF_UART_UMR_BC_6;
+ break;
+ case CS7:
+ databits = (int) MCF_UART_UMR_BC_7;
+ break;
+ case CS8:
+ databits = (int) MCF_UART_UMR_BC_8;
+ break;
+ }
+
+ /* determine if parity is enabled */
+ if (t->c_cflag & PARENB) {
+ if (t->c_cflag & PARODD) {
+ /* odd parity */
+ parity = (int) MCF_UART_UMR_PM_ODD;
+ } else {
+ /* even parity */
+ parity = (int) MCF_UART_UMR_PM_EVEN;
+ }
+ }
+
+ /* determine stop bits */
+ if (t->c_cflag & CSTOPB) {
+ /* two stop bits */
+ stopbits = (int) MCF_UART_UMR_SB_STOP_BITS_2;
+ }
+
+ /* check to see if hardware flow control */
+ if (t->c_cflag & CRTSCTS) {
+ hwflow = 1;
+ }
+ }
+
+ /* check to see if values have changed */
+ if ((baud != info->baud) ||
+ (databits != info->databits) ||
+ (parity != info->parity) ||
+ (stopbits != info->stopbits) || (hwflow != info->hwflow)) {
+
+ /* call function to set values */
+ IntUartSet(minor, baud, databits, parity, stopbits, hwflow);
+ }
+
+ return (RTEMS_SUCCESSFUL);
+
+}
+
+/***************************************************************************
+ Function : IntUartInterruptHandler
+
+ Description : This is the interrupt handler for the internal uart. It
+ determines which channel caused the interrupt before queueing any received
+ chars and dequeueing chars waiting for transmission.
+ ***************************************************************************/
+static rtems_isr IntUartInterruptHandler(rtems_vector_number v)
+{
+ unsigned int chan = v - UART_INTC0_IRQ_VECTOR(0);
+ struct IntUartInfoStruct *info = &IntUartInfo[chan];
+
+ /* check to see if received data */
+ if (MCF_UART_UISR(chan) & MCF_UART_UISR_RXRDY_FU) {
+ /* read data and put into the receive buffer */
+ while (MCF_UART_USR(chan) & MCF_UART_USR_RXRDY) {
+
+ if (MCF_UART_USR(chan) & MCF_UART_USR_ERROR) {
+ /* clear the error */
+ MCF_UART_UCR(chan) = MCF_UART_UCR_RESET_ERROR;
+ }
+ /* put data in rx buffer and check for errors */
+ info->rx_buffer[info->rx_in] = MCF_UART_URB(chan);
+
+ /* update buffer values */
+ info->rx_in++;
+
+ if (info->rx_in >= RX_BUFFER_SIZE) {
+ info->rx_in = 0;
+ }
+ }
+ /* Make sure the port has been opened */
+ if (info->ttyp) {
+
+ /* check to see if task driven */
+ if (info->iomode == TERMIOS_TASK_DRIVEN) {
+ /* notify rx task that rx buffer has data */
+ rtems_termios_rxirq_occured(info->ttyp);
+ } else {
+ /* Push up the received data */
+ rtems_termios_enqueue_raw_characters(info->ttyp, info->rx_buffer,
+ info->rx_in);
+ info->rx_in = 0;
+ }
+ }
+ }
+
+ /* check to see if data needs to be transmitted */
+ if ((info->uimr & MCF_UART_UIMR_TXRDY) &&
+ (MCF_UART_UISR(chan) & MCF_UART_UISR_TXRDY)) {
+
+ /* disable tx interrupts */
+ info->uimr &= ~MCF_UART_UIMR_TXRDY;
+ MCF_UART_UIMR(chan) = info->uimr;
+
+ /* tell upper level that character has been sent */
+ if (info->ttyp)
+ rtems_termios_dequeue_characters(info->ttyp, 1);
+ }
+}
+
+/***************************************************************************
+ Function : IntUartInitialize
+
+ Description : This initialises the internal uart hardware for all
+ internal uarts. If the internal uart is to be interrupt driven then the
+ interrupt vectors are hooked.
+ ***************************************************************************/
+static void IntUartInitialize(void)
+{
+ unsigned int chan;
+ struct IntUartInfoStruct *info;
+ rtems_isr_entry old_handler;
+ int level;
+
+ for (chan = 0; chan < MAX_UART_INFO; chan++) {
+ info = &IntUartInfo[chan];
+
+ info->ttyp = NULL;
+ info->rx_in = 0;
+ info->rx_out = 0;
+ info->baud = -1;
+ info->databits = -1;
+ info->parity = -1;
+ info->stopbits = -1;
+ info->hwflow = -1;
+ info->iomode = TERMIOS_POLLED; /*polled console io */
+
+ MCF_UART_UACR(chan) = 0;
+ MCF_UART_UIMR(chan) = 0;
+ if (info->iomode != TERMIOS_POLLED) {
+ rtems_interrupt_catch(IntUartInterruptHandler,
+ UART_INTC0_IRQ_VECTOR(chan), &old_handler);
+ }
+
+ /* set uart default values */
+ IntUartSetAttributes(chan, NULL);
+
+ /* unmask interrupt */
+ rtems_interrupt_disable(level);
+ switch (chan) {
+ case 0:
+ MCF_INTC0_ICR26 = MCF_INTC_ICR_IL(UART0_IRQ_LEVEL);
+ MCF_INTC0_IMRL &= ~(MCF_INTC_IMRL_INT_MASK26);
+ break;
+
+ case 1:
+ MCF_INTC0_ICR27 = MCF_INTC_ICR_IL(UART1_IRQ_LEVEL);
+ MCF_INTC0_IMRL &= ~(MCF_INTC_IMRL_INT_MASK27);
+ break;
+
+ case 2:
+ MCF_INTC0_ICR28 = MCF_INTC_ICR_IL(UART2_IRQ_LEVEL);
+ MCF_INTC0_IMRL &= ~(MCF_INTC_IMRL_INT_MASK28);
+ break;
+ }
+ rtems_interrupt_enable(level);
+
+ } /* of chan loop */
+
+} /* IntUartInitialise */
+
+/***************************************************************************
+ Function : IntUartInterruptWrite
+
+ Description : This writes a single character to the appropriate uart
+ channel. This is either called during an interrupt or in the user's task
+ to initiate a transmit sequence. Calling this routine enables Tx
+ interrupts.
+ ***************************************************************************/
+static ssize_t IntUartInterruptWrite(int minor, const char *buf, size_t len)
+{
+ if (len > 0) {
+ /* write out character */
+ MCF_UART_UTB(minor) = *buf;
+
+ /* enable tx interrupt */
+ IntUartInfo[minor].uimr |= MCF_UART_UIMR_TXRDY;
+ MCF_UART_UIMR(minor) = IntUartInfo[minor].uimr;
+ }
+
+ return (0);
+}
+
+/***************************************************************************
+ Function : IntUartInterruptOpen
+
+ Description : This enables interrupts when the tty is opened.
+ ***************************************************************************/
+static int IntUartInterruptOpen(int major, int minor, void *arg)
+{
+ struct IntUartInfoStruct *info = &IntUartInfo[minor];
+
+ /* enable the uart */
+ MCF_UART_UCR(minor) = (MCF_UART_UCR_TX_ENABLED | MCF_UART_UCR_RX_ENABLED);
+
+ /* check to see if interrupts need to be enabled */
+ if (info->iomode != TERMIOS_POLLED) {
+ /* enable rx interrupts */
+ info->uimr |= MCF_UART_UIMR_RXRDY_FU;
+ MCF_UART_UIMR(minor) = info->uimr;
+ }
+
+ /* check to see if doing hardware flow control */
+ if (info->hwflow) {
+ /* assert the RTS line */
+ MCF_UART_UOP1(minor) = 1;
+ }
+
+ return (0);
+}
+
+/***************************************************************************
+ Function : IntUartInterruptClose
+
+ Description : This disables interrupts when the tty is closed.
+ ***************************************************************************/
+static int IntUartInterruptClose(int major, int minor, void *arg)
+{
+ struct IntUartInfoStruct *info = &IntUartInfo[minor];
+
+ /* disable the interrupts and the uart */
+ MCF_UART_UIMR(minor) = 0;
+ MCF_UART_UCR(minor) = (MCF_UART_UCR_TX_DISABLED | MCF_UART_UCR_RX_DISABLED);
+
+ /* reset values */
+ info->ttyp = NULL;
+ info->uimr = 0;
+ info->rx_in = 0;
+ info->rx_out = 0;
+
+ return (0);
+}
+
+/***************************************************************************
+ Function : IntUartTaskRead
+
+ Description : This reads all available characters from the internal uart
+ and places them into the termios buffer. The rx interrupts will be
+ re-enabled after all data has been read.
+ ***************************************************************************/
+static int IntUartTaskRead(int minor)
+{
+ char buffer[RX_BUFFER_SIZE];
+ int count;
+ int rx_in;
+ int index = 0;
+ struct IntUartInfoStruct *info = &IntUartInfo[minor];
+
+ /* determine number of values to copy out */
+ rx_in = info->rx_in;
+ if (info->rx_out <= rx_in) {
+ count = rx_in - info->rx_out;
+ } else {
+ count = (RX_BUFFER_SIZE - info->rx_out) + rx_in;
+ }
+
+ /* copy data into local buffer from rx buffer */
+ while ((index < count) && (index < RX_BUFFER_SIZE)) {
+ /* copy data byte */
+ buffer[index] = info->rx_buffer[info->rx_out];
+ index++;
+
+ /* increment rx buffer values */
+ info->rx_out++;
+ if (info->rx_out >= RX_BUFFER_SIZE) {
+ info->rx_out = 0;
+ }
+ }
+
+ /* check to see if buffer is not empty */
+ if (count > 0) {
+ /* set characters into termios buffer */
+ rtems_termios_enqueue_raw_characters(info->ttyp, buffer, count);
+ }
+
+ return (EOF);
+}
+
+/***************************************************************************
+ Function : IntUartPollRead
+
+ Description : This reads a character from the internal uart. It returns
+ to the caller without blocking if not character is waiting.
+ ***************************************************************************/
+static int IntUartPollRead(int minor)
+{
+ if ((MCF_UART_USR(minor) & MCF_UART_USR_RXRDY) == 0)
+ return (-1);
+
+ return (MCF_UART_URB(minor));
+}
+
+/***************************************************************************
+ Function : IntUartPollWrite
+
+ Description : This writes out each character in the buffer to the
+ appropriate internal uart channel waiting till each one is sucessfully
+ transmitted.
+ ***************************************************************************/
+static ssize_t IntUartPollWrite(int minor, const char *buf, size_t len)
+{
+ size_t retval = len;
+ /* loop over buffer */
+ while (len--) {
+ /* block until we can transmit */
+ while ((MCF_UART_USR(minor) & MCF_UART_USR_TXRDY) == 0)
+ continue;
+ /* transmit data byte */
+ MCF_UART_UTB(minor) = *buf++;
+ }
+ return retval;
+}
+
+/***************************************************************************
+ Function : console_initialize
+
+ Description : This initialises termios, both sets of uart hardware before
+ registering /dev/tty devices for each channel and the system /dev/console.
+ ***************************************************************************/
+rtems_device_driver console_initialize(rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg)
+{
+ rtems_status_code status;
+
+ /* Set up TERMIOS */
+ rtems_termios_initialize();
+
+ /* set io modes for the different channels and initialize device */
+ IntUartInfo[minor].iomode = TERMIOS_IRQ_DRIVEN;
+ IntUartInitialize();
+
+ /* Register the console port */
+ status = rtems_io_register_name("/dev/console", major, CONSOLE_PORT);
+ if (status != RTEMS_SUCCESSFUL) {
+ rtems_fatal_error_occurred(status);
+ }
+
+ /* Register the other port */
+ if (CONSOLE_PORT != 0) {
+ status = rtems_io_register_name("/dev/tty00", major, 0);
+ if (status != RTEMS_SUCCESSFUL) {
+ rtems_fatal_error_occurred(status);
+ }
+ }
+ if (CONSOLE_PORT != 1) {
+ status = rtems_io_register_name("/dev/tty01", major, 1);
+ if (status != RTEMS_SUCCESSFUL) {
+ rtems_fatal_error_occurred(status);
+ }
+ }
+
+ return (RTEMS_SUCCESSFUL);
+}
+
+/***************************************************************************
+ Function : console_open
+
+ Description : This actually opens the device depending on the minor
+ number set during initialisation. The device specific access routines are
+ passed to termios when the devices is opened depending on whether it is
+ polled or not.
+ ***************************************************************************/
+rtems_device_driver console_open(rtems_device_major_number major,
+ rtems_device_minor_number minor, void *arg)
+{
+ rtems_status_code status = RTEMS_INVALID_NUMBER;
+ rtems_libio_open_close_args_t *args = (rtems_libio_open_close_args_t *) arg;
+ struct IntUartInfoStruct *info;
+
+ static const rtems_termios_callbacks IntUartPollCallbacks = {
+ NULL, /* firstOpen */
+ NULL, /* lastClose */
+ IntUartPollRead, /* pollRead */
+ IntUartPollWrite, /* write */
+ IntUartSetAttributes, /* setAttributes */
+ NULL, /* stopRemoteTx */
+ NULL, /* startRemoteTx */
+ TERMIOS_POLLED /* mode */
+ };
+ static const rtems_termios_callbacks IntUartIntrCallbacks = {
+ IntUartInterruptOpen, /* firstOpen */
+ IntUartInterruptClose, /* lastClose */
+ NULL, /* pollRead */
+ IntUartInterruptWrite, /* write */
+ IntUartSetAttributes, /* setAttributes */
+ NULL, /* stopRemoteTx */
+ NULL, /* startRemoteTx */
+ TERMIOS_IRQ_DRIVEN /* mode */
+ };
+
+ static const rtems_termios_callbacks IntUartTaskCallbacks = {
+ IntUartInterruptOpen, /* firstOpen */
+ IntUartInterruptClose, /* lastClose */
+ IntUartTaskRead, /* pollRead */
+ IntUartInterruptWrite, /* write */
+ IntUartSetAttributes, /* setAttributes */
+ NULL, /* stopRemoteTx */
+ NULL, /* startRemoteTx */
+ TERMIOS_TASK_DRIVEN /* mode */
+ };
+
+ /* open the port depending on the minor device number */
+ if ((minor >= 0) && (minor < MAX_UART_INFO)) {
+ info = &IntUartInfo[minor];
+ switch (info->iomode) {
+ case TERMIOS_POLLED:
+ status = rtems_termios_open(major, minor, arg, &IntUartPollCallbacks);
+ break;
+ case TERMIOS_IRQ_DRIVEN:
+ status = rtems_termios_open(major, minor, arg, &IntUartIntrCallbacks);
+ info->ttyp = args->iop->data1;
+ break;
+ case TERMIOS_TASK_DRIVEN:
+ status = rtems_termios_open(major, minor, arg, &IntUartTaskCallbacks);
+ info->ttyp = args->iop->data1;
+ break;
+ }
+ }
+
+ if (status == RTEMS_SUCCESSFUL) {
+ /*
+ * Reset the default baudrate.
+ */
+ struct termios term;
+
+ if (tcgetattr(STDIN_FILENO, &term) >= 0) {
+ term.c_cflag &= ~(CSIZE);
+ term.c_cflag |= CS8;
+ term.c_ispeed = B19200;
+ term.c_ospeed = B19200;
+ tcsetattr(STDIN_FILENO, TCSANOW, &term);
+ }
+ }
+
+ return (status);
+}
+
+/***************************************************************************
+ Function : console_close
+
+ Description : This closes the device via termios
+ ***************************************************************************/
+rtems_device_driver console_close(rtems_device_major_number major,
+ rtems_device_minor_number minor, void *arg)
+{
+ return (rtems_termios_close(arg));
+}
+
+/***************************************************************************
+ Function : console_read
+
+ Description : Read from the device via termios
+ ***************************************************************************/
+rtems_device_driver console_read(rtems_device_major_number major,
+ rtems_device_minor_number minor, void *arg)
+{
+ return (rtems_termios_read(arg));
+}
+
+/***************************************************************************
+ Function : console_write
+
+ Description : Write to the device via termios
+ ***************************************************************************/
+rtems_device_driver console_write(rtems_device_major_number major,
+ rtems_device_minor_number minor, void *arg)
+{
+ return (rtems_termios_write(arg));
+}
+
+/***************************************************************************
+ Function : console_ioctl
+
+ Description : Pass the IOCtl call to termios
+ ***************************************************************************/
+rtems_device_driver console_control(rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg)
+{
+ return (rtems_termios_ioctl(arg));
+}
diff --git a/bsps/m68k/mrm332/console/console.c b/bsps/m68k/mrm332/console/console.c
new file mode 100644
index 0000000000..7b5ae7d51c
--- /dev/null
+++ b/bsps/m68k/mrm332/console/console.c
@@ -0,0 +1,155 @@
+/*
+ * COPYRIGHT (c) 1989-1997.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <termios.h>
+
+#include <rtems/console.h>
+#include <rtems/libio.h>
+#include <bsp.h>
+#include "sci.h"
+
+/*
+ * console_open
+ *
+ * open a port as a termios console.
+ */
+rtems_device_driver console_open(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+ rtems_status_code status;
+
+ /* the console is opened three times at startup */
+ /* for standard input, output, and error */
+
+ /* Get correct callback structure for the device */
+
+ /* argument of FALSE gives us interrupt driven serial io */
+ /* argument of TRUE gives us polling based serial io */
+
+ /* SCI internal uart */
+
+ status = rtems_termios_open( major, minor, arg, SciGetTermiosHandlers( FALSE ) );
+
+ return status;
+}
+
+/*
+ * console_close
+ *
+ * This routine closes a port that has been opened as console.
+ */
+rtems_device_driver console_close(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+ return rtems_termios_close (arg);
+}
+
+/*
+ * console_read
+ *
+ * This routine uses the termios driver to read a character.
+ */
+rtems_device_driver console_read(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+ return rtems_termios_read (arg);
+}
+
+/*
+ * console_write
+ *
+ * this routine uses the termios driver to write a character.
+ */
+rtems_device_driver console_write(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+ return rtems_termios_write (arg);
+}
+
+/*
+ * console_control
+ *
+ * this routine uses the termios driver to process io
+ */
+
+rtems_device_driver console_control(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+ return rtems_termios_ioctl (arg);
+}
+
+/*
+ * console_initialize
+ *
+ * Routine called to initialize the console device driver.
+ */
+rtems_device_driver console_initialize(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor_arg,
+ void *arg
+)
+{
+ rtems_status_code status;
+
+ /*
+ * initialize the termio interface.
+ */
+ rtems_termios_initialize();
+
+ /*
+ * register the SCI device name for termios
+ * do this over in the sci driver init routine?
+ */
+
+ status = rtems_io_register_name( "/dev/sci", major, 0 );
+
+ if (status != RTEMS_SUCCESSFUL)
+ {
+ rtems_fatal_error_occurred(status);
+ }
+
+ /*
+ * Link the uart device to the console device
+ */
+
+#if 1
+ status = rtems_io_register_name( "/dev/console", major, 0 );
+
+ if (status != RTEMS_SUCCESSFUL)
+ {
+ rtems_fatal_error_occurred(status);
+ }
+#else
+ if ( link( "/dev/sci", "/dev/console") < 0 )
+ {
+ rtems_fatal_error_occurred( RTEMS_IO_ERROR );
+ }
+#endif
+
+ /*
+ * Console Initialize Succesful
+ */
+
+ return RTEMS_SUCCESSFUL;
+}
diff --git a/bsps/m68k/mrm332/console/sci.c b/bsps/m68k/mrm332/console/sci.c
new file mode 100644
index 0000000000..c6b4933f13
--- /dev/null
+++ b/bsps/m68k/mrm332/console/sci.c
@@ -0,0 +1,1586 @@
+/*****************************************************************************
+* File: sci.c
+*
+* Desc: This file contains the console IO routines for the SCI port.
+* There are two interfaces in this module. One is for the rtems
+* termios/console code and the other is a device driver interface.
+* This module works together with the termio module which is
+* sometimes referred to as the "line disciplines" which implements
+* terminal i/o processing like tabs, backspaces, and newlines.
+* The rtems printf uses interrupt io and the rtems printk routine
+* uses polled io which is better for debugging.
+*
+* Index: Documentation
+* Section A - Include Files
+* Section B - Manifest Constants
+* Section C - External Data
+* Section D - External Functions
+* Section E - Local Functions
+* Section F - Local Variables
+* Section G - A circular data buffer for rcv chars
+* Section H - RTEMS termios callbacks for the interrupt api
+* Section I - RTEMS termios callbacks for the polled api
+
+* Section 0 - Miscellaneous routines
+* Section 1 - Routines to manipulate the circular buffer
+* Section 2 - Interrupt based entry points for the termios module
+* Section 3 - Polling based entry points for the termios module
+* Section 4 - Device driver public api entry points
+* Section 5 - Hardware level routines
+* Section 6 - Testing and debugging code
+*
+* Refer: Motorola QSM Reference Manual - Chapter 5 - SCI sub-module
+*
+* Note: See bsp.h,confdefs.h,system.h for installing drivers into RTEMS.
+*
+*****************************************************************************/
+
+/*****************************************************************************
+ Overview of serial port console terminal input/output
+*****************************************************************************/
+
+/*
+ +-----------+ +---------+
+ | app | | app |
+ +-----------+ +---------+
+ | |
+ | (printf,scanf,etc.) |
+ v |
+ +-----------+ |
+ | libc | |
+ +-----------+ |
+ | |
+ | |
+ | (open,close,read,write,ioctl) |
+ ======|==========================================|========================
+ | /dev/console | /dev/sci
+ | (stdin,stdout,stderr) |
+ ======|==========================================|========================
+ | |
+ | |
+ v v
+ +-----------+ +-----------+ +---------+
+ | console | <---> | termios | <---> | sci |
+ | driver | | module | | driver |
+ +-----------+ +-----------+ +---------+
+ |
+ |
+ v
+ +---------+
+ | |
+ | uart |
+ | |
+ +---------+
+*/
+
+
+/*****************************************************************************
+ Section A - Include Files
+*****************************************************************************/
+
+#include <rtems.h>
+#include <bsp.h>
+#include <rtems/bspIo.h>
+#include <stdio.h>
+#include <rtems/libio.h>
+#include <libchip/serial.h>
+#include <libchip/sersupp.h>
+#include "sci.h"
+#include <rtems/m68k/qsm.h>
+#include <inttypes.h>
+/*#include "../misc/include/cpu332.h" */
+
+/*****************************************************************************
+ Section B - Manifest Constants
+*****************************************************************************/
+
+#define SCI_MINOR 0 /* minor device number */
+
+/* IMPORTANT - if the device driver api is opened, it means the sci is being
+ * used for direct hardware access, so other users (like termios) get ignored
+ */
+#define DRIVER_CLOSED 0 /* the device driver api is closed */
+#define DRIVER_OPENED 1 /* the device driver api is opened */
+
+/* system clock definitions, i dont have documentation on this... */
+
+#if 0 /* Not needed, this is provided in mrm332.h */
+#define XTAL 32768.0 /* crystal frequency in Hz */
+#define NUMB_W 0 /* system clock parameters */
+#define NUMB_X 1
+#define NUMB_Y 0x38 /* for 14.942 Mhz */
+#define NUMB_Y 0x3F /* for 16.777 Mhz */
+
+#define SYS_CLOCK (XTAL * 4.0 * (NUMB_Y+1) * (1 << (2 * NUMB_W + NUMB_X)))
+
+#endif
+
+
+/*****************************************************************************
+ Section C - External Data
+*****************************************************************************/
+
+
+
+/*****************************************************************************
+ Section D - External Functions
+*****************************************************************************/
+
+
+
+/*****************************************************************************
+ Section E - Local Functions
+*****************************************************************************/
+
+void SCI_output_char(char c);
+
+/*rtems_isr SciIsr( rtems_vector_number vector ); interrupt handler */
+
+const rtems_termios_callbacks * SciGetTermiosHandlers( int32_t polled );
+
+rtems_device_driver SciInitialize( /* device driver api */
+ rtems_device_major_number, rtems_device_minor_number, void *);
+rtems_device_driver SciOpen( /* device driver api */
+ rtems_device_major_number, rtems_device_minor_number, void *);
+rtems_device_driver SciClose( /* device driver api */
+ rtems_device_major_number, rtems_device_minor_number, void *);
+rtems_device_driver SciRead( /* device driver api */
+ rtems_device_major_number, rtems_device_minor_number, void *);
+rtems_device_driver SciWrite( /* device driver api */
+ rtems_device_major_number, rtems_device_minor_number, void *);
+rtems_device_driver SciControl( /* device driver api */
+ rtems_device_major_number, rtems_device_minor_number, void *);
+rtems_device_driver SciRead (
+ rtems_device_major_number, rtems_device_minor_number, void *);
+
+rtems_isr SciIsr( rtems_vector_number vector );
+
+int SciInterruptOpen(int, int, void *); /* termios api */
+int SciInterruptClose(int, int, void *); /* termios api */
+ssize_t SciInterruptWrite(int, const char *, size_t); /* termios api */
+
+int SciSetAttributes(int, const struct termios*); /* termios api */
+int SciPolledOpen(int, int, void *); /* termios api */
+int SciPolledClose(int, int, void *); /* termios api */
+int SciPolledRead(int); /* termios api */
+ssize_t SciPolledWrite(int, const char *, size_t); /* termios api */
+
+static void SciSetBaud(uint32_t rate); /* hardware routine */
+static void SciSetDataBits(uint16_t bits); /* hardware routine */
+static void SciSetParity(uint16_t parity); /* hardware routine */
+
+static void inline SciDisableAllInterrupts( void ); /* hardware routine */
+static void inline SciDisableTransmitInterrupts( void );/* hardware routine */
+static void inline SciDisableReceiveInterrupts( void ); /* hardware routine */
+
+static void inline SciEnableTransmitInterrupts( void ); /* hardware routine */
+static void inline SciEnableReceiveInterrupts( void ); /* hardware routine */
+
+static void inline SciDisableReceiver( void ); /* hardware routine */
+static void inline SciDisableTransmitter( void ); /* hardware routine */
+
+static void inline SciEnableReceiver( void ); /* hardware routine */
+static void inline SciEnableTransmitter( void ); /* hardware routine */
+
+void SciWriteCharWait ( uint8_t ); /* hardware routine */
+void SciWriteCharNoWait( uint8_t ); /* hardware routine */
+
+uint8_t inline SciCharAvailable( void ); /* hardware routine */
+
+static uint8_t inline SciReadCharWait( void ); /* hardware routine */
+static uint8_t inline SciReadCharNoWait( void ); /* hardware routine */
+
+void SciSendBreak( void ); /* test routine */
+
+static int8_t SciRcvBufGetChar(void); /* circular rcv buf */
+static void SciRcvBufPutChar( uint8_t); /* circular rcv buf */
+#if 0
+static void SciRcvBufFlush( void ); /* unused routine */
+#endif
+
+void SciUnitTest(void); /* test routine */
+void SciPrintStats(void); /* test routine */
+
+
+/*****************************************************************************
+ Section F - Local Variables
+*****************************************************************************/
+
+static struct rtems_termios_tty *SciTermioTty;
+
+static uint8_t SciInited = 0; /* has the driver been inited */
+
+static uint8_t SciOpened; /* has the driver been opened */
+
+static uint8_t SciMajor; /* major device number */
+
+static uint16_t SciBaud; /* current value in baud register */
+
+static uint32_t SciBytesIn = 0; /* bytes received */
+static uint32_t SciBytesOut = 0; /* bytes transmitted */
+
+static uint32_t SciErrorsParity = 0; /* error counter */
+static uint32_t SciErrorsNoise = 0; /* error counter */
+static uint32_t SciErrorsFraming = 0; /* error counter */
+static uint32_t SciErrorsOverrun = 0; /* error counter */
+
+#if defined(CONSOLE_SCI)
+
+/* this is what rtems printk uses to do polling based output */
+
+BSP_output_char_function_type BSP_output_char = SCI_output_char;
+BSP_polling_getchar_function_type BSP_poll_char = NULL;
+
+#endif
+
+/*****************************************************************************
+ Section G - A circular buffer for rcv chars when the driver interface is used.
+*****************************************************************************/
+
+/* it is trivial to wrap your buffer pointers when size is a power of two */
+
+#define SCI_RCV_BUF_SIZE 256 /* must be a power of 2 !!! */
+
+/* if someone opens the sci device using the device driver interface,
+ * then the receive data interrupt handler will put characters in this buffer
+ * instead of sending them up to the termios module for the console
+ */
+static uint8_t SciRcvBuffer[SCI_RCV_BUF_SIZE];
+
+static uint8_t SciRcvBufPutIndex = 0; /* array index to put in next char */
+
+static uint8_t SciRcvBufGetIndex = 0; /* array index to take out next char */
+
+static uint16_t SciRcvBufCount = 0; /* how many bytes are in the buffer */
+
+
+
+/*****************************************************************************
+ Section H - RTEMS termios callbacks for the interrupt version of the driver
+*****************************************************************************/
+
+static const rtems_termios_callbacks SciInterruptCallbacks =
+{
+ SciInterruptOpen, /* first open */
+ SciInterruptClose, /* last close */
+ NULL, /* polled read (not required) */
+ SciInterruptWrite, /* write */
+ SciSetAttributes, /* set attributes */
+ NULL, /* stop remote xmit */
+ NULL, /* start remote xmit */
+ TRUE /* output uses interrupts */
+};
+
+/*****************************************************************************
+ Section I - RTEMS termios callbacks for the polled version of the driver
+*****************************************************************************/
+
+static const rtems_termios_callbacks SciPolledCallbacks =
+{
+ SciPolledOpen, /* first open */
+ SciPolledClose, /* last close */
+ SciPolledRead, /* polled read */
+ SciPolledWrite, /* write */
+ SciSetAttributes, /* set attributes */
+ NULL, /* stop remote xmit */
+ NULL, /* start remote xmit */
+ FALSE /* output uses interrupts */
+};
+
+
+/*
+ * SECTION 0
+ * MISCELLANEOUS ROUTINES
+ */
+
+/****************************************************************************
+ * Func: SCI_output_char
+ * Desc: used by rtems printk function to send a char to the uart
+ * Inputs: the character to transmit
+ * Outputs: none
+ * Errors: none
+ * Scope: public
+ ****************************************************************************/
+
+void SCI_output_char(char c)
+{
+/* ( minor device number, pointer to the character, length ) */
+
+ SciPolledWrite( SCI_MINOR, &c, 1);
+
+ return;
+}
+
+
+/****************************************************************************
+* Func: SciGetTermiosHandlers
+* Desc: returns a pointer to the table of serial io functions
+* this is called from console_open with polled set to false
+* Inputs: flag indicating whether we want polled or interrupt driven io
+* Outputs: pointer to function table
+* Errors: none
+* Scope: public
+****************************************************************************/
+
+const rtems_termios_callbacks * SciGetTermiosHandlers( int32_t polled )
+{
+ if ( polled )
+ {
+ return &SciPolledCallbacks; /* polling based */
+ }
+ else
+ {
+ return &SciInterruptCallbacks; /* interrupt driven */
+ }
+}
+
+
+/****************************************************************************
+* Func: SciIsr
+* Desc: interrupt handler for serial communications interface
+* Inputs: vector number - unused
+* Outputs: none
+* Errors: none
+* Scope: public API
+****************************************************************************/
+
+rtems_isr SciIsr( rtems_vector_number vector )
+{
+ uint8_t ch;
+
+ if ( (*SCSR) & SCI_ERROR_PARITY ) SciErrorsParity ++;
+ if ( (*SCSR) & SCI_ERROR_FRAMING ) SciErrorsFraming ++;
+ if ( (*SCSR) & SCI_ERROR_NOISE ) SciErrorsNoise ++;
+ if ( (*SCSR) & SCI_ERROR_OVERRUN ) SciErrorsOverrun ++;
+
+ /* see if it was a transmit interrupt */
+ /* data reg empty, xmt complete */
+ if ( ( *SCCR1 & SCI_ENABLE_INT_TX ) && ( (*SCSR) & SCI_XMTR_AVAILABLE ) )
+ {
+ SciDisableTransmitInterrupts();
+
+ /* tell termios module that the charcter was sent */
+ /* he will call us later to transmit more if there are any */
+
+ if (rtems_termios_dequeue_characters( SciTermioTty, 1 ))
+ {
+ /* there are more bytes to transmit so enable TX interrupt */
+
+ SciEnableTransmitInterrupts();
+ }
+ }
+
+ /* see if it was a receive interrupt */
+ /* on the sci uart we just get one character per interrupt */
+
+ while ( SciCharAvailable() ) /* char in data register? */
+ {
+ ch = SciReadCharNoWait(); /* get the char from the uart */
+
+ /* IMPORTANT!!! */
+ /* either send it to the termios module or keep it locally */
+
+ if ( SciOpened == DRIVER_OPENED ) /* the driver is open */
+ {
+ SciRcvBufPutChar(ch); /* keep it locally */
+ }
+ else /* put in termios buffer */
+ {
+ char c = (char) ch;
+ rtems_termios_enqueue_raw_characters( SciTermioTty, &c, 1 );
+ }
+
+ *SCSR &= SCI_CLEAR_RX_INT; /* clear the interrupt */
+ }
+}
+
+
+/*
+ * SECTION 1
+ * ROUTINES TO MANIPULATE THE CIRCULAR BUFFER
+ */
+
+/****************************************************************************
+* Func: SciRcvBufGetChar
+* Desc: read a character from the circular buffer
+* make sure there is data before you call this!
+* Inputs: none
+* Outputs: the character or -1
+* Errors: none
+* Scope: private
+****************************************************************************/
+
+static int8_t SciRcvBufGetChar(void)
+{
+ rtems_interrupt_level level;
+ uint8_t ch;
+
+ if ( SciRcvBufCount == 0 )
+ {
+ rtems_fatal_error_occurred(0xDEAD); /* check the count first! */
+ }
+
+ rtems_interrupt_disable( level ); /* disable interrupts */
+
+ ch = SciRcvBuffer[SciRcvBufGetIndex]; /* get next byte */
+
+ SciRcvBufGetIndex++; /* bump the index */
+
+ SciRcvBufGetIndex &= SCI_RCV_BUF_SIZE - 1; /* and wrap it */
+
+ SciRcvBufCount--; /* decrement counter */
+
+ rtems_interrupt_enable( level ); /* restore interrupts */
+
+ return ch; /* return the char */
+}
+
+
+/****************************************************************************
+* Func: SciRcvBufPutChar
+* Desc: put a character into the rcv data circular buffer
+* Inputs: the character
+* Outputs: none
+* Errors: none
+* Scope: private
+****************************************************************************/
+
+static void SciRcvBufPutChar( uint8_t ch )
+{
+ rtems_interrupt_level level;
+
+ if ( SciRcvBufCount == SCI_RCV_BUF_SIZE ) /* is there room? */
+ {
+ return; /* no, throw it away */
+ }
+
+ rtems_interrupt_disable( level ); /* disable interrupts */
+
+ SciRcvBuffer[SciRcvBufPutIndex] = ch; /* put it in the buf */
+
+ SciRcvBufPutIndex++; /* bump the index */
+
+ SciRcvBufPutIndex &= SCI_RCV_BUF_SIZE - 1; /* and wrap it */
+
+ SciRcvBufCount++; /* increment counter */
+
+ rtems_interrupt_enable( level ); /* restore interrupts */
+
+ return; /* return */
+}
+
+
+/****************************************************************************
+* Func: SciRcvBufFlush
+* Desc: completely reset and clear the rcv buffer
+* Inputs: none
+* Outputs: none
+* Errors: none
+* Scope: private
+****************************************************************************/
+
+#if 0 /* prevents compiler warning */
+static void SciRcvBufFlush( void )
+{
+ rtems_interrupt_level level;
+
+ rtems_interrupt_disable( level ); /* disable interrupts */
+
+ memset( SciRcvBuffer, 0, sizeof(SciRcvBuffer) );
+
+ SciRcvBufPutIndex = 0; /* clear */
+
+ SciRcvBufGetIndex = 0; /* clear */
+
+ SciRcvBufCount = 0; /* clear */
+
+ rtems_interrupt_enable( level ); /* restore interrupts */
+
+ return; /* return */
+}
+#endif
+
+
+/*
+ *
+ * SECTION 2
+ * INTERRUPT BASED ENTRY POINTS FOR THE TERMIOS MODULE
+ */
+
+/****************************************************************************
+* Func: SciInterruptOpen
+* Desc: open routine for the interrupt based device driver
+* Default state is 9600 baud, 8 bits, No parity, and 1 stop bit. ??
+**CHANGED** Default baud rate is now 19200, 8N1
+* called from rtems_termios_open which is called from console_open
+* Inputs: major - device number
+* minor - device number
+* args - points to terminal info
+* Outputs: success/fail
+* Errors: none
+* Scope: public API
+****************************************************************************/
+
+int SciInterruptOpen(
+ int major,
+ int minor,
+ void *arg
+)
+{
+ rtems_libio_open_close_args_t * args = arg;
+ rtems_isr_entry old_vector;
+
+ if ( minor != SCI_MINOR ) /* check minor device num */
+ {
+ return -1;
+ }
+
+ if ( !args ) /* must have args */
+ {
+ return -1;
+ }
+
+ SciTermioTty = args->iop->data1; /* save address of struct */
+
+ SciDisableAllInterrupts(); /* turn off sci interrupts */
+
+ /* THIS IS ACTUALLY A BAD THING - SETTING LINE PARAMETERS HERE */
+ /* IT SHOULD BE DONE THROUGH TCSETATTR() WHEN THE CONSOLE IS OPENED!!! */
+
+/* SciSetBaud(115200); set the baud rate */
+/* SciSetBaud( 57600); set the baud rate */
+/* SciSetBaud( 38400); set the baud rate */
+/* SciSetBaud( 19200); set the baud rate */
+ SciSetBaud( 9600); /* set the baud rate */
+
+ SciSetParity(SCI_PARITY_NONE); /* set parity to none */
+
+ SciSetDataBits(SCI_8_DATA_BITS); /* set data bits to 8 */
+
+ /* Install our interrupt handler into RTEMS. */
+ /* 68 is an unused user-defined vector. Note that the vector must be */
+ /* even - it sets the low bit for SPI interrupts, and clears it for */
+ /* SCI interrupts. Also note that vector 66 is used by CPU32bug on */
+ /* the mrm332. */
+
+ rtems_interrupt_catch( SciIsr, 68, &old_vector );
+
+ *QSMCR = (*QSMCR & ~IARB) | 1; // Is 1 a good value for qsm iarb?
+ *QIVR = 68;
+ *QILR &= 0xf8;
+ *QILR |= 0x06 & 0x07;
+
+ SciEnableTransmitter(); /* enable the transmitter */
+
+ SciEnableReceiver(); /* enable the receiver */
+
+ SciEnableReceiveInterrupts(); /* enable rcv interrupts */
+
+ return RTEMS_SUCCESSFUL;
+}
+
+
+/****************************************************************************
+* Func: SciInterruptClose
+* Desc: close routine called by the termios module
+* Inputs: major - device number
+* minor - device number
+* args - unused
+* Outputs: success/fail
+* Errors: none
+* Scope: public - termio entry point
+****************************************************************************/
+
+int SciInterruptClose(
+ int major,
+ int minor,
+ void *arg
+)
+{
+ SciDisableAllInterrupts();
+
+ return RTEMS_SUCCESSFUL;
+}
+
+
+/****************************************************************************
+* Func: SciInterruptWrite
+* Desc: writes data to the uart using transmit interrupts
+* Inputs: minor - device number
+* buf - points to the data
+* len - number of bytes to send
+* Outputs: success/fail
+* Errors: none
+* Scope: public API
+****************************************************************************/
+
+ssize_t SciInterruptWrite(
+ int minor,
+ const char *buf,
+ size_t len
+)
+{
+ /* We are using interrupt driven output so termios only sends us */
+ /* one character at a time. The sci does not have a fifo. */
+
+ if ( !len ) /* no data? */
+ {
+ return -1; /* return error */
+ }
+
+ if ( minor != SCI_MINOR ) /* check the minor dev num */
+ {
+ return -1; /* return error */
+ }
+
+ if ( SciOpened == DRIVER_OPENED ) /* is the driver api open? */
+ {
+ return -1; /* yep, throw this away */
+ }
+
+ SciWriteCharNoWait(*buf); /* try to send a char */
+
+ *SCSR &= SCI_CLEAR_TDRE; /* clear tx data reg empty flag */
+
+ SciEnableTransmitInterrupts(); /* enable the tx interrupt */
+
+ return 0; /* return success */
+}
+
+
+/****************************************************************************
+* Func: SciSetAttributes
+* Desc: setup the uart based on the termios modules requests
+* Inputs: minor - device number
+* t - pointer to the termios info struct
+* Outputs: none
+* Errors: none
+* Scope: public API
+****************************************************************************/
+
+int SciSetAttributes(
+ int minor,
+ const struct termios *t
+)
+{
+ uint32_t baud_requested;
+ uint32_t sci_rate = 0;
+ uint16_t sci_parity = 0;
+ uint16_t sci_databits = 0;
+
+ if ( minor != SCI_MINOR ) /* check the minor dev num */
+ {
+ return -1; /* return error */
+ }
+
+ /* if you look closely you will see this is the only thing we use */
+ /* set the baud rate */
+
+ baud_requested = t->c_ospeed; /* baud rate */
+
+ if (!baud_requested)
+ {
+ baud_requested = B9600; /* default to 9600 baud */
+ /* baud_requested = B19200; default to 19200 baud */
+ }
+
+ sci_rate = rtems_termios_baud_to_number( baud_requested );
+
+ /* parity error detection */
+
+ if (t->c_cflag & PARENB) /* enable parity detection? */
+ {
+ if (t->c_cflag & PARODD)
+ {
+ sci_parity = SCI_PARITY_ODD; /* select odd parity */
+ }
+ else
+ {
+ sci_parity = SCI_PARITY_EVEN; /* select even parity */
+ }
+ }
+ else
+ {
+ sci_parity = SCI_PARITY_NONE; /* no parity, most common */
+ }
+
+ /* set the number of data bits, 8 is most common */
+
+ if (t->c_cflag & CSIZE) /* was it specified? */
+ {
+ switch (t->c_cflag & CSIZE)
+ {
+ case CS8: sci_databits = SCI_8_DATA_BITS; break;
+ default : sci_databits = SCI_9_DATA_BITS; break;
+ }
+ }
+ else
+ {
+ sci_databits = SCI_8_DATA_BITS; /* default to 8 data bits */
+ }
+
+ /* the number of stop bits; always 1 for SCI */
+
+ if (t->c_cflag & CSTOPB)
+ {
+ /* do nothing */
+ }
+
+ /* setup the hardware with these serial port parameters */
+
+ SciSetBaud(sci_rate); /* set the baud rate */
+ SciSetParity(sci_parity); /* set the parity type */
+ SciSetDataBits(sci_databits); /* set the data bits */
+
+ return RTEMS_SUCCESSFUL;
+}
+
+
+/*
+ *
+ * SECTION 3
+ * POLLING BASED ENTRY POINTS FOR THE TERMIOS MODULE
+ */
+
+/****************************************************************************
+* Func: SciPolledOpen
+* Desc: open routine for the polled i/o version of the driver
+* called from rtems_termios_open which is called from console_open
+* Inputs: major - device number
+* minor - device number
+* args - points to terminal info struct
+* Outputs: success/fail
+* Errors: none
+* Scope: public - termios entry point
+****************************************************************************/
+
+int SciPolledOpen(
+ int major,
+ int minor,
+ void *arg
+)
+{
+ rtems_libio_open_close_args_t * args = arg;
+
+ if ( minor != SCI_MINOR ) /* check minor device num */
+ {
+ return -1;
+ }
+
+ if ( !args ) /* must have args */
+ {
+ return -1;
+ }
+
+ SciTermioTty = args->iop->data1; /* Store tty pointer */
+
+ SciDisableAllInterrupts(); /* don't generate interrupts */
+
+ /* THIS IS ACTUALLY A BAD THING - SETTING LINE PARAMETERS HERE */
+ /* IT SHOULD BE DONE THROUGH TCSETATTR() WHEN THE CONSOLE IS OPENED!!! */
+
+/* SciSetBaud(115200); set the baud rate */
+/* SciSetBaud( 57600); set the baud rate */
+/* SciSetBaud( 38400); set the baud rate */
+/* SciSetBaud( 19200); * set the baud rate */
+ SciSetBaud( 9600); /* set the baud rate */
+
+ SciSetParity(SCI_PARITY_NONE); /* set no parity */
+
+ SciSetDataBits(SCI_8_DATA_BITS); /* set 8 data bits */
+
+ SciEnableTransmitter(); /* enable the xmitter */
+
+ SciEnableReceiver(); /* enable the rcvr */
+
+ return RTEMS_SUCCESSFUL;
+}
+
+
+/****************************************************************************
+* Func: SciPolledClose
+* Desc: close routine for the device driver, same for both
+* Inputs: major - device number
+* minor - device number
+* args - unused
+* Outputs: success/fail
+* Errors: none
+* Scope: public termios API
+****************************************************************************/
+
+int SciPolledClose(
+ int major,
+ int minor,
+ void *arg
+)
+{
+ SciDisableAllInterrupts();
+
+ return RTEMS_SUCCESSFUL;
+}
+
+
+/****************************************************************************
+* Func: SciPolledRead
+* Desc: polling based read routine for the uart
+* Inputs: minor - device number
+* Outputs: error or the character read
+* Errors: none
+* Scope: public API
+****************************************************************************/
+
+int SciPolledRead(
+ int minor
+)
+{
+ if ( minor != SCI_MINOR ) /* check the type-punned dev num */
+ {
+ return -1; /* return error */
+ }
+
+ if ( SciCharAvailable() ) /* if a char is available */
+ {
+ return SciReadCharNoWait(); /* read the rx data register */
+ }
+
+ return -1; /* return error */
+}
+
+
+/****************************************************************************
+* Func: SciPolledWrite
+* Desc: writes out characters in polled mode, waiting for the uart
+* check in console_open, but we only seem to use interrupt mode
+* Inputs: minor - device number
+* buf - points to the data
+* len - how many bytes
+* Outputs: error or number of bytes written
+* Errors: none
+* Scope: public termios API
+****************************************************************************/
+
+ssize_t SciPolledWrite(
+ int minor,
+ const char *buf,
+ size_t len
+)
+{
+ ssize_t written = 0;
+
+ if ( minor != SCI_MINOR ) /* check minor device num */
+ {
+ return -1;
+ }
+
+ if ( SciOpened == DRIVER_OPENED ) /* is the driver api open? */
+ {
+ return -1; /* toss the data */
+ }
+
+ /* send each byte in the string out the port */
+
+ while ( written < len )
+ {
+ SciWriteCharWait(*buf++); /* send a byte */
+
+ written++; /* increment counter */
+ }
+
+ return written; /* return count */
+}
+
+
+/*
+ *
+ * SECTION 4
+ * DEVICE DRIVER PUBLIC API ENTRY POINTS
+ */
+
+/****************************************************************************
+* Func: SciInit
+* Desc: Initialize the lasers device driver and hardware
+* Inputs: major - the major device number which is assigned by rtems
+* minor - the minor device number which is undefined at this point
+* arg - ?????
+* Outputs: RTEMS_SUCCESSFUL
+* Errors: None.
+* Scope: public API
+****************************************************************************/
+
+rtems_device_driver SciInitialize (
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+/* rtems_status_code status; */
+
+/*printk("%s\r\n", __FUNCTION__); */
+
+ /* register the SCI device name for termios console i/o
+ * this is done over in console.c which doesn't seem exactly right
+ * but there were problems doing it here...
+ */
+
+/* status = rtems_io_register_name( "/dev/sci", major, 0 ); */
+
+/* if (status != RTEMS_SUCCESSFUL) */
+/* rtems_fatal_error_occurred(status); */
+
+ SciMajor = major; /* save the rtems major number */
+
+ SciOpened = DRIVER_CLOSED; /* initial state is closed */
+
+ /* if you have an interrupt handler, install it here */
+
+ SciInited = 1; /* set the inited flag */
+
+ return RTEMS_SUCCESSFUL;
+}
+
+
+/****************************************************************************
+* Func: SciOpen
+* Desc: device driver open routine
+* you must open a device before you can anything else
+* only one process can have the device opened at a time
+* you could look at the task id to restrict access if you want
+* Inputs: major - the major device number assigned by rtems
+* minor - the minor device number assigned by us
+* arg - ?????
+* Outputs: see below
+* Errors: none
+* Scope: public API
+****************************************************************************/
+
+rtems_device_driver SciOpen (
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+/*printk("%s major=%d minor=%d\r\n", __FUNCTION__,major,minor); */
+
+ if (SciInited == 0) /* must be initialized first! */
+ {
+ return RTEMS_NOT_CONFIGURED;
+ }
+
+ if (minor != SCI_MINOR)
+ {
+ return RTEMS_INVALID_NAME; /* verify minor number */
+ }
+
+ if (SciOpened == DRIVER_OPENED)
+ {
+ return RTEMS_RESOURCE_IN_USE; /* already opened! */
+ }
+
+ SciOpened = DRIVER_OPENED; /* set the opened flag */
+
+ return RTEMS_SUCCESSFUL;
+}
+
+
+/****************************************************************************
+* Func: SciClose
+* Desc: device driver close routine
+* the device must be opened before you can close it
+* the device must be closed before someone (else) can open it
+* Inputs: major - the major device number
+* minor - the minor device number
+* arg - ?????
+* Outputs: see below
+* Errors: none
+* Scope: public API
+****************************************************************************/
+
+rtems_device_driver SciClose (
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+/*printk("%s major=%d minor=%d\r\n", __FUNCTION__,major,minor); */
+
+ if (minor != SCI_MINOR)
+ {
+ return RTEMS_INVALID_NAME; /* check the minor number */
+ }
+
+ if (SciOpened != DRIVER_OPENED)
+ {
+ return RTEMS_INCORRECT_STATE; /* must be opened first */
+ }
+
+ SciOpened = DRIVER_CLOSED; /* set the flag */
+
+ return RTEMS_SUCCESSFUL;
+}
+
+
+/****************************************************************************
+* Func: SciRead
+* Desc: device driver read routine
+* this function is not meaningful for the laser devices
+* Inputs: major - the major device number
+* minor - the minor device number
+* arg - read/write arguments
+* Outputs: see below
+* Errors: none
+* Scope: public API
+****************************************************************************/
+
+rtems_device_driver SciRead (
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg
+)
+{
+ rtems_libio_rw_args_t *rw_args; /* ptr to argument struct */
+ char *buffer;
+
+ rw_args = (rtems_libio_rw_args_t *) arg; /* arguments to read() */
+
+ if (minor != SCI_MINOR)
+ {
+ return RTEMS_INVALID_NAME; /* check the minor number */
+ }
+
+ if (SciOpened == DRIVER_CLOSED)
+ {
+ return RTEMS_INCORRECT_STATE; /* must be opened first */
+ }
+
+ buffer = rw_args->buffer; /* points to user's buffer */
+
+/* *buffer = SciReadCharWait(); wait for a character */
+
+ /* if there isn't a character available, wait until one shows up */
+ /* or the timeout period expires, which ever happens first */
+
+ if ( SciRcvBufCount == 0 ) /* no chars */
+ {
+ /* wait for someone to wake me up... */
+ /*rtems_task_wake_after(SciReadTimeout); */
+ }
+
+ if ( SciRcvBufCount ) /* any characters locally? */
+ {
+ *buffer = SciRcvBufGetChar(); /* get the character */
+
+ rw_args->bytes_moved = 1; /* how many we actually read */
+ }
+
+ return RTEMS_SUCCESSFUL;
+}
+
+
+/****************************************************************************
+* Func: SciWrite
+* Desc: device driver write routine
+* this function is not meaningful for the laser devices
+* Inputs: major - the major device number
+* minor - the minor device number
+* arg - read/write arguments
+* Outputs: see below
+* Errors: non3
+* Scope: public API
+****************************************************************************/
+
+rtems_device_driver SciWrite (
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+ rtems_libio_rw_args_t *rw_args; /* ptr to argument struct */
+ uint8_t *buffer;
+ size_t length;
+
+ rw_args = (rtems_libio_rw_args_t *) arg;
+
+ if (minor != SCI_MINOR)
+ {
+ return RTEMS_INVALID_NAME; /* check the minor number */
+ }
+
+ if (SciOpened == DRIVER_CLOSED)
+ {
+ return RTEMS_INCORRECT_STATE; /* must be opened first */
+ }
+
+ buffer = (uint8_t*)rw_args->buffer; /* points to data */
+
+ length = rw_args->count; /* how many bytes */
+
+ while (length--)
+ {
+ SciWriteCharWait(*buffer++); /* send the bytes out */
+ }
+
+ rw_args->bytes_moved = rw_args->count; /* how many we wrote */
+
+ return RTEMS_SUCCESSFUL;
+}
+
+
+/****************************************************************************
+* Func: SciControl
+* Desc: device driver control routine
+* see below for an example of how to use the ioctl interface
+* Inputs: major - the major device number
+* minor - the minor device number
+* arg - io control args
+* Outputs: see below
+* Errors: none
+* Scope: public API
+****************************************************************************/
+
+rtems_device_driver SciControl (
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+ rtems_libio_ioctl_args_t *args = arg; /* rtems arg struct */
+ uint16_t command; /* the cmd to execute */
+
+/*printk("%s major=%d minor=%d\r\n", __FUNCTION__,major,minor); */
+
+ /* do some sanity checking */
+
+ if (minor != SCI_MINOR)
+ {
+ return RTEMS_INVALID_NAME; /* check the minor number */
+ }
+
+ if (SciOpened == DRIVER_CLOSED)
+ {
+ return RTEMS_INCORRECT_STATE; /* must be open first */
+ }
+
+ if (args == 0)
+ {
+ return RTEMS_INVALID_ADDRESS; /* must have args */
+ }
+
+ args->ioctl_return = -1; /* assume an error */
+
+ command = args->command; /* get the command */
+
+ if (command == SCI_SEND_BREAK) /* process the command */
+ {
+ SciSendBreak(); /* send break char */
+ }
+
+ args->ioctl_return = 0; /* return status */
+
+ return RTEMS_SUCCESSFUL;
+}
+
+
+/*
+ *
+ * SECTION 5
+ * HARDWARE LEVEL ROUTINES
+ */
+
+/****************************************************************************
+* Func: SciSetBaud
+* Desc: setup the uart based on the termios modules requests
+* Inputs: baud rate
+* Outputs: none
+* Errors: none
+* Scope: private
+****************************************************************************/
+
+static void SciSetBaud(uint32_t rate)
+{
+ uint16_t value;
+ uint16_t save_sccr1;
+
+/* when you open the console you need to set the termio struct baud rate */
+/* it has a default value of 9600, when someone calls tcsetattr it reverts! */
+
+ SciBaud = rate; /* save the rate */
+
+ /* calculate the register value as a float and convert to an int */
+ /* set baud rate - you must define the system clock constant */
+ /* see mrm332.h for an example */
+
+ value = ( (uint16_t) ( SYS_CLOCK / rate / 32.0 + 0.5 ) & 0x1fff );
+
+ save_sccr1 = *SCCR1; /* save register */
+
+ /* also turns off the xmtr and rcvr */
+
+ *SCCR1 &= SCI_DISABLE_INT_ALL; /* disable interrupts */
+
+ *SCCR0 = value; /* write the register */
+
+ *SCCR1 = save_sccr1; /* restore register */
+
+ return;
+}
+
+
+/****************************************************************************
+* Func: SciSetParity
+* Desc: setup the uart based on the termios modules requests
+* Inputs: parity
+* Outputs: none
+* Errors: none
+* Scope: private
+****************************************************************************/
+
+static void SciSetParity(uint16_t parity)
+{
+ uint16_t value;
+
+ value = *SCCR1; /* get the register */
+
+ if (parity == SCI_PARITY_ODD)
+ {
+ value |= SCI_PARITY_ENABLE; /* parity enabled */
+ value |= SCI_PARITY_ODD; /* parity odd */
+ }
+
+ else if (parity == SCI_PARITY_EVEN)
+ {
+ value |= SCI_PARITY_ENABLE; /* parity enabled */
+ value &= ~SCI_PARITY_ODD; /* parity even */
+ }
+
+ else if (parity == SCI_PARITY_NONE)
+ {
+ value &= ~SCI_PARITY_ENABLE; /* disabled, most common */
+ }
+
+ /* else no changes */
+
+ *SCCR1 = value; /* write the register */
+
+ return;
+}
+
+
+/****************************************************************************
+* Func: SciSetDataBits
+* Desc: setup the uart based on the termios modules requests
+* Inputs: data bits
+* Outputs: none
+* Errors: none
+* Scope: private
+****************************************************************************/
+
+static void SciSetDataBits(uint16_t bits)
+{
+ uint16_t value;
+
+ value = *SCCR1; /* get the register */
+
+ /* note - the parity setting affects the number of data bits */
+
+ if (bits == SCI_9_DATA_BITS)
+ {
+ value |= SCI_9_DATA_BITS; /* 9 data bits */
+ }
+
+ else if (bits == SCI_8_DATA_BITS)
+ {
+ value &= SCI_8_DATA_BITS; /* 8 data bits */
+ }
+
+ /* else no changes */
+
+ *SCCR1 = value; /* write the register */
+
+ return;
+}
+
+
+/****************************************************************************
+* Func: SciDisableAllInterrupts
+* Func: SciEnableTransmitInterrupts
+* Func: SciEnableReceiveInterrupts
+* Desc: handles generation of interrupts by the sci module
+* Inputs: none
+* Outputs: none
+* Errors: none
+* Scope: private
+****************************************************************************/
+
+static void inline SciDisableAllInterrupts( void )
+{
+ /* this also turns off the xmtr and rcvr */
+
+ *SCCR1 &= SCI_DISABLE_INT_ALL;
+}
+
+static void inline SciEnableReceiveInterrupts( void )
+{
+ *SCCR1 |= SCI_ENABLE_INT_RX;
+}
+
+static void inline SciDisableReceiveInterrupts( void )
+{
+ *SCCR1 &= SCI_DISABLE_INT_RX;
+}
+
+static void inline SciEnableTransmitInterrupts( void )
+{
+ *SCCR1 |= SCI_ENABLE_INT_TX;
+}
+
+static void inline SciDisableTransmitInterrupts( void )
+{
+ *SCCR1 &= SCI_DISABLE_INT_TX;
+}
+
+
+/****************************************************************************
+* Func: SciEnableTransmitter, SciDisableTransmitter
+* Func: SciEnableReceiver, SciDisableReceiver
+* Desc: turns the transmitter and receiver on and off
+* Inputs: none
+* Outputs: none
+* Errors: none
+* Scope: private
+****************************************************************************/
+
+static void inline SciEnableTransmitter( void )
+{
+ *SCCR1 |= SCI_ENABLE_XMTR;
+}
+
+static void inline SciDisableTransmitter( void )
+{
+ *SCCR1 &= SCI_DISABLE_XMTR;
+}
+
+static void inline SciEnableReceiver( void )
+{
+ *SCCR1 |= SCI_ENABLE_RCVR;
+}
+
+static void inline SciDisableReceiver( void )
+{
+ *SCCR1 &= SCI_DISABLE_RCVR;
+}
+
+
+/****************************************************************************
+* Func: SciWriteCharWait
+* Desc: wait for room in the fifo and then put a char in
+* Inputs: a byte to send
+* Outputs: none
+* Errors: none
+* Scope: public
+****************************************************************************/
+
+void SciWriteCharWait(uint8_t c)
+{
+ /* poll the fifo, waiting for room for another character */
+
+ while ( ( *SCSR & SCI_XMTR_AVAILABLE ) != SCI_XMTR_AVAILABLE )
+ {
+ /* Either we are writing to the fifo faster than
+ * the uart can clock bytes out onto the cable,
+ * or we are in flow control (actually no, we
+ * are ignoring flow control from the other end).
+ * In the first case, higher baud rates will help.
+ */
+ /* relinquish processor while waiting */
+ rtems_task_wake_after(RTEMS_YIELD_PROCESSOR);
+ }
+
+ *SCDR = c; /* send the charcter */
+
+ SciBytesOut++; /* increment the counter */
+
+ return;
+}
+
+/****************************************************************************
+* Func: SciWriteCharNoWait
+* Desc: if no room in the fifo throw the char on the floor
+* Inputs: a byte to send
+* Outputs: none
+* Errors: none
+* Scope: public
+****************************************************************************/
+
+void SciWriteCharNoWait(uint8_t c)
+{
+ if ( ( *SCSR & SCI_XMTR_AVAILABLE ) == 0 )
+ {
+ return; /* no room, throw it away */
+ }
+
+ *SCDR = c; /* put the char in the fifo */
+
+ SciBytesOut++; /* increment the counter */
+
+ return;
+}
+
+
+/****************************************************************************
+* Func: SciReadCharWait
+* Desc: read a character, waiting for one to show up, if need be
+* Inputs: none
+* Outputs: a character
+* Errors: none
+* Scope: public
+****************************************************************************/
+
+static uint8_t inline SciReadCharWait( void )
+{
+ uint8_t ch;
+
+ while ( SciCharAvailable() == 0 ) /* anything there? */
+ {
+ /* relinquish processor while waiting */
+ rtems_task_wake_after(RTEMS_YIELD_PROCESSOR);
+ }
+
+ /* if you have rcv ints enabled, then the isr will probably */
+ /* get the character before you will unless you turn off ints */
+ /* ie polling and ints don't mix that well */
+
+ ch = *SCDR; /* get the charcter */
+
+ SciBytesIn++; /* increment the counter */
+
+ return ch; /* return the char */
+}
+
+/****************************************************************************
+* Func: SciReadCharNoWait
+* Desc: try to get a char but dont wait for one
+* Inputs: none
+* Outputs: a character or -1 if none
+* Errors: none
+* Scope: public
+****************************************************************************/
+
+static uint8_t inline SciReadCharNoWait( void )
+{
+ uint8_t ch;
+
+ if ( SciCharAvailable() == 0 ) /* anything there? */
+ return -1;
+
+ ch = *SCDR; /* get the character */
+
+ SciBytesIn++; /* increment the count */
+
+ return ch; /* return the char */
+}
+
+
+/****************************************************************************
+* Func: SciCharAvailable
+* Desc: is there a receive character in the data register
+* Inputs: none
+* Outputs: false if no char available, else true
+* Errors: none
+* Scope: public
+****************************************************************************/
+
+uint8_t inline SciCharAvailable( void )
+{
+ return ( *SCSR & SCI_RCVR_READY ); /* char in data register? */
+}
+
+
+/****************************************************************************
+* Func: SciSendBreak
+* Desc: send 1 or tow breaks (all zero bits)
+* Inputs: none
+* Outputs: none
+* Errors: none
+* Scope: public
+****************************************************************************/
+
+void SciSendBreak( void )
+{
+ /* From the Motorola QSM reference manual - */
+
+ /* "if SBK is toggled by writing it first to a one and then immediately */
+ /* to a zero (in less than one serial frame interval), the transmitter */
+ /* sends only one or two break frames before reverting to mark (idle) */
+ /* or before commencing to send more data" */
+
+ *SCCR1 |= SCI_SEND_BREAK; /* set the bit */
+
+ *SCCR1 &= ~SCI_SEND_BREAK; /* clear the bit */
+
+ return;
+}
+
+
+/*
+ *
+ * SECTION 6
+ * TEST CODE
+ */
+
+/****************************************************************************
+* Func: SciUnitTest
+* Desc: test the device driver
+* Inputs: nothing
+* Outputs: nothing
+* Scope: public
+****************************************************************************/
+
+#if 0
+void SciUnitTest()
+{
+ uint8_t byte; /* a character */
+ uint16_t fd; /* file descriptor for device */
+ uint16_t result; /* result of ioctl */
+
+ fd = open("/dev/sci",O_RDWR); /* open the device */
+
+printk("SCI open fd=%d\r\n",fd);
+
+ result = write(fd, "abcd\r\n", 6); /* send a string */
+
+printk("SCI write result=%d\r\n",result);
+
+ result = read(fd, &byte, 1); /* read a byte */
+
+printk("SCI read result=%d,byte=%x\r\n",result,byte);
+
+ return;
+}
+#endif
+
+
+/****************************************************************************
+* Func: SciPrintStats
+* Desc: print out some driver information
+* Inputs: nothing
+* Outputs: nothing
+* Scope: public
+****************************************************************************/
+
+void SciPrintStats ( void )
+{
+ printk("\r\n");
+
+ printk( "SYS_CLOCK is %2.6f Mhz\r\n\n", SYS_CLOCK / 1000000.0 );
+
+ printk( "Current baud rate is %d bps or %d cps\r\n\n", SciBaud, SciBaud / 10 );
+
+ printk( "SCI Uart chars in %8" PRIu32 "\r\n", SciBytesIn );
+ printk( "SCI Uart chars out %8" PRIu32 "\r\n", SciBytesOut );
+ printk( "SCI Uart framing errors %8" PRIu32 "\r\n", SciErrorsFraming );
+ printk( "SCI Uart parity errors %8" PRIu32 "\r\n", SciErrorsParity );
+ printk( "SCI Uart overrun errors %8" PRIu32 "\r\n", SciErrorsOverrun );
+ printk( "SCI Uart noise errors %8" PRIu32 "\r\n", SciErrorsNoise );
+
+ return;
+}
diff --git a/bsps/m68k/mrm332/console/sci.h b/bsps/m68k/mrm332/console/sci.h
new file mode 100644
index 0000000000..93893ecbfc
--- /dev/null
+++ b/bsps/m68k/mrm332/console/sci.h
@@ -0,0 +1,233 @@
+/****************************************************************************
+* File: sci.h
+*
+* Desc: This is the include file for the serial communications interface.
+*
+* Note: See bsp.h,confdefs.h,system.h for installing drivers into RTEMS.
+*
+****************************************************************************/
+
+#ifndef _sci_h_
+#define _sci_h_
+
+/*******************************************************************************
+ IOCTL commands for the sci driver.
+ I'm still working on these...
+*******************************************************************************/
+
+#define SCI_IOCTL_PARITY_NONE 0x00 /* no parity bit after the data bits */
+#define SCI_IOCTL_PARITY_ODD 0x01 /* parity bit added after data bits */
+#define SCI_IOCTL_PARITY_EVEN 0x02 /* parity bit added after data bits */
+#define SCI_IOCTL_PARITY_MARK 0x03 /* parity bit is lo, -12 volts, logical 1 */
+#define SCI_IOCTL_PARITY_SPACE 0x04 /* parity bit is hi, +12 volts, logical 0 */
+#define SCI_IOCTL_PARITY_FORCED_ON 0x03 /* parity bit is forced hi or lo */
+#define SCI_IOCTL_PARITY_FORCED_OFF 0x04 /* parity bit is forced hi or lo */
+
+#define SCI_IOCTL_BAUD_RATE 0x20 /* set the baud rate, arg is baud */
+
+#define SCI_IOCTL_DATA_BITS 0x30 /* set the data bits, arg is # bits */
+
+#define SCI_IOCTL_STOP_BITS_1 0x40 /* 1 stop bit after char frame */
+#define SCI_IOCTL_STOP_BITS_2 0x41 /* 2 stop bit after char frame */
+
+#define SCI_IOCTL_MODE_NORMAL 0x50 /* normal operating mode */
+#define SCI_IOCTL_MODE_LOOP 0x51 /* internal loopback mode */
+
+#define SCI_IOCTL_FLOW_NONE 0x60 /* no flow control */
+#define SCI_IOCTL_FLOW_RTS_CTS 0x61 /* hardware flow control */
+
+#define SCI_IOCTL_SEND_BREAK 0x70 /* send an rs-232 break */
+
+#define SCI_IOCTL_MODE_1200 0x80 /* 1200,n,8,1 download mode */
+#define SCI_IOCTL_MODE_9600 0x81 /* 9600,n,8,1 download mode */
+#define SCI_IOCTL_MODE_9_BIT 0x82 /* 9600,forced,8,1 command mode */
+
+
+/*******************************************************************************
+ SCI Registers
+*******************************************************************************/
+
+/* SCI Control Register 0 (SCCR0) $FFFC08
+
+ 8 4 2 1 - 8 4 2 1 - 8 4 2 1 - 8 4 2 1
+ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
+ | | | | | | | | | | | | | | | |
+ | | | | | | | | | | | | | | | +----- 0 baud rate divisor
+ | | | | | | | | | | | | | | +------- 1 baud rate divisor
+ | | | | | | | | | | | | | +--------- 2 baud rate divisor
+ | | | | | | | | | | | | +----------- 3 baud rate divisor
+ | | | | | | | | | | | |
+ | | | | | | | | | | | +--------------- 4 baud rate divisor
+ | | | | | | | | | | +----------------- 5 baud rate divisor
+ | | | | | | | | | +------------------- 6 baud rate divisor
+ | | | | | | | | +--------------------- 7 baud rate divisor
+ | | | | | | | |
+ | | | | | | | +------------------------- 8 baud rate divisor
+ | | | | | | +--------------------------- 9 baud rate divisor
+ | | | | | +----------------------------- 10 baud rate divisor
+ | | | | +------------------------------- 11 baud rate divisor
+ | | | |
+ | | | +----------------------------------- 12 baud rate divisor
+ | | +------------------------------------- 13 unused
+ | +--------------------------------------- 14 unused
+ +----------------------------------------- 15 unused
+
+ 0 0 0 0 - 0 0 0 0 - 0 0 0 0 - 0 1 0 0 reset value - (64k baud?)
+ */
+
+#define SCI_BAUD_57_6K 9
+#define SCI_BAUD_38_4K 14
+#define SCI_BAUD_19_2K 27
+#define SCI_BAUD_9600 55
+#define SCI_BAUD_4800 109
+#define SCI_BAUD_2400 218
+#define SCI_BAUD_1200 437
+
+
+/* SCI Control Register 1 (SCCR1) $FFFC0A
+
+ 8 4 2 1 - 8 4 2 1 - 8 4 2 1 - 8 4 2 1
+ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
+ | | | | | | | | | | | | | | | |
+ | | | | | | | | | | | | | | | +----- 0 send a break
+ | | | | | | | | | | | | | | +------- 1 rcvr wakeup mode
+ | | | | | | | | | | | | | +--------- 2 rcvr enable
+ | | | | | | | | | | | | +----------- 3 xmtr enable
+ | | | | | | | | | | | |
+ | | | | | | | | | | | +--------------- 4 idle line intr enable
+ | | | | | | | | | | +----------------- 5 rcvr intr enable
+ | | | | | | | | | +------------------- 6 xmit complete intr enable
+ | | | | | | | | +--------------------- 7 xmtr intr enable
+ | | | | | | | |
+ | | | | | | | +------------------------- 8 wakeup on address mark
+ | | | | | | +--------------------------- 9 mode 1=9 bits, 0=8 bits
+ | | | | | +----------------------------- 10 parity enable 1=on, 0=off
+ | | | | +------------------------------- 11 parity type 1=odd, 0=even
+ | | | |
+ | | | +----------------------------------- 12 idle line select
+ | | +------------------------------------- 13 wired-or mode
+ | +--------------------------------------- 14 loop mode
+ +----------------------------------------- 15 unused
+
+ 0 0 0 0 - 0 0 0 0 - 0 0 0 0 - 0 0 0 0 reset value
+*/
+
+#define SCI_SEND_BREAK 0x0001 /* 0000-0000-0000-0001 */
+#define SCI_RCVR_WAKEUP 0x0002 /* 0000-0000-0000-0010 */
+#define SCI_ENABLE_RCVR 0x0004 /* 0000-0000-0000-0100 */
+#define SCI_ENABLE_XMTR 0x0008 /* 0000-0000-0000-1000 */
+
+#define SCI_DISABLE_RCVR 0xFFFB /* 1111-1111-1111-1011 */
+#define SCI_DISABLE_XMTR 0xFFF7 /* 1111-1111-1111-0111 */
+
+#define SCI_ENABLE_INT_IDLE 0x0010 /* 0000-0000-0001-0000 */
+#define SCI_ENABLE_INT_RX 0x0020 /* 0000-0000-0010-0000 */
+#define SCI_ENABLE_INT_TX_DONE 0x0040 /* 0000-0000-0100-0000 */
+#define SCI_ENABLE_INT_TX 0x0080 /* 0000-0000-1000-0000 */
+
+#define SCI_DISABLE_INT_ALL 0xFF00 /* 1111-1111-0000-0000 ??? */
+
+#define SCI_DISABLE_INT_RX 0xFFDF /* 1111-1111-1101-1111 */
+#define SCI_CLEAR_RX_INT 0xFFBF /* 1111-1111-1011-1111 */
+#define SCI_DISABLE_INT_TX 0xFF7F /* 1111-1111-0111-1111 */
+#define SCI_CLEAR_TDRE 0xFEFF /* 1111-1110-1111-1111 */
+
+#define SCI_RCVR_WAKE_ON_MARK 0x0100 /* 0000-0001-0000-0000 */
+#define SCI_9_DATA_BITS 0x0200 /* 0000-0010-0000-0000 */
+#define SCI_PARITY_ENABLE 0x0400 /* 0000-0100-0000-0000 */
+#define SCI_PARITY_ODD 0x0800 /* 0000-1000-0000-0000 */
+
+#define SCI_RCVR_WAKE_ON_IDLE 0xFEFF /* 1111-1110-1111-1111 */
+#define SCI_8_DATA_BITS 0xFDFF /* 1111-1101-1111-1111 */
+#define SCI_PARITY_DISABLE 0xFBFF /* 1111-1011-1111-1111 */
+#define SCI_PARITY_EVEN 0xF7FF /* 1111-0111-1111-1111 */
+
+#define SCI_PARITY_NONE 0xF3FF /* 1111-0011-1111-1111 */
+
+#define SCI_IDLE_LINE_LONG 0x1000 /* 0001-0000-0000-0000 */
+#define SCI_TXD_OPEN_DRAIN 0x2000 /* 0010-0000-0000-0000 */
+#define SCI_LOOPBACK_MODE 0x4000 /* 0100-0000-0000-0000 */
+#define SCI_SCCR1_UNUSED 0x8000 /* 1000-0000-0000-0000 */
+
+
+/* SCI Status Register (SCSR) $FFFC0C
+
+ 8 4 2 1 - 8 4 2 1 - 8 4 2 1 - 8 4 2 1
+ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
+ | | | | | | | | | | | | | | | |
+ | | | | | | | | | | | | | | | +----- 0 PF - parity error
+ | | | | | | | | | | | | | | +------- 1 FE - framing error
+ | | | | | | | | | | | | | +--------- 2 NF - noise flag
+ | | | | | | | | | | | | +----------- 3 OR - overrun flag
+ | | | | | | | | | | | |
+ | | | | | | | | | | | +--------------- 4 IDLE - idle line detected
+ | | | | | | | | | | +----------------- 5 RAF - rcvr active flag
+ | | | | | | | | | +------------------- 6 RDRF - rcv data reg full
+ | | | | | | | | +--------------------- 7 TC - xmt complete flag
+ | | | | | | | |
+ | | | | | | | +------------------------- 8 TDRE - xmt data reg empty
+ | | | | | | +--------------------------- 9 always zero
+ | | | | | +----------------------------- 10 always zero
+ | | | | +------------------------------- 11 always zero
+ | | | |
+ | | | +----------------------------------- 12 always zero
+ | | +------------------------------------- 13 always zero
+ | +--------------------------------------- 14 always zero
+ +----------------------------------------- 15 always zero
+
+ 0 0 0 0 - 0 0 0 1 - 1 0 0 0 - 0 0 0 0 reset value
+*/
+
+#define SCI_ERROR_PARITY 0x0001 /* 0000-0000-0000-0001 */
+#define SCI_ERROR_FRAMING 0x0002 /* 0000-0000-0000-0010 */
+#define SCI_ERROR_NOISE 0x0004 /* 0000-0000-0000-0100 */
+#define SCI_ERROR_OVERRUN 0x0008 /* 0000-0000-0000-1000 */
+
+#define SCI_IDLE_LINE 0x0010 /* 0000-0000-0001-0000 */
+#define SCI_RCVR_ACTIVE 0x0020 /* 0000-0000-0010-0000 */
+#define SCI_RCVR_READY 0x0040 /* 0000-0000-0100-0000 */
+#define SCI_XMTR_IDLE 0x0080 /* 0000-0000-1000-0000 */
+
+#define SCI_CLEAR_RX_INT 0xFFBF /* 1111-1111-1011-1111 */
+
+#define SCI_XMTR_READY 0x0100 /* 0000-0001-0000-0000 */
+
+#define SCI_CLEAR_TDRE 0xFEFF /* 1111-1110-1111-1111 */
+
+#define SCI_XMTR_AVAILABLE 0x0180 /* 0000-0001-1000-0000 */
+
+
+
+/*******************************************************************************
+ Function prototypes
+*******************************************************************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* look at console_open to see how this is called */
+
+const rtems_termios_callbacks * SciGetTermiosHandlers( int32_t polled );
+
+/* SCI interrupt */
+
+/*rtems_isr SciIsr( rtems_vector_number vector ); */
+
+/*int32_t SciOpenPolled ( int32_t major, int32_t minor, void *arg ); */
+/*int32_t SciOpenInterrupt ( int32_t major, int32_t minor, void *arg ); */
+
+/*int32_t SciClose ( int32_t major, int32_t minor, void *arg ); */
+
+/*int32_t SciWritePolled ( int32_t minor, const char *buf, int32_t len ); */
+/*int32_t SciWriteInterrupt( int32_t minor, const char *buf, int32_t len ); */
+
+/*int32_t SciReadPolled ( int32_t minor ); */
+
+/*int32_t SciSetAttributes ( int32_t minor, const struct termios *t ); */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _sci_h_ */
diff --git a/bsps/m68k/mvme147/console/console.c b/bsps/m68k/mvme147/console/console.c
new file mode 100644
index 0000000000..f26ca6485a
--- /dev/null
+++ b/bsps/m68k/mvme147/console/console.c
@@ -0,0 +1,203 @@
+/*
+ * This file contains the MVME147 console IO package.
+ */
+
+/*
+ * COPYRIGHT (c) 1989-1999.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ *
+ * MVME147 port for TNI - Telecom Bretagne
+ * by Dominique LE CAMPION (Dominique.LECAMPION@enst-bretagne.fr)
+ * May 1996
+ *
+ * This file was taken from the DMV152 bsp
+ */
+
+#define M147_INIT
+
+#include <rtems/console.h>
+#include <rtems/libio.h>
+#include <rtems/zilog/z8530.h>
+#include <rtems/iosupp.h>
+#include <bsp.h>
+
+/* console_initialize
+ *
+ * This routine initializes the console IO driver.
+ */
+rtems_device_driver console_initialize(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg
+)
+{
+ rtems_status_code status;
+
+ status = rtems_io_register_name(
+ "/dev/console",
+ major,
+ (rtems_device_minor_number) 0
+ );
+
+ if (status != RTEMS_SUCCESSFUL)
+ rtems_fatal_error_occurred(status);
+
+ return RTEMS_SUCCESSFUL;
+}
+
+/* inbyte
+ *
+ * This routine reads a character from the SCC.
+ */
+static char inbyte( void )
+{
+ uint8_t rr_0;
+ char ch;
+
+ for ( ; ; ) {
+ Z8x30_READ_CONTROL( CONSOLE_CONTROL, RR_0, rr_0 );
+ if ( (rr_0 & RR_0_RX_DATA_AVAILABLE) != 0 )
+ break;
+ }
+
+ Z8x30_READ_DATA( CONSOLE_DATA, ch );
+ return ( ch );
+}
+
+/* outbyte
+ *
+ * This routine transmits a character out the SCC. It supports
+ * XON/XOFF flow control.
+ */
+static void outbyte(
+ char ch
+)
+{
+ uint8_t rr_0;
+ char flow_control;
+
+ for ( ; ; ) {
+ Z8x30_READ_CONTROL( CONSOLE_CONTROL, RR_0, rr_0 );
+ if ( (rr_0 & RR_0_TX_BUFFER_EMPTY) != 0 )
+ break;
+ }
+
+ for ( ; ; ) {
+ Z8x30_READ_CONTROL( CONSOLE_CONTROL, RR_0, rr_0 );
+ if ( (rr_0 & RR_0_RX_DATA_AVAILABLE) == 0 )
+ break;
+
+ Z8x30_READ_DATA( CONSOLE_DATA, flow_control );
+
+ if ( flow_control == XOFF )
+ do {
+ do {
+ Z8x30_READ_CONTROL( CONSOLE_CONTROL, RR_0, rr_0 );
+ } while ( (rr_0 & RR_0_RX_DATA_AVAILABLE) == 0 );
+ Z8x30_READ_DATA( CONSOLE_DATA, flow_control );
+ } while ( flow_control != XON );
+ }
+
+ Z8x30_WRITE_DATA( CONSOLE_DATA, ch );
+}
+
+/*
+ * Open entry point
+ */
+rtems_device_driver console_open(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+ return RTEMS_SUCCESSFUL;
+}
+
+/*
+ * Close entry point
+ */
+rtems_device_driver console_close(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+ return RTEMS_SUCCESSFUL;
+}
+
+/*
+ * read bytes from the serial port. We only have stdin.
+ */
+rtems_device_driver console_read(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+ rtems_libio_rw_args_t *rw_args;
+ char *buffer;
+ int maximum;
+ int count = 0;
+
+ rw_args = (rtems_libio_rw_args_t *) arg;
+
+ buffer = rw_args->buffer;
+ maximum = rw_args->count;
+
+ for (count = 0; count < maximum; count++) {
+ buffer[ count ] = inbyte();
+ if (buffer[ count ] == '\n' || buffer[ count ] == '\r') {
+ buffer[ count++ ] = '\n';
+ break;
+ }
+ }
+
+ rw_args->bytes_moved = count;
+ return (count >= 0) ? RTEMS_SUCCESSFUL : RTEMS_UNSATISFIED;
+}
+
+/*
+ * write bytes to the serial port. Stdout and stderr are the same.
+ */
+rtems_device_driver console_write(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+ int count;
+ int maximum;
+ rtems_libio_rw_args_t *rw_args;
+ char *buffer;
+
+ rw_args = (rtems_libio_rw_args_t *) arg;
+
+ buffer = rw_args->buffer;
+ maximum = rw_args->count;
+
+ for (count = 0; count < maximum; count++) {
+ if ( buffer[ count ] == '\n') {
+ outbyte('\r');
+ }
+ outbyte( buffer[ count ] );
+ }
+
+ rw_args->bytes_moved = maximum;
+ return 0;
+}
+
+/*
+ * IO Control entry point
+ */
+rtems_device_driver console_control(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+ return RTEMS_SUCCESSFUL;
+}
diff --git a/bsps/m68k/mvme162/console/console.c b/bsps/m68k/mvme162/console/console.c
new file mode 100644
index 0000000000..985254d483
--- /dev/null
+++ b/bsps/m68k/mvme162/console/console.c
@@ -0,0 +1,277 @@
+/*
+ * This file contains the MVME162 console IO package.
+ */
+
+/*
+ * COPYRIGHT (c) 1989-2013.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ *
+ * Modifications of respective RTEMS file: COPYRIGHT (c) 1994.
+ * EISCAT Scientific Association. M.Savitski
+ *
+ * This material is a part of the MVME162 Board Support Package
+ * for the RTEMS executive. Its licensing policies are those of the
+ * RTEMS above.
+ */
+
+#define M162_INIT
+
+#include <rtems/bspIo.h>
+#include <rtems/console.h>
+#include <rtems/libio.h>
+#include <rtems/ringbuf.h>
+#include <bsp.h>
+
+Ring_buffer_t Console_Buffer[2];
+
+/*
+ * Interrupt handler for receiver interrupts
+ */
+static rtems_isr C_Receive_ISR(rtems_vector_number vector)
+{
+ register int ipend, port;
+
+ ZWRITE0(1, 0x38); /* reset highest IUS */
+
+ ipend = ZREAD(1, 3); /* read int pending from A side */
+
+ if (ipend == 0x04) port = 0; /* channel B intr pending */
+ else if (ipend == 0x20) port = 1; /* channel A intr pending */
+ else return;
+
+ Ring_buffer_Add_character(&Console_Buffer[port], ZREADD(port));
+
+ if (ZREAD(port, 1) & 0x70) { /* check error stat */
+ ZWRITE0(port, 0x30); /* reset error */
+ }
+}
+
+rtems_device_driver console_initialize(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg
+)
+{
+ int i;
+ rtems_status_code status;
+
+ /*
+ * Initialise receiver interrupts on both ports
+ */
+ for (i = 0; i <= 1; i++) {
+ Ring_buffer_Initialize( &Console_Buffer[i] );
+ ZWRITE(i, 2, SCC_VECTOR);
+ ZWRITE(i, 10, 0);
+ ZWRITE(i, 1, 0x10); /* int on all Rx chars or special condition */
+ ZWRITE(i, 9, 8); /* master interrupt enable */
+ }
+
+ set_vector(C_Receive_ISR, SCC_VECTOR, 1); /* install ISR for ports A and B */
+
+ mcchip->vector_base = 0;
+ mcchip->gen_control = 2; /* MIEN */
+ mcchip->SCC_int_ctl = 0x13; /* SCC IEN, IPL3 */
+
+ status = rtems_io_register_name(
+ "/dev/console",
+ major,
+ (rtems_device_minor_number) 1
+ );
+
+ if (status != RTEMS_SUCCESSFUL)
+ rtems_fatal_error_occurred(status);
+
+ status = rtems_io_register_name(
+ "/dev/tty00",
+ major,
+ (rtems_device_minor_number) 0
+ );
+
+ if (status != RTEMS_SUCCESSFUL)
+ rtems_fatal_error_occurred(status);
+
+ status = rtems_io_register_name(
+ "/dev/tty01",
+ major,
+ (rtems_device_minor_number) 1
+ );
+
+ if (status != RTEMS_SUCCESSFUL)
+ rtems_fatal_error_occurred(status);
+
+ return RTEMS_SUCCESSFUL;
+}
+
+/*
+ * Non-blocking char input
+ */
+bool char_ready(int port, char *ch)
+{
+ if ( Ring_buffer_Is_empty( &Console_Buffer[port] ) )
+ return false;
+
+ Ring_buffer_Remove_character( &Console_Buffer[port], *ch );
+
+ return true;
+}
+
+/*
+ * Block on char input
+ */
+static char inbyte(int port)
+{
+ char tmp_char;
+
+ while ( !char_ready(port, &tmp_char) );
+ return tmp_char;
+}
+
+/*
+ * This routine transmits a character out the SCC. It no longer supports
+ * XON/XOFF flow control.
+ */
+static void outbyte(char ch, int port)
+{
+ while (1) {
+ if (ZREAD0(port) & TX_BUFFER_EMPTY) break;
+ }
+ ZWRITED(port, ch);
+}
+
+/*
+ * Open entry point
+ */
+rtems_device_driver console_open(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+ return RTEMS_SUCCESSFUL;
+}
+
+/*
+ * Close entry point
+ */
+rtems_device_driver console_close(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+ return RTEMS_SUCCESSFUL;
+}
+
+/*
+ * read bytes from the serial port. We only have stdin.
+ */
+rtems_device_driver console_read(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+ rtems_libio_rw_args_t *rw_args;
+ char *buffer;
+ int maximum;
+ int count = 0;
+
+ rw_args = (rtems_libio_rw_args_t *) arg;
+
+ buffer = rw_args->buffer;
+ maximum = rw_args->count;
+
+ if ( minor > 1 )
+ return RTEMS_INVALID_NUMBER;
+
+ for (count = 0; count < maximum; count++) {
+ buffer[ count ] = inbyte( minor );
+ if (buffer[ count ] == '\n' || buffer[ count ] == '\r') {
+ buffer[ count++ ] = '\n';
+ break;
+ }
+ }
+
+ rw_args->bytes_moved = count;
+ return (count >= 0) ? RTEMS_SUCCESSFUL : RTEMS_UNSATISFIED;
+}
+
+/*
+ * write bytes to the serial port. Stdout and stderr are the same.
+ */
+rtems_device_driver console_write(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+ int count;
+ int maximum;
+ rtems_libio_rw_args_t *rw_args;
+ char *buffer;
+
+ rw_args = (rtems_libio_rw_args_t *) arg;
+
+ buffer = rw_args->buffer;
+ maximum = rw_args->count;
+
+ if ( minor > 1 )
+ return RTEMS_INVALID_NUMBER;
+
+ for (count = 0; count < maximum; count++) {
+ if ( buffer[ count ] == '\n') {
+ outbyte('\r', minor );
+ }
+ outbyte( buffer[ count ], minor );
+ }
+
+ rw_args->bytes_moved = maximum;
+ return 0;
+}
+
+/*
+ * IO Control entry point
+ */
+rtems_device_driver console_control(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+ return RTEMS_SUCCESSFUL;
+}
+
+/*
+ * _162Bug_output_char
+ *
+ * Output a single character using the 162Bug functions. The character
+ * will be written to the default output port.
+ */
+static void _162Bug_output_char( char c )
+{
+ asm volatile( "moveb %0, -(%%sp)\n\t" /* char to output */
+ "trap #15\n\t" /* Trap to 162Bug */
+ ".short 0x20" /* Code for .OUTCHR */
+ :: "d" (c) );
+}
+
+/*
+ * _BSP_output_char
+ *
+ * printk() function prototyped in bspIo.h. Does not use termios.
+ *
+ * If we have initialized the console device then use it, otherwise
+ * use the 162Bug routines to send it to the default output port.
+ */
+static void _BSP_output_char(char c)
+{
+ _162Bug_output_char(c);
+}
+
+/* Printk function */
+BSP_output_char_function_type BSP_output_char = _BSP_output_char;
+BSP_polling_getchar_function_type BSP_poll_char = NULL;
diff --git a/bsps/m68k/mvme167/console/console-recording.h b/bsps/m68k/mvme167/console/console-recording.h
new file mode 100644
index 0000000000..4d8d3fc66c
--- /dev/null
+++ b/bsps/m68k/mvme167/console/console-recording.h
@@ -0,0 +1,572 @@
+/*
+ * Copyright (c) 2000, National Research Council of Canada
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+/* CD2401 CONSOLE DRIVER DEBUG INFO RECORDING */
+
+#ifdef CD2401_RECORD_DEBUG_INFO
+
+/* Control individual recording here. That way, we don't clutter console.c */
+#define CD2401_RECORD_WRITE
+#define CD2401_RECORD_TX_ISR
+#define CD2401_RECORD_RX_ISR
+#define CD2401_RECORD_RE_ISR
+#define CD2401_RECORD_MODEM_ISR
+#define CD2401_RECORD_SET_ATTRIBUTE
+#define CD2401_RECORD_FIRST_OPEN
+#define CD2401_RECORD_LAST_CLOSE
+#define CD2401_RECORD_START_REMOTE_TX
+#define CD2401_RECORD_STOP_REMOTE_TX
+#define CD2401_RECORD_DRAIN_OUTPUT
+#define CD2401_RECORD_DELAY
+
+/* Call the data recording functions */
+#ifdef CD2401_RECORD_WRITE
+#define CD2401_RECORD_WRITE_INFO( args ) cd2401_record_write_info args
+#else
+#define CD2401_RECORD_WRITE_INFO( args )
+#endif
+
+#ifdef CD2401_RECORD_TX_ISR
+#define CD2401_RECORD_TX_ISR_INFO( args ) cd2401_record_tx_isr_info args
+#define CD2401_RECORD_TX_ISR_SPURIOUS_INFO( args ) cd2401_record_tx_isr_spurious_info args
+#define CD2401_RECORD_TX_ISR_BUSERR_INFO( args ) cd2401_record_tx_isr_buserr_info args
+#else
+#define CD2401_RECORD_TX_ISR_INFO( args )
+#define CD2401_RECORD_TX_ISR_SPURIOUS_INFO( args )
+#define CD2401_RECORD_TX_ISR_BUSERR_INFO( args )
+#endif
+
+#ifdef CD2401_RECORD_RX_ISR
+#define CD2401_RECORD_RX_ISR_INFO( args ) cd2401_record_rx_isr_info args
+#define CD2401_RECORD_RX_ISR_SPURIOUS_INFO( args ) cd2401_record_rx_isr_spurious_info args
+#else
+#define CD2401_RECORD_RX_ISR_INFO( args )
+#define CD2401_RECORD_RX_ISR_SPURIOUS_INFO( args )
+#endif
+
+#ifdef CD2401_RECORD_RE_ISR
+#define CD2401_RECORD_RE_ISR_SPURIOUS_INFO( args ) cd2401_record_re_isr_spurious_info args
+#else
+#define CD2401_RECORD_RE_ISR_SPURIOUS_INFO( args )
+#endif
+
+#ifdef CD2401_RECORD_MODEM_ISR
+#define CD2401_RECORD_MODEM_ISR_SPURIOUS_INFO( args ) cd2401_record_modem_isr_spurious_info args
+#else
+#define CD2401_RECORD_MODEM_ISR_SPURIOUS_INFO( args )
+#endif
+
+#ifdef CD2401_RECORD_SET_ATTRIBUTES
+#define CD2401_RECORD_SET_ATTRIBUTES_INFO( args ) cd2401_record_set_attributes_info args
+#else
+#define CD2401_RECORD_SET_ATTRIBUTES_INFO( args )
+#endif
+
+#ifdef CD2401_RECORD_FIRST_OPEN
+#define CD2401_RECORD_FIRST_OPEN_INFO( args ) cd2401_record_first_open_info args
+#else
+#define CD2401_RECORD_FIRST_OPEN_INFO( args )
+#endif
+
+#ifdef CD2401_RECORD_LAST_CLOSE
+#define CD2401_RECORD_LAST_CLOSE_INFO( args ) cd2401_record_last_close_info args
+#else
+#define CD2401_RECORD_LAST_CLOSE_INFO( args )
+#endif
+
+#ifdef CD2401_RECORD_START_REMOTE_TX
+#define CD2401_RECORD_START_REMOTE_TX_INFO( args ) cd2401_record_start_remote_tx_info args
+#else
+#define CD2401_RECORD_START_REMOTE_TX_INFO( args )
+#endif
+
+#ifdef CD2401_RECORD_STOP_REMOTE_TX
+#define CD2401_RECORD_STOP_REMOTE_TX_INFO( args ) cd2401_record_stop_remote_tx_info args
+#else
+#define CD2401_RECORD_STOP_REMOTE_TX_INFO( args )
+#endif
+
+#ifdef CD2401_RECORD_DRAIN_OUTPUT
+#define CD2401_RECORD_DRAIN_OUTPUT_INFO( args ) cd2401_record_drain_output_info args
+#else
+#define CD2401_RECORD_DRAIN_OUTPUT_INFO( args )
+#endif
+
+#ifdef CD2401_RECORD_DELAY
+#define CD2401_RECORD_DELAY_INFO( args ) cd2401_record_delay_info args
+#else
+#define CD2401_RECORD_DELAY_INFO( args )
+#endif
+
+/* Define the data and the recording functions */
+#define CD2401_DEBUG_BUFFER_SIZE 256
+#define CD2401_DEBUG_CHAR_BUFSIZE 64
+#define CD2401_WRITE_INFO 1
+#define CD2401_TX_ISR_INFO 2
+#define CD2401_TX_ISR_SPURIOUS_INFO 3
+#define CD2401_TX_ISR_BUSERR_INFO 4
+#define CD2401_RX_ISR_INFO 5
+#define CD2401_RX_ISR_SPURIOUS_INFO 6
+#define CD2401_RE_ISR_SPURIOUS_INFO 7
+#define CD2401_MODEM_ISR_SPURIOUS_INFO 8
+#define CD2401_FIRST_OPEN_INFO 9
+#define CD2401_LAST_CLOSE_INFO 10
+#define CD2401_START_REMOTE_TX_INFO 11
+#define CD2401_STOP_REMOTE_TX_INFO 12
+#define CD2401_SET_ATTRIBUTE_INFO 13
+#define CD2401_DRAIN_OUTPUT_INFO 14
+#define CD2401_DELAY_INFO 15
+
+struct cd2401_debug_info {
+ short discriminant;
+ short record_size;
+ union {
+ struct cd2401_write_info {
+ int length;
+ char buffer[CD2401_DEBUG_CHAR_BUFSIZE];
+ char dmabuf;
+ } write_info;
+ struct cd2401_tx_isr_info {
+ unsigned char channel;
+ unsigned char status;
+ unsigned char initial_ier;
+ unsigned char final_ier;
+ uint8_t txEmpty;
+ } tx_isr_info;
+ struct cd2401_tx_isr_spurious_info {
+ unsigned char channel;
+ unsigned char status;
+ unsigned char initial_ier;
+ unsigned char final_ier;
+ unsigned long spurdev;
+ unsigned long spurcount;
+ } tx_isr_spurious_info;
+ struct cd2401_tx_isr_buserr_info {
+ unsigned char channel;
+ unsigned char status;
+ unsigned char initial_ier;
+ unsigned char buserr;
+ unsigned long type;
+ unsigned long addr;
+ } tx_isr_buserr_info;
+ struct cd2401_rx_isr_info {
+ unsigned char channel;
+ int length;
+ char buffer[CD2401_DEBUG_CHAR_BUFSIZE];
+ } rx_isr_info;
+ struct cd2401_rx_isr_spurious_info {
+ unsigned char channel;
+ unsigned char status;
+ unsigned long spurdev;
+ unsigned long spurcount;
+ } rx_isr_spurious_info;
+ struct cd2401_re_isr_spurious_info {
+ unsigned char channel;
+ unsigned long spurdev;
+ unsigned long spurcount;
+ } re_isr_spurious_info;
+ struct cd2401_modem_isr_spurious_info {
+ unsigned char channel;
+ unsigned long spurdev;
+ unsigned long spurcount;
+ } modem_isr_spurious_info;
+ struct cd2401_first_open_info {
+ unsigned char channel;
+ uint8_t init_count;
+ } first_open_info;
+ struct cd2401_last_close_info {
+ unsigned char channel;
+ uint8_t init_count;
+ } last_close_info;
+ struct cd2401_start_remote_tx_info {
+ unsigned char channel;
+ } start_remote_tx_info;
+ struct cd2401_stop_remote_tx_info {
+ unsigned char channel;
+ } stop_remote_tx_info;
+ struct cd2401_set_attribute_info {
+ int minor;
+ uint8_t need_reinit;
+ uint8_t txEmpty;
+ uint8_t csize;
+ uint8_t cstopb;
+ uint8_t parodd;
+ uint8_t parenb;
+ uint8_t ignpar;
+ uint8_t inpck;
+ uint8_t hw_flow_ctl;
+ uint8_t sw_flow_ctl;
+ uint8_t extra_flow_ctl;
+ uint8_t icrnl;
+ uint8_t igncr;
+ uint8_t inlcr;
+ uint8_t brkint;
+ uint8_t ignbrk;
+ uint8_t parmrk;
+ uint8_t istrip;
+ uint16_t tx_period;
+ uint16_t rx_period;
+ uint32_t out_baud;
+ uint32_t in_baud;
+ } set_attribute_info;
+ struct cd2401_drain_output_info {
+ uint8_t txEmpty;
+ uint8_t own_buf_A;
+ uint8_t own_buf_B;
+ } drain_output_info;
+ struct cd2401_delay_info {
+ rtems_interval start;
+ rtems_interval end;
+ rtems_interval current;
+ unsigned long loop_count;
+ } delay_info;
+ } u;
+};
+
+struct cd2401_debug_info cd2401_debug_buffer[CD2401_DEBUG_BUFFER_SIZE];
+int cd2401_debug_index = 0;
+
+#include <string.h>
+
+int cd2401_get_record_size(
+ int size
+)
+{
+ /* Not the best way to do this */
+ return size + 4;
+}
+
+void cd2401_record_write_info(
+ int len,
+ const char * buf,
+ char dmabuf
+)
+{
+ int max_length;
+
+ max_length = (len < CD2401_DEBUG_CHAR_BUFSIZE ) ? len : CD2401_DEBUG_CHAR_BUFSIZE;
+
+ memset( &(cd2401_debug_buffer[cd2401_debug_index]), '\0', sizeof( struct cd2401_debug_info ) );
+ cd2401_debug_buffer[cd2401_debug_index].discriminant = CD2401_WRITE_INFO;
+ cd2401_debug_buffer[cd2401_debug_index].record_size =
+ cd2401_get_record_size( sizeof( struct cd2401_write_info ) );
+ cd2401_debug_buffer[cd2401_debug_index].u.write_info.length = len;
+ memcpy ( &(cd2401_debug_buffer[cd2401_debug_index].u.write_info.buffer), buf, max_length );
+ cd2401_debug_buffer[cd2401_debug_index].u.write_info.dmabuf = dmabuf;
+
+ cd2401_debug_index = (cd2401_debug_index + 1 ) % CD2401_DEBUG_BUFFER_SIZE;
+}
+
+void cd2401_record_tx_isr_info(
+ unsigned char ch,
+ unsigned char status,
+ unsigned char initial_ier,
+ unsigned char final_ier,
+ uint8_t txEmpty
+)
+{
+ memset( &(cd2401_debug_buffer[cd2401_debug_index]), '\0', sizeof( struct cd2401_debug_info ) );
+ cd2401_debug_buffer[cd2401_debug_index].discriminant = CD2401_TX_ISR_INFO;
+ cd2401_debug_buffer[cd2401_debug_index].record_size =
+ cd2401_get_record_size( sizeof( struct cd2401_tx_isr_info ) );
+ cd2401_debug_buffer[cd2401_debug_index].u.tx_isr_info.channel = ch;
+ cd2401_debug_buffer[cd2401_debug_index].u.tx_isr_info.status = status;
+ cd2401_debug_buffer[cd2401_debug_index].u.tx_isr_info.initial_ier = initial_ier;
+ cd2401_debug_buffer[cd2401_debug_index].u.tx_isr_info.final_ier = final_ier;
+ cd2401_debug_buffer[cd2401_debug_index].u.tx_isr_info.txEmpty = txEmpty;
+
+ cd2401_debug_index = (cd2401_debug_index + 1 ) % CD2401_DEBUG_BUFFER_SIZE;
+}
+
+void cd2401_record_tx_isr_spurious_info(
+ unsigned char ch,
+ unsigned char status,
+ unsigned char initial_ier,
+ unsigned char final_ier,
+ unsigned char spur_dev,
+ unsigned char spur_cnt
+)
+{
+ memset( &(cd2401_debug_buffer[cd2401_debug_index]), '\0', sizeof( struct cd2401_debug_info ) );
+ cd2401_debug_buffer[cd2401_debug_index].discriminant = CD2401_TX_ISR_SPURIOUS_INFO;
+ cd2401_debug_buffer[cd2401_debug_index].record_size =
+ cd2401_get_record_size( sizeof( struct cd2401_tx_isr_spurious_info ) );
+ cd2401_debug_buffer[cd2401_debug_index].u.tx_isr_spurious_info.channel = ch;
+ cd2401_debug_buffer[cd2401_debug_index].u.tx_isr_spurious_info.status = status;
+ cd2401_debug_buffer[cd2401_debug_index].u.tx_isr_spurious_info.initial_ier = initial_ier;
+ cd2401_debug_buffer[cd2401_debug_index].u.tx_isr_spurious_info.final_ier = final_ier;
+ cd2401_debug_buffer[cd2401_debug_index].u.tx_isr_spurious_info.spurdev = spur_dev;
+ cd2401_debug_buffer[cd2401_debug_index].u.tx_isr_spurious_info.spurcount = spur_cnt;
+
+ cd2401_debug_index = (cd2401_debug_index + 1 ) % CD2401_DEBUG_BUFFER_SIZE;
+}
+
+void cd2401_record_tx_isr_buserr_info(
+ unsigned char ch,
+ unsigned char status,
+ unsigned char initial_ier,
+ unsigned char buserr,
+ unsigned long buserr_type,
+ unsigned long buserr_addr
+)
+{
+ memset( &(cd2401_debug_buffer[cd2401_debug_index]), '\0', sizeof( struct cd2401_debug_info ) );
+ cd2401_debug_buffer[cd2401_debug_index].discriminant = CD2401_TX_ISR_BUSERR_INFO;
+ cd2401_debug_buffer[cd2401_debug_index].record_size =
+ cd2401_get_record_size( sizeof( struct cd2401_tx_isr_buserr_info ) );
+ cd2401_debug_buffer[cd2401_debug_index].u.tx_isr_buserr_info.channel = ch;
+ cd2401_debug_buffer[cd2401_debug_index].u.tx_isr_buserr_info.status = status;
+ cd2401_debug_buffer[cd2401_debug_index].u.tx_isr_buserr_info.initial_ier = initial_ier;
+ cd2401_debug_buffer[cd2401_debug_index].u.tx_isr_buserr_info.buserr = buserr;
+ cd2401_debug_buffer[cd2401_debug_index].u.tx_isr_buserr_info.type = buserr_type;
+ cd2401_debug_buffer[cd2401_debug_index].u.tx_isr_buserr_info.addr = buserr_addr;
+
+ cd2401_debug_index = (cd2401_debug_index + 1 ) % CD2401_DEBUG_BUFFER_SIZE;
+}
+
+void cd2401_record_rx_isr_info(
+ unsigned char ch,
+ unsigned char total,
+ char * buffer
+)
+{
+ int max_length;
+
+ max_length = (total < CD2401_DEBUG_CHAR_BUFSIZE ) ? total : CD2401_DEBUG_CHAR_BUFSIZE;
+
+ memset( &(cd2401_debug_buffer[cd2401_debug_index]), '\0', sizeof( struct cd2401_debug_info ) );
+ cd2401_debug_buffer[cd2401_debug_index].discriminant = CD2401_RX_ISR_INFO;
+ cd2401_debug_buffer[cd2401_debug_index].record_size =
+ cd2401_get_record_size( sizeof( struct cd2401_rx_isr_info ) );
+ cd2401_debug_buffer[cd2401_debug_index].u.rx_isr_info.length = max_length;
+ memcpy ( &(cd2401_debug_buffer[cd2401_debug_index].u.rx_isr_info.buffer), buffer, max_length );
+
+ cd2401_debug_index = (cd2401_debug_index + 1 ) % CD2401_DEBUG_BUFFER_SIZE;
+}
+
+void cd2401_record_rx_isr_spurious_info(
+ unsigned char ch,
+ unsigned char status,
+ uint32_t spur_dev,
+ uint32_t spur_cnt
+)
+{
+ memset( &(cd2401_debug_buffer[cd2401_debug_index]), '\0', sizeof( struct cd2401_debug_info ) );
+ cd2401_debug_buffer[cd2401_debug_index].discriminant = CD2401_RX_ISR_SPURIOUS_INFO;
+ cd2401_debug_buffer[cd2401_debug_index].record_size =
+ cd2401_get_record_size( sizeof( struct cd2401_rx_isr_spurious_info ) );
+ cd2401_debug_buffer[cd2401_debug_index].u.rx_isr_spurious_info.channel = ch;
+ cd2401_debug_buffer[cd2401_debug_index].u.rx_isr_spurious_info.status = status;
+ cd2401_debug_buffer[cd2401_debug_index].u.rx_isr_spurious_info.spurdev = spur_dev;
+ cd2401_debug_buffer[cd2401_debug_index].u.rx_isr_spurious_info.spurcount = spur_cnt;
+
+ cd2401_debug_index = (cd2401_debug_index + 1 ) % CD2401_DEBUG_BUFFER_SIZE;
+}
+
+void cd2401_record_re_isr_spurious_info(
+ unsigned char ch,
+ uint32_t spur_dev,
+ uint32_t spur_cnt
+)
+{
+ memset( &(cd2401_debug_buffer[cd2401_debug_index]), '\0', sizeof( struct cd2401_debug_info ) );
+ cd2401_debug_buffer[cd2401_debug_index].discriminant = CD2401_RE_ISR_SPURIOUS_INFO;
+ cd2401_debug_buffer[cd2401_debug_index].record_size =
+ cd2401_get_record_size( sizeof( struct cd2401_re_isr_spurious_info ) );
+ cd2401_debug_buffer[cd2401_debug_index].u.re_isr_spurious_info.channel = ch;
+ cd2401_debug_buffer[cd2401_debug_index].u.re_isr_spurious_info.spurdev = spur_dev;
+ cd2401_debug_buffer[cd2401_debug_index].u.re_isr_spurious_info.spurcount = spur_cnt;
+
+ cd2401_debug_index = (cd2401_debug_index + 1 ) % CD2401_DEBUG_BUFFER_SIZE;
+}
+
+void cd2401_record_modem_isr_spurious_info(
+ unsigned char ch,
+ uint32_t spur_dev,
+ uint32_t spur_cnt
+)
+{
+ memset( &(cd2401_debug_buffer[cd2401_debug_index]), '\0', sizeof( struct cd2401_debug_info ) );
+ cd2401_debug_buffer[cd2401_debug_index].discriminant = CD2401_MODEM_ISR_SPURIOUS_INFO;
+ cd2401_debug_buffer[cd2401_debug_index].record_size =
+ cd2401_get_record_size( sizeof( struct cd2401_modem_isr_spurious_info ) );
+ cd2401_debug_buffer[cd2401_debug_index].u.modem_isr_spurious_info.channel = ch;
+ cd2401_debug_buffer[cd2401_debug_index].u.modem_isr_spurious_info.spurdev = spur_dev;
+ cd2401_debug_buffer[cd2401_debug_index].u.modem_isr_spurious_info.spurcount = spur_cnt;
+
+ cd2401_debug_index = (cd2401_debug_index + 1 ) % CD2401_DEBUG_BUFFER_SIZE;
+}
+
+void cd2401_record_first_open_info(
+ unsigned char ch,
+ uint8_t init_count
+)
+{
+ memset( &(cd2401_debug_buffer[cd2401_debug_index]), '\0', sizeof( struct cd2401_debug_info ) );
+ cd2401_debug_buffer[cd2401_debug_index].discriminant = CD2401_FIRST_OPEN_INFO;
+ cd2401_debug_buffer[cd2401_debug_index].record_size =
+ cd2401_get_record_size( sizeof( struct cd2401_first_open_info ) );
+ cd2401_debug_buffer[cd2401_debug_index].u.first_open_info.channel = ch;
+ cd2401_debug_buffer[cd2401_debug_index].u.first_open_info.init_count = init_count;
+
+ cd2401_debug_index = (cd2401_debug_index + 1 ) % CD2401_DEBUG_BUFFER_SIZE;
+}
+
+void cd2401_record_last_close_info(
+ unsigned char ch,
+ uint8_t init_count
+)
+{
+ memset( &(cd2401_debug_buffer[cd2401_debug_index]), '\0', sizeof( struct cd2401_debug_info ) );
+ cd2401_debug_buffer[cd2401_debug_index].discriminant = CD2401_LAST_CLOSE_INFO;
+ cd2401_debug_buffer[cd2401_debug_index].record_size =
+ cd2401_get_record_size( sizeof( struct cd2401_last_close_info ) );
+ cd2401_debug_buffer[cd2401_debug_index].u.last_close_info.channel = ch;
+ cd2401_debug_buffer[cd2401_debug_index].u.last_close_info.init_count = init_count;
+
+ cd2401_debug_index = (cd2401_debug_index + 1 ) % CD2401_DEBUG_BUFFER_SIZE;
+}
+
+void cd2401_record_start_remote_tx_info(
+ unsigned char ch
+)
+{
+ memset( &(cd2401_debug_buffer[cd2401_debug_index]), '\0', sizeof( struct cd2401_debug_info ) );
+ cd2401_debug_buffer[cd2401_debug_index].discriminant = CD2401_START_REMOTE_TX_INFO;
+ cd2401_debug_buffer[cd2401_debug_index].record_size =
+ cd2401_get_record_size( sizeof( struct cd2401_start_remote_tx_info ) );
+ cd2401_debug_buffer[cd2401_debug_index].u.start_remote_tx_info.channel = ch;
+
+ cd2401_debug_index = (cd2401_debug_index + 1 ) % CD2401_DEBUG_BUFFER_SIZE;
+}
+
+void cd2401_record_stop_remote_tx_info(
+ unsigned char ch
+)
+{
+ memset( &(cd2401_debug_buffer[cd2401_debug_index]), '\0', sizeof( struct cd2401_debug_info ) );
+ cd2401_debug_buffer[cd2401_debug_index].discriminant = CD2401_STOP_REMOTE_TX_INFO;
+ cd2401_debug_buffer[cd2401_debug_index].record_size =
+ cd2401_get_record_size( sizeof( struct cd2401_stop_remote_tx_info ) );
+ cd2401_debug_buffer[cd2401_debug_index].u.stop_remote_tx_info.channel = ch;
+
+ cd2401_debug_index = (cd2401_debug_index + 1 ) % CD2401_DEBUG_BUFFER_SIZE;
+}
+
+void cd2401_record_set_attributes_info(
+ int minor,
+ uint8_t need_reinit,
+ uint8_t csize,
+ uint8_t cstopb,
+ uint8_t parodd,
+ uint8_t parenb,
+ uint8_t ignpar,
+ uint8_t inpck,
+ uint8_t hw_flow_ctl,
+ uint8_t sw_flow_ctl,
+ uint8_t extra_flow_ctl,
+ uint8_t icrnl,
+ uint8_t igncr,
+ uint8_t inlcr,
+ uint8_t brkint,
+ uint8_t ignbrk,
+ uint8_t parmrk,
+ uint8_t istrip,
+ uint16_t tx_period,
+ uint16_t rx_period,
+ uint32_t out_baud,
+ uint32_t in_baud
+)
+{
+ memset( &(cd2401_debug_buffer[cd2401_debug_index]), '\0', sizeof( struct cd2401_debug_info ) );
+ cd2401_debug_buffer[cd2401_debug_index].discriminant = CD2401_SET_ATTRIBUTE_INFO;
+ cd2401_debug_buffer[cd2401_debug_index].record_size =
+ cd2401_get_record_size( sizeof( struct cd2401_set_attribute_info ) );
+ cd2401_debug_buffer[cd2401_debug_index].u.set_attribute_info.minor = minor;
+ cd2401_debug_buffer[cd2401_debug_index].u.set_attribute_info.need_reinit = need_reinit;
+ cd2401_debug_buffer[cd2401_debug_index].u.set_attribute_info.txEmpty = CD2401_Channel_Info[minor].txEmpty;
+ cd2401_debug_buffer[cd2401_debug_index].u.set_attribute_info.csize = csize;
+ cd2401_debug_buffer[cd2401_debug_index].u.set_attribute_info.cstopb = cstopb;
+ cd2401_debug_buffer[cd2401_debug_index].u.set_attribute_info.parodd = parodd;
+ cd2401_debug_buffer[cd2401_debug_index].u.set_attribute_info.parenb = parenb;
+ cd2401_debug_buffer[cd2401_debug_index].u.set_attribute_info.ignpar = ignpar;
+ cd2401_debug_buffer[cd2401_debug_index].u.set_attribute_info.inpck = inpck;
+ cd2401_debug_buffer[cd2401_debug_index].u.set_attribute_info.hw_flow_ctl = hw_flow_ctl;
+ cd2401_debug_buffer[cd2401_debug_index].u.set_attribute_info.sw_flow_ctl = sw_flow_ctl;
+ cd2401_debug_buffer[cd2401_debug_index].u.set_attribute_info.extra_flow_ctl = extra_flow_ctl;
+ cd2401_debug_buffer[cd2401_debug_index].u.set_attribute_info.icrnl = icrnl;
+ cd2401_debug_buffer[cd2401_debug_index].u.set_attribute_info.igncr = igncr;
+ cd2401_debug_buffer[cd2401_debug_index].u.set_attribute_info.inlcr = inlcr;
+ cd2401_debug_buffer[cd2401_debug_index].u.set_attribute_info.brkint = brkint;
+ cd2401_debug_buffer[cd2401_debug_index].u.set_attribute_info.ignbrk = ignbrk;
+ cd2401_debug_buffer[cd2401_debug_index].u.set_attribute_info.parmrk = parmrk;
+ cd2401_debug_buffer[cd2401_debug_index].u.set_attribute_info.istrip = istrip;
+ cd2401_debug_buffer[cd2401_debug_index].u.set_attribute_info.tx_period = tx_period;
+ cd2401_debug_buffer[cd2401_debug_index].u.set_attribute_info.rx_period = rx_period;
+ cd2401_debug_buffer[cd2401_debug_index].u.set_attribute_info.out_baud = out_baud;
+ cd2401_debug_buffer[cd2401_debug_index].u.set_attribute_info.in_baud = in_baud;
+
+ cd2401_debug_index = (cd2401_debug_index + 1 ) % CD2401_DEBUG_BUFFER_SIZE;
+}
+
+void cd2401_record_drain_output_info(
+ uint8_t txEmpty,
+ uint8_t own_buf_A,
+ uint8_t own_buf_B
+)
+{
+ memset( &(cd2401_debug_buffer[cd2401_debug_index]), '\0', sizeof( struct cd2401_debug_info ) );
+ cd2401_debug_buffer[cd2401_debug_index].discriminant = CD2401_DRAIN_OUTPUT_INFO;
+ cd2401_debug_buffer[cd2401_debug_index].record_size =
+ cd2401_get_record_size( sizeof( struct cd2401_drain_output_info ) );
+ cd2401_debug_buffer[cd2401_debug_index].u.drain_output_info.txEmpty = txEmpty;
+ cd2401_debug_buffer[cd2401_debug_index].u.drain_output_info.own_buf_A = own_buf_A;
+ cd2401_debug_buffer[cd2401_debug_index].u.drain_output_info.own_buf_B = own_buf_B;
+
+ cd2401_debug_index = (cd2401_debug_index + 1 ) % CD2401_DEBUG_BUFFER_SIZE;
+}
+
+void cd2401_record_delay_info(
+ rtems_interval start,
+ rtems_interval end,
+ rtems_interval current,
+ unsigned long loop_count
+)
+{
+ memset( &(cd2401_debug_buffer[cd2401_debug_index]), '\0', sizeof( struct cd2401_debug_info ) );
+ cd2401_debug_buffer[cd2401_debug_index].discriminant = CD2401_DELAY_INFO;
+ cd2401_debug_buffer[cd2401_debug_index].record_size =
+ cd2401_get_record_size( sizeof( struct cd2401_delay_info ) );
+ cd2401_debug_buffer[cd2401_debug_index].u.delay_info.start = start;
+ cd2401_debug_buffer[cd2401_debug_index].u.delay_info.end = end;
+ cd2401_debug_buffer[cd2401_debug_index].u.delay_info.current = current;
+ cd2401_debug_buffer[cd2401_debug_index].u.delay_info.loop_count = loop_count;
+
+ cd2401_debug_index = (cd2401_debug_index + 1 ) % CD2401_DEBUG_BUFFER_SIZE;
+}
+
+#else
+
+/* Do not call the data recording functions */
+#define CD2401_RECORD_WRITE_INFO( args )
+#define CD2401_RECORD_TX_ISR_INFO( args )
+#define CD2401_RECORD_TX_ISR_SPURIOUS_INFO( args )
+#define CD2401_RECORD_TX_ISR_BUSERR_INFO( args )
+#define CD2401_RECORD_RX_ISR_INFO( args )
+#define CD2401_RECORD_RX_ISR_SPURIOUS_INFO( args )
+#define CD2401_RECORD_RE_ISR_SPURIOUS_INFO( args )
+#define CD2401_RECORD_MODEM_ISR_SPURIOUS_INFO( args )
+#define CD2401_RECORD_FIRST_OPEN_INFO( args )
+#define CD2401_RECORD_LAST_CLOSE_INFO( args )
+#define CD2401_RECORD_START_REMOTE_TX_INFO( args )
+#define CD2401_RECORD_STOP_REMOTE_TX_INFO( args )
+#define CD2401_RECORD_SET_ATTRIBUTES_INFO( args )
+#define CD2401_RECORD_DRAIN_OUTPUT_INFO( args )
+#define CD2401_RECORD_DELAY_INFO( args )
+
+#endif
diff --git a/bsps/m68k/mvme167/console/console.c b/bsps/m68k/mvme167/console/console.c
new file mode 100644
index 0000000000..0499ac46b3
--- /dev/null
+++ b/bsps/m68k/mvme167/console/console.c
@@ -0,0 +1,1676 @@
+/*
+ * This file contains the MVME167 termios console package. Only asynchronous
+ * I/O is supported.
+ *
+ * /dev/tty0 is channel 0, Serial Port 1/Console on the MVME712M.
+ * /dev/tty1 is channel 1, Serial Port 2/TTY01 on the MVME712M.
+ * /dev/tty2 is channel 2, Serial Port 3 on the MVME712M.
+ * /dev/tty3 is channel 3, Serial Port 4 on the MVME712M.
+ *
+ * Normal I/O uses DMA for output, interrupts for input. /dev/console is
+ * fixed to be /dev/tty01, Serial Port 2. Very limited support is provided
+ * for polled I/O. Polled I/O is intended only for running the RTEMS test
+ * suites. In all cases, Serial Port 1/Console is allocated to 167Bug and
+ * is the dedicated debugger port. We configure GDB to use 167Bug for
+ * debugging. When debugging with GDB or 167Bug, do not open /dev/tty00.
+ *
+ * Modern I/O chips often contain a number of I/O devices that can operate
+ * almost independently of each other. Typically, in RTEMS, all devices in
+ * an I/O chip are handled by a single device driver, but that need not be
+ * always the case. Each device driver must supply six entry points in the
+ * Device Driver Table: a device initialization function, as well as an open,
+ * close, read, write and a control function. RTEMS assigns a device major
+ * number to each device driver. This major device number is the index of the
+ * device driver entries in the Device Driver Table, and it used to identify
+ * a particular device driver. To distinguish multiple I/O sub-devices within
+ * an I/O chip, RTEMS supports device minor numbers. When a I/O device is
+ * initialized, the major number is supplied to the initialization function.
+ * That function must register each sub-device with a separate name and minor
+ * number (as well as the supplied major number). When an application opens a
+ * device by name, the corresponding major and minor numbers are returned to
+ * the caller to be used in subsequent I/O operations (although these details
+ * are typically hidden within the library functions).
+ *
+ * Such a scheme recognizes that the initialization of the individual
+ * sub-devices is generally not completely independent. For example, the
+ * four serial ports of the CD2401 can be configured almost independently
+ * from each other. One port could be configured to operate in asynchronous
+ * mode with interrupt-driven I/O, while another port could be configured to
+ * operate in HDLC mode with DMA I/O. However, a device reset command will
+ * reset all four channels, and the width of DMA transfers and the number of
+ * retries following bus errors selected applies to all four channels.
+ * Consequently, when initializing one channel, one must be careful not to
+ * destroy the configuration of other channels that are already configured.
+ *
+ * One problem with the RTEMS I/O initialization model is that no information
+ * other than a device major number is passed to the initialization function.
+ * Consequently, the sub-devices must be initialized with some pre-determined
+ * configuration. To change the configuration of a sub-device, it is
+ * necessary to either rewrite the initialization function, or to make a
+ * series of rtems_io_control() calls after initialization. The first
+ * approach is not very elegant. The second approach is acceptable if an
+ * application is simply changing baud rates, parity or other such
+ * asynchronous parameters (as supplied by the termios package). But what if
+ * an application requires one channel to run in HDLC or Bisync mode and
+ * another in async mode? With a single driver per I/O chip approach, the
+ * device driver must support multiple protocols. This is feasible, but it
+ * often means that an application that only does asynchronous I/O now links
+ * in code for other unused protocols, thus wasting precious ROM space.
+ * Worse, it requires that the sub-devices be initialized in some
+ * configuration, and that configuration then changed through a series of
+ * device driver control calls. There is no standard API in RTEMS to switch
+ * a serial line to some synchronous protocol.
+ *
+ * A better approach is to treat each channel as a separate device, each with
+ * its own device device driver. The application then supplies its own device
+ * driver table with only the required protocols (drivers) on each line. The
+ * problem with this approach is that the device drivers are not really
+ * independent, given that the I/O sub-devices within a common chip are not
+ * independent themselves. Consequently, the related device drivers must
+ * share some information. In RTEMS, there is no standard location in which
+ * to share information.
+ *
+ * This driver handles all four channels, i.e. it distinguishes the
+ * sub-devices using minor device numbers. Only asynchronous I/O is
+ * supported. The console is currently fixed to be channel 1 on the CD2401,
+ * which corresponds to the TTY01 port (Serial Port 2) on the MVME712M
+ * Transition Module.
+ *
+ * The CD2401 does either interrupt-driven or DMA I/O; it does not support
+ * polling. In interrupt-driven or DMA I/O modes, interrupts from the CD2401
+ * are routed to the MC68040, and the processor generates an interrupt
+ * acknowledge cycle directly to the CD2401 to obtain an interrupt vector.
+ * The PCCchip2 supports a pseudo-polling mode in which interrupts from the
+ * CD2401 are not routed to the MC68040, but can be detected by the processor
+ * by reading the appropriate CD2401 registers. In this mode, interrupt
+ * acknowledge cycles must be generated to the CD2401 by reading the
+ * appropriate PCCchip2 registers.
+ *
+ * Interrupts from the four channels cannot be routed independently; either
+ * all channels are used in the pseudo-polling mode, or all channels are used
+ * in interrupt-driven/DMA mode. There is no advantage in using the speudo-
+ * polling mode. Consenquently, this driver performs DMA input and output.
+ * Output is performed directly from the termios raw output buffer, while
+ * input is accumulated into a separate buffer.
+ *
+ * THIS MODULE IS NOT RE-ENTRANT! Simultaneous access to a device from
+ * multiple tasks is likely to cause significant problems! Concurrency
+ * control is implemented in the termios package.
+ *
+ * THE INTERRUPT LEVEL IS SET TO 1 FOR ALL CHANNELS.
+ * If the CD2401 is to be used for high speed synchronous serial I/O, the
+ * interrupt priority might need to be increased.
+ *
+ * ALL INTERRUPT HANDLERS ARE SHARED.
+ * When adding extra device drivers, either rewrite the interrupt handlers
+ * to demultiplex the interrupts, or install separate vectors. Common vectors
+ * are currently used to catch spurious interrupts. We could already have
+ * installed separate vectors for each channel and used the spurious
+ * interrupt handler defined in some other BSPs, but handling spurious
+ * interrupts from the CD2401 in this device driver allows us to record more
+ * information on the source of the interrupts. Furthermore, we have observed
+ * the occasional spurious interrupt from channel 0. We definitely do not
+ * to call a debugger for those.
+ *
+ * All page references are to the MVME166/MVME167/MVME187 Single Board
+ * Computer Programmer's Reference Guide (MVME187PG/D2) with the April
+ * 1993 supplements/addenda (MVME187PG/D2A1).
+ */
+
+/*
+ * Copyright (c) 1998, National Research Council of Canada
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#define M167_INIT
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include <rtems/console.h>
+#include <rtems/libio.h>
+#include <rtems/termiostypes.h>
+#include <bsp.h> /* Must be before libio.h */
+
+/* Utility functions */
+void cd2401_udelay( unsigned long delay );
+void cd2401_chan_cmd( uint8_t channel, uint8_t cmd, uint8_t wait );
+uint16_t cd2401_bitrate_divisor( uint32_t clkrate, uint32_t * bitrate );
+void cd2401_initialize( void );
+void cd2401_interrupts_initialize( bool enable );
+
+/* ISRs */
+rtems_isr cd2401_modem_isr( rtems_vector_number vector );
+rtems_isr cd2401_re_isr( rtems_vector_number vector );
+rtems_isr cd2401_rx_isr( rtems_vector_number vector );
+rtems_isr cd2401_tx_isr( rtems_vector_number vector );
+
+/* Termios callbacks */
+int cd2401_firstOpen( int major, int minor, void *arg );
+int cd2401_lastClose( int major, int minor, void *arg );
+int cd2401_setAttributes( int minor, const struct termios *t );
+int cd2401_startRemoteTx( int minor );
+int cd2401_stopRemoteTx( int minor );
+ssize_t cd2401_write( int minor, const char *buf, size_t len );
+int cd2401_drainOutput( int minor );
+int _167Bug_pollRead( int minor );
+ssize_t _167Bug_pollWrite( int minor, const char *buf, size_t len );
+
+/* Printk function */
+static void _BSP_output_char( char c );
+BSP_output_char_function_type BSP_output_char = _BSP_output_char;
+BSP_polling_getchar_function_type BSP_poll_char = NULL;
+
+/* '\r' character in memory. This used to live on
+ * the stack but storing the '\r' character is
+ * optimized away by gcc-4.3.2 (since it seems to
+ * be unused [only referenced from inline assembly
+ * code in _167Bug_pollWrite()]).
+ * Hence we make it a global constant.
+ */
+static const char cr_char = '\r';
+
+/* Channel info */
+/* static */ volatile struct {
+ void *tty; /* Really a struct rtems_termios_tty * */
+ int len; /* Record nb of chars being TX'ed */
+ const char *buf; /* Record where DMA is coming from */
+ uint32_t spur_cnt; /* Nb of spurious ints so far */
+ uint32_t spur_dev; /* Indo on last spurious int */
+ uint32_t buserr_addr; /* Faulting address */
+ uint32_t buserr_type; /* Reason of bus error during DMA */
+ uint8_t own_buf_A; /* If true, buffer A belongs to the driver */
+ uint8_t own_buf_B; /* If true, buffer B belongs to the driver */
+ uint8_t txEmpty; /* If true, the output FIFO should be empty */
+} CD2401_Channel_Info[4];
+
+/*
+ * The number of channels already opened. If zero, enable the interrupts. The
+ * initial value must be 0. If initialized explicitly, the variable ends up
+ * in the .data section. Its value is not re-initialized on system restart.
+ * Furthermore, because the variable is changed, the .data section would not
+ * be ROMable. We thus leave the variable uninitialized, which causes it to
+ * be allocated in the .bss section, and rely on RTEMS to zero the .bss
+ * section on every startup.
+ */
+uint8_t Init_count;
+
+/* Record previous handlers */
+rtems_isr_entry Prev_re_isr; /* Previous rx exception isr */
+rtems_isr_entry Prev_rx_isr; /* Previous rx isr */
+rtems_isr_entry Prev_tx_isr; /* Previous tx isr */
+rtems_isr_entry Prev_modem_isr; /* Previous modem/timer isr */
+
+/* Define the following symbol to trace the calls to this driver */
+/* #define CD2401_RECORD_DEBUG_INFO */
+#include "console-recording.h"
+
+/*
+ * Utility functions.
+ */
+
+/*
+ * Assumes that clock ticks 1 million times per second.
+ *
+ * MAXIMUM DELAY IS ABOUT 20 ms
+ *
+ * Input parameters:
+ * delay: Number of microseconds to delay.
+ *
+ * Output parameters: NONE
+ *
+ * Return values: NONE
+ */
+ void cd2401_udelay
+(
+ unsigned long delay
+)
+{
+ unsigned long i = 20000; /* In case clock is off */
+ rtems_interval start_ticks, end_ticks, current_ticks;
+
+ start_ticks = rtems_clock_get_ticks_since_boot();
+ end_ticks = start_ticks + delay;
+
+ do {
+ current_ticks = rtems_clock_get_ticks_since_boot();
+ } while ( --i && (current_ticks <= end_ticks) );
+
+ CD2401_RECORD_DELAY_INFO(( start_ticks, end_ticks, current_ticks, i ));
+}
+
+/*
+ * cd2401_chan_cmd
+ *
+ * Sends a CCR command to the specified channel. Waits for any unfinished
+ * previous command to complete, then sends the specified command. Optionally
+ * wait for the current command to finish before returning.
+ *
+ * Input parameters:
+ * channel - CD2401 channel number
+ * cmd - command byte
+ * wait - if non-zero, wait for specified command to complete before
+ * returning.
+ *
+ * Output parameters: NONE
+ *
+ * Return values: NONE
+ */
+void cd2401_chan_cmd(
+ uint8_t channel,
+ uint8_t cmd,
+ uint8_t wait
+)
+{
+ if ( channel < 4 ) {
+ cd2401->car = channel; /* Select channel */
+
+ while ( cd2401->ccr != 0 ); /* Wait for completion of previous command */
+ cd2401->ccr = cmd; /* Send command */
+ if ( wait )
+ while( cd2401->ccr != 0 );/* Wait for completion */
+ }
+ else {
+ /* This may not be the best error message */
+ rtems_fatal_error_occurred( RTEMS_INVALID_NUMBER );
+ }
+}
+
+/*
+ * cd2401_bitrate_divisor
+ *
+ * Compute the divisor and clock source to use to obtain the desired bitrate.
+ *
+ * Input parameters:
+ * clkrate - system clock rate (CLK input frequency)
+ * bitrate - the desired bitrate
+ *
+ * Output parameters:
+ * bitrate - The actual bitrate achievable, to the nearest bps.
+ *
+ * Return values:
+ * Returns divisor in lower byte and clock source in upper byte for the
+ * specified bitrate.
+ */
+uint16_t cd2401_bitrate_divisor(
+ uint32_t clkrate,
+ uint32_t * bitrate
+)
+{
+ uint32_t divisor;
+ uint16_t clksource;
+
+ divisor = *bitrate << 3; /* temporary; multiply by 8 for CLK/8 */
+ divisor = (clkrate + (divisor>>1)) / divisor; /* divisor for clk0 (CLK/8) */
+
+ /* Use highest speed clock source for best precision - try clk0 to clk4 */
+ for( clksource = 0; clksource < 0x0400 && divisor > 0x100; clksource += 0x0100 )
+ divisor >>= 2;
+ divisor--; /* adjustment, see specs */
+ if( divisor < 1 )
+ divisor = 1;
+ else if( divisor > 0xFF )
+ divisor = 0xFF;
+ *bitrate = clkrate / (1 << ((clksource >> 7)+3)) / (divisor+1);
+ return( clksource | divisor );
+}
+
+/*
+ * cd2401_initialize
+ *
+ * Initializes the CD2401 device. Individual channels on the chip are left in
+ * their default reset state, and should be subsequently configured.
+ *
+ * Input parameters: NONE
+ *
+ * Output parameters: NONE
+ *
+ * Return values: NONE
+ */
+void cd2401_initialize( void )
+{
+ int i;
+
+ for ( i = 3; i >= 0; i-- ) {
+ CD2401_Channel_Info[i].tty = NULL;
+ CD2401_Channel_Info[i].len = 0;
+ CD2401_Channel_Info[i].buf = NULL;
+ CD2401_Channel_Info[i].spur_cnt = 0;
+ CD2401_Channel_Info[i].spur_dev = 0;
+ CD2401_Channel_Info[i].buserr_type = 0;
+ CD2401_Channel_Info[i].buserr_addr = 0;
+ CD2401_Channel_Info[i].own_buf_A = TRUE;
+ CD2401_Channel_Info[i].own_buf_B = TRUE;
+ CD2401_Channel_Info[i].txEmpty = TRUE;
+ }
+
+ /*
+ * Normally, do a device reset here. If we do it, we will most likely clober
+ * the port settings for 167Bug on channel 0. So we just shut up all the
+ * ports by disabling their interrupts.
+ */
+#if 0
+ cd2401->gfrcr = 0; /* So we can detect that device init is done */
+ cd2401_chan_cmd( 0x10, 0); /* Reset all */
+ while(cd2401->gfrcr == 0); /* Wait for reset all */
+#endif
+
+ /*
+ * The CL-CD2400/2401 manual (part no 542400-003) states on page 87 that
+ * the LICR "contains the number of the interrupting channel being served.
+ * The channel number is always that of the current acknowledged interrupt."
+ * THE USER MUST PROGRAM CHANNEL NUMBER IN LICR! It is not set automatically
+ * by the hardware, as suggested by the manual.
+ *
+ * The updated manual (part no 542400-007) has the story straight. The
+ * CD2401 automatically initializes the LICR to contain the channel number
+ * in bits 2 and 3. However, these bits are not preserved when the user
+ * defined bits are written.
+ *
+ * The same vector number is used for all four channels. Different vector
+ * numbers could be programmed for each channel, thus avoiding the need to
+ * demultiplex the interrupts in the ISR.
+ */
+ for ( i = 0; i < 4; i++ ) {
+ cd2401->car = i; /* Select channel */
+ cd2401->livr = 0x5C; /* Motorola suggested value p. 3-15 */
+ cd2401->licr = i << 2; /* Don't rely on reset value */
+ cd2401->ier = 0; /* Disable all interrupts */
+ }
+
+ /*
+ * The content of the CD2401 xpilr registers must match the A7-A0 addresses
+ * generated by the PCCchip2 during interrupt acknowledge cycles in order
+ * for the CD2401 to recognize the IACK cycle and clear its interrupt
+ * request.
+ */
+ cd2401->mpilr = 0x01; /* Match pccchip2->modem_piack p. 3-27 */
+ cd2401->tpilr = 0x02; /* Match pccchip2->tx_piack p. 3-28 */
+ cd2401->rpilr = 0x03; /* Match pccchip2->rx_piack p. 3-29 */
+
+ /* Global CD2401 registers */
+ cd2401->dmr = 0; /* 16-bit DMA transfers when possible */
+ cd2401->bercnt = 0; /* Do not retry DMA upon bus errors */
+
+ /*
+ * Setup timer prescaler period, which clocks timers 1 and 2 (or rx timeout
+ * and tx delay). The prescaler is clocked by the system clock) / 2048. The
+ * register must be in the range 0x0A..0xFF, ie. a rescaler period range of
+ * about 1ms..26ms for a nominal system clock rate of 20MHz.
+ */
+ cd2401->tpr = 0x0A; /* Same value as 167Bug */
+}
+
+/*
+ * cd2401_interrupts_initialize
+ *
+ * This routine enables or disables the CD2401 interrupts to the MC68040.
+ * Interrupts cannot be enabled/disabled on a per-channel basis.
+ *
+ * Input parameters:
+ * enable - if true, enable the interrupts, else disable them.
+ *
+ * Output parameters: NONE
+ *
+ * Return values: NONE
+ *
+ * THE FIRST CD2401 CHANNEL OPENED SHOULD ENABLE INTERRUPTS.
+ * THE LAST CD2401 CHANNEL CLOSED SHOULD DISABLE INTERRUPTS.
+ */
+void cd2401_interrupts_initialize(
+ bool enable
+)
+{
+ if ( enable ) {
+ /*
+ * Enable interrupts from the CD2401 in the PCCchip2.
+ * During DMA transfers, the MC68040 supplies dirty data during read cycles
+ * from the CD2401 and leaves the data dirty in its data cache if there is
+ * a cache hit. The MC68040 updates the data cache during write cycles from
+ * the CD2401 if there is a cache hit.
+ */
+ pccchip2->SCC_error = 0x01;
+ pccchip2->SCC_modem_int_ctl = 0x10 | CD2401_INT_LEVEL;
+ pccchip2->SCC_tx_int_ctl = 0x10 | CD2401_INT_LEVEL;
+ pccchip2->SCC_rx_int_ctl = 0x50 | CD2401_INT_LEVEL;
+
+ pccchip2->gen_control |= 0x02; /* Enable pccchip2 interrupts */
+ }
+ else {
+ /* Disable interrupts */
+ pccchip2->SCC_modem_int_ctl &= 0xEF;
+ pccchip2->SCC_tx_int_ctl &= 0xEF;
+ pccchip2->SCC_rx_int_ctl &= 0xEF;
+ }
+}
+
+/* ISRs */
+
+/*
+ * cd2401_modem_isr
+ *
+ * Modem/timer interrupt (group 1) from CD2401. These are not used, and not
+ * expected. Record as spurious and clear.
+ *
+ * Input parameters:
+ * vector - vector number
+ *
+ * Output parameters: NONE
+ *
+ * Return values: NONE
+ */
+rtems_isr cd2401_modem_isr(
+ rtems_vector_number vector
+)
+{
+ uint8_t ch;
+
+ /* Get interrupting channel ID */
+ ch = cd2401->licr >> 2;
+
+ /* Record interrupt info for debugging */
+ CD2401_Channel_Info[ch].spur_dev =
+ (vector << 24) | (cd2401->stk << 16) | (cd2401->mir << 8) | cd2401->misr;
+ CD2401_Channel_Info[ch].spur_cnt++;
+
+ cd2401->meoir = 0; /* EOI */
+ CD2401_RECORD_MODEM_ISR_SPURIOUS_INFO(( ch,
+ CD2401_Channel_Info[ch].spur_dev,
+ CD2401_Channel_Info[ch].spur_cnt ));
+}
+
+/*
+ * cd2401_re_isr
+ *
+ * RX exception interrupt (group 3, receiver exception) from CD2401. These are
+ * not used, and not expected. Record as spurious and clear.
+ *
+ * FIX THIS ISR TO DETECT BREAK CONDITIONS AND RAISE SIGINT
+ *
+ * Input parameters:
+ * vector - vector number
+ *
+ * Output parameters: NONE
+ *
+ * Return values: NONE
+ */
+rtems_isr cd2401_re_isr(
+ rtems_vector_number vector
+)
+{
+ uint8_t ch;
+
+ /* Get interrupting channel ID */
+ ch = cd2401->licr >> 2;
+
+ /* Record interrupt info for debugging */
+ CD2401_Channel_Info[ch].spur_dev =
+ (vector << 24) | (cd2401->stk << 16) | (cd2401->rir << 8) | cd2401->u5.b.risrl;
+ CD2401_Channel_Info[ch].spur_cnt++;
+
+ if ( cd2401->u5.b.risrl & 0x80 ) /* Timeout interrupt? */
+ cd2401->ier &= 0xDF; /* Disable rx timeout interrupt */
+ cd2401->reoir = 0x08; /* EOI; exception char not read */
+ CD2401_RECORD_RE_ISR_SPURIOUS_INFO(( ch,
+ CD2401_Channel_Info[ch].spur_dev,
+ CD2401_Channel_Info[ch].spur_cnt ));
+}
+
+/*
+ * cd2401_rx_isr
+ *
+ * RX interrupt (group 3, receiver data) from CD2401.
+ *
+ * Input parameters:
+ * vector - vector number
+ *
+ * Output parameters: NONE
+ *
+ * Return values: NONE
+ */
+rtems_isr cd2401_rx_isr(
+ rtems_vector_number vector
+)
+{
+ char c;
+ uint8_t ch, status, nchars, total;
+ #ifdef CD2401_RECORD_DEBUG_INFO
+ uint8_t i = 0;
+ char buffer[256];
+ #endif
+
+ (void) total; /* avoid set but not used warnings when not recording info */
+
+ status = cd2401->u5.b.risrl;
+ ch = cd2401->licr >> 2;
+
+ /* Has this channel been initialized or is it a condition we ignore? */
+ if ( CD2401_Channel_Info[ch].tty && !status ) {
+ /* Normal Rx Int, read chars, enqueue them, and issue EOI */
+ total = nchars = cd2401->rfoc; /* Nb of chars to retrieve from rx FIFO */
+ while ( nchars-- > 0 ) {
+ c = (char)cd2401->dr; /* Next char in rx FIFO */
+ rtems_termios_enqueue_raw_characters( CD2401_Channel_Info[ch].tty ,&c, 1 );
+ #ifdef CD2401_RECORD_DEBUG_INFO
+ buffer[i++] = c;
+ #endif
+ }
+ cd2401->reoir = 0; /* EOI */
+ CD2401_RECORD_RX_ISR_INFO(( ch, total, buffer ));
+ } else {
+ /* No, record as spurious interrupt */
+ CD2401_Channel_Info[ch].spur_dev =
+ (vector << 24) | (cd2401->stk << 16) | (cd2401->rir << 8) | cd2401->u5.b.risrl;
+ CD2401_Channel_Info[ch].spur_cnt++;
+ cd2401->reoir = 0x04; /* EOI - character not read */
+ CD2401_RECORD_RX_ISR_SPURIOUS_INFO(( ch, status,
+ CD2401_Channel_Info[ch].spur_dev,
+ CD2401_Channel_Info[ch].spur_cnt ));
+ }
+}
+
+/*
+ * cd2401_tx_isr
+ *
+ * TX interrupt (group 2) from CD2401.
+ *
+ * Input parameters:
+ * vector - vector number
+ *
+ * Output parameters: NONE
+ *
+ * Return values: NONE
+ */
+rtems_isr cd2401_tx_isr(
+ rtems_vector_number vector
+)
+{
+ uint8_t ch, status, buserr, initial_ier, final_ier;
+
+ status = cd2401->tisr;
+ ch = cd2401->licr >> 2;
+ initial_ier = cd2401->ier;
+
+ #ifndef CD2401_RECORD_DEBUG_INFO
+ /*
+ * When the debug is disabled, these variables are really not read.
+ * But when debug is enabled, they are.
+ */
+ (void) initial_ier; /* avoid set but not used warning */
+ (void) final_ier; /* avoid set but not used warning */
+ #endif
+
+ /* Has this channel been initialized? */
+ if ( !CD2401_Channel_Info[ch].tty ) {
+ /* No, record as spurious interrupt */
+ CD2401_Channel_Info[ch].spur_dev =
+ (vector << 24) | (cd2401->stk << 16) | (cd2401->tir << 8) | cd2401->tisr;
+ CD2401_Channel_Info[ch].spur_cnt++;
+ final_ier = cd2401->ier &= 0xFC;/* Shut up, whoever you are */
+
+ cd2401->teoir = 0x88; /* EOI - Terminate buffer and no transfer */
+ CD2401_RECORD_TX_ISR_SPURIOUS_INFO(( ch, status, initial_ier, final_ier,
+ CD2401_Channel_Info[ch].spur_dev,
+ CD2401_Channel_Info[ch].spur_cnt ));
+ return;
+ }
+
+ if ( status & 0x80 ) {
+ /*
+ * Bus error occurred during DMA transfer. For now, just record.
+ * Get reason for DMA bus error and clear the report for the next
+ * occurrence
+ */
+ buserr = pccchip2->SCC_error;
+ pccchip2->SCC_error = 0x01;
+ CD2401_Channel_Info[ch].buserr_type =
+ (vector << 24) | (buserr << 16) | (cd2401->tir << 8) | cd2401->tisr;
+ CD2401_Channel_Info[ch].buserr_addr =
+ (((uint32_t)cd2401->tcbadru) << 16) | cd2401->tcbadrl;
+
+ cd2401->teoir = 0x80; /* EOI - terminate bad buffer */
+ CD2401_RECORD_TX_ISR_BUSERR_INFO(( ch, status, initial_ier, buserr,
+ CD2401_Channel_Info[ch].buserr_type,
+ CD2401_Channel_Info[ch].buserr_addr ));
+ return;
+ }
+
+ if ( status & 0x20 ) {
+ /* DMA done -- Turn off TxD int, turn on TxMpty */
+ final_ier = cd2401->ier = (cd2401->ier & 0xFE) | 0x02;
+ if( status & 0x08 ) {
+ /* Transmit buffer B was released */
+ CD2401_Channel_Info[ch].own_buf_B = TRUE;
+ }
+ else {
+ /* Transmit buffer A was released */
+ CD2401_Channel_Info[ch].own_buf_A = TRUE;
+ }
+ CD2401_RECORD_TX_ISR_INFO(( ch, status, initial_ier, final_ier,
+ CD2401_Channel_Info[ch].txEmpty ));
+
+ /* This call can result in a call to cd2401_write() */
+ rtems_termios_dequeue_characters (
+ CD2401_Channel_Info[ch].tty,
+ CD2401_Channel_Info[ch].len );
+ cd2401->teoir = 0x08; /* EOI - no data transfered */
+ }
+ else if ( status & 0x02 ) {
+ /* TxEmpty */
+ CD2401_Channel_Info[ch].txEmpty = TRUE;
+ final_ier = cd2401->ier &= 0xFD;/* Shut up the interrupts */
+ cd2401->teoir = 0x08; /* EOI - no data transfered */
+ CD2401_RECORD_TX_ISR_INFO(( ch, status, initial_ier, final_ier,
+ CD2401_Channel_Info[ch].txEmpty ));
+ }
+ else {
+ /* Why did we get a Tx interrupt? */
+ CD2401_Channel_Info[ch].spur_dev =
+ (vector << 24) | (cd2401->stk << 16) | (cd2401->tir << 8) | cd2401->tisr;
+ CD2401_Channel_Info[ch].spur_cnt++;
+ cd2401->teoir = 0x08; /* EOI - no data transfered */
+ CD2401_RECORD_TX_ISR_SPURIOUS_INFO(( ch, status, initial_ier, 0xFF,
+ CD2401_Channel_Info[ch].spur_dev,
+ CD2401_Channel_Info[ch].spur_cnt ));
+ }
+}
+
+/*
+ * termios callbacks
+ */
+
+/*
+ * cd2401_firstOpen
+ *
+ * This is the first time that this minor device (channel) is opened.
+ * Complete the asynchronous initialization.
+ *
+ * Input parameters:
+ * major - device major number
+ * minor - channel number
+ * arg - pointer to a struct rtems_libio_open_close_args_t
+ *
+ * Output parameters: NONE
+ *
+ * Return value: IGNORED
+ */
+int cd2401_firstOpen(
+ int major,
+ int minor,
+ void *arg
+)
+{
+ rtems_libio_open_close_args_t *args = arg;
+ rtems_libio_ioctl_args_t newarg;
+ struct termios termios;
+ rtems_status_code sc;
+ rtems_interrupt_level level;
+
+ rtems_interrupt_disable (level);
+
+ /*
+ * Set up the line with the specified parameters. The difficulty is that
+ * the line parameters are stored in the struct termios field of a
+ * struct rtems_termios_tty that is not defined in a public header file.
+ * Therefore, we do not have direct access to the termios passed in with
+ * arg. So we make a rtems_termios_ioctl() call to get a pointer to the
+ * termios structure.
+ *
+ * THIS KLUDGE MAY BREAK IN THE FUTURE!
+ *
+ * We could have made a tcgetattr() call if we had our fd.
+ */
+ newarg.iop = args->iop;
+ newarg.command = TIOCGETA;
+ newarg.buffer = &termios;
+ sc = rtems_termios_ioctl (&newarg);
+ if (sc != RTEMS_SUCCESSFUL)
+ rtems_fatal_error_occurred (sc);
+
+ /*
+ * Turn off hardware flow control. It is a pain with 3-wire cables.
+ * The rtems_termios_ioctl() call below results in a call to
+ * cd2401_setAttributes to initialize the line. The caller will "wait"
+ * on the ttyMutex that it already owns; this is safe in RTEMS.
+ */
+ termios.c_cflag |= CLOCAL; /* Ignore modem status lines */
+ newarg.command = TIOCGETA;
+ sc = rtems_termios_ioctl (&newarg);
+ if (sc != RTEMS_SUCCESSFUL)
+ rtems_fatal_error_occurred (sc);
+
+ /* Mark that the channel as initialized */
+ CD2401_Channel_Info[minor].tty = args->iop->data1;
+
+ /* If the first of the four channels to open, set up the interrupts */
+ if ( !Init_count++ ) {
+ /* Install the interrupt handlers */
+ Prev_re_isr = (rtems_isr_entry) set_vector( cd2401_re_isr, 0x5C, 1 );
+ Prev_modem_isr = (rtems_isr_entry) set_vector( cd2401_modem_isr, 0x5D, 1 );
+ Prev_tx_isr = (rtems_isr_entry) set_vector( cd2401_tx_isr, 0x5E, 1 );
+ Prev_rx_isr = (rtems_isr_entry) set_vector( cd2401_rx_isr, 0x5F, 1 );
+
+ cd2401_interrupts_initialize( TRUE );
+ }
+
+ CD2401_RECORD_FIRST_OPEN_INFO(( minor, Init_count ));
+
+ rtems_interrupt_enable (level);
+
+ /* Return something */
+ return RTEMS_SUCCESSFUL;
+}
+
+/*
+ * cd2401_lastClose
+ *
+ * There are no more opened file descriptors to this device. Close it down.
+ *
+ * Input parameters:
+ * major - device major number
+ * minor - channel number
+ * arg - pointer to a struct rtems_libio_open_close_args_t
+ */
+int cd2401_lastClose(
+ int major,
+ int minor,
+ void *arg
+)
+{
+ rtems_interrupt_level level;
+
+ rtems_interrupt_disable (level);
+
+ /* Mark that the channel is no longer is use */
+ CD2401_Channel_Info[minor].tty = NULL;
+
+ /* If the last of the four channels to close, disable the interrupts */
+ if ( !--Init_count ) {
+ cd2401_interrupts_initialize( FALSE );
+
+ /* De-install the interrupt handlers */
+ set_vector( Prev_re_isr, 0x5C, 1 );
+ set_vector( Prev_modem_isr, 0x5D, 1 );
+ set_vector( Prev_tx_isr, 0x5E, 1 );
+ set_vector( Prev_rx_isr, 0x5F, 1 );
+ }
+
+ CD2401_RECORD_LAST_CLOSE_INFO(( minor, Init_count ));
+
+ rtems_interrupt_enable (level);
+
+ /* return something */
+ return RTEMS_SUCCESSFUL;
+}
+
+/*
+ * cd2401_setAttributes
+ *
+ * Set up the selected channel of the CD2401 chip for doing asynchronous
+ * I/O with DMA.
+ *
+ * The chip must already have been initialized by cd2401_initialize().
+ *
+ * This code was written for clarity. The code space it occupies could be
+ * reduced. The code could also be compiled with aggressive optimization
+ * turned on.
+ *
+ * Input parameters:
+ * minor - the selected channel
+ * t - the termios parameters
+ *
+ * Output parameters: NONE
+ *
+ * Return value: IGNORED
+ */
+int cd2401_setAttributes(
+ int minor,
+ const struct termios *t
+)
+{
+ uint8_t csize, cstopb, parodd, parenb, ignpar, inpck;
+ uint8_t hw_flow_ctl, sw_flow_ctl, extra_flow_ctl;
+ uint8_t icrnl, igncr, inlcr, brkint, ignbrk, parmrk, istrip;
+ uint8_t need_reinitialization = FALSE;
+ uint8_t read_enabled;
+ uint16_t tx_period, rx_period;
+ uint32_t out_baud, in_baud;
+ rtems_interrupt_level level;
+
+ /* Determine what the line parameters should be */
+
+ /* baud rates */
+ out_baud = rtems_termios_baud_to_number(t->c_ospeed);
+ in_baud = rtems_termios_baud_to_number(t->c_ispeed);
+
+ /* Number of bits per char */
+ csize = 0x07; /* to avoid a warning */
+ switch ( t->c_cflag & CSIZE ) {
+ case CS5: csize = 0x04; break;
+ case CS6: csize = 0x05; break;
+ case CS7: csize = 0x06; break;
+ case CS8: csize = 0x07; break;
+ }
+
+ /* Parity */
+ if ( t->c_cflag & PARODD )
+ parodd = 0x80; /* Odd parity */
+ else
+ parodd = 0;
+
+ if ( t->c_cflag & PARENB )
+ parenb = 0x40; /* Parity enabled on Tx and Rx */
+ else
+ parenb = 0x00; /* No parity on Tx and Rx */
+
+ /* CD2401 IGNPAR and INPCK bits are inverted wrt POSIX standard? */
+ if ( t->c_iflag & INPCK )
+ ignpar = 0; /* Check parity on input */
+ else
+ ignpar = 0x10; /* Do not check parity on input */
+ if ( t->c_iflag & IGNPAR ) {
+ inpck = 0x03; /* Discard error character */
+ parmrk = 0;
+ } else {
+ if ( t->c_iflag & PARMRK ) {
+ inpck = 0x01; /* Translate to 0xFF 0x00 <char> */
+ parmrk = 0x04;
+ } else {
+ inpck = 0x01; /* Translate to 0x00 */
+ parmrk = 0;
+ }
+ }
+
+ /* Stop bits */
+ if ( t->c_cflag & CSTOPB )
+ cstopb = 0x04; /* Two stop bits */
+ else
+ cstopb = 0x02; /* One stop bit */
+
+ /* Modem flow control */
+ if ( t->c_cflag & CLOCAL )
+ hw_flow_ctl = 0x04; /* Always assert RTS before Tx */
+ else
+ hw_flow_ctl = 0x07; /* Always assert RTS before Tx,
+ wait for CTS and DSR */
+
+ /* XON/XOFF Tx flow control */
+ if ( t->c_iflag & IXON ) {
+ sw_flow_ctl = 0x40; /* Tx in-band flow ctl enabled, wait for XON */
+ extra_flow_ctl = 0x30; /* Eat XON/XOFF, XON/XOFF in SCHR1, SCHR2 */
+ }
+ else {
+ sw_flow_ctl = 0; /* Tx in-band flow ctl disabled */
+ extra_flow_ctl = 0; /* Pass on XON/XOFF */
+ }
+
+ /* CL/LF translation */
+ if ( t->c_iflag & ICRNL )
+ icrnl = 0x40; /* Map CR to NL on input */
+ else
+ icrnl = 0; /* Pass on CR */
+ if ( t->c_iflag & INLCR )
+ inlcr = 0x20; /* Map NL to CR on input */
+ else
+ inlcr = 0; /* Pass on NL */
+ if ( t->c_iflag & IGNCR )
+ igncr = 0x80; /* CR discarded on input */
+ else
+ igncr = 0;
+
+ /* Break handling */
+ if ( t->c_iflag & IGNBRK ) {
+ ignbrk = 0x10; /* Ignore break on input */
+ brkint = 0x08;
+ } else {
+ if ( t->c_iflag & BRKINT ) {
+ ignbrk = 0; /* Generate SIGINT (interrupt ) */
+ brkint = 0;
+ } else {
+ ignbrk = 0; /* Convert to 0x00 */
+ brkint = 0x08;
+ }
+ }
+
+ /* Stripping */
+ if ( t->c_iflag & ISTRIP )
+ istrip = 0x80; /* Strip to 7 bits */
+ else
+ istrip = 0; /* Leave as 8 bits */
+
+ rx_period = cd2401_bitrate_divisor( 20000000Ul, &in_baud );
+ tx_period = cd2401_bitrate_divisor( 20000000Ul, &out_baud );
+
+ /*
+ * If this is the first time that the line characteristics are set up, then
+ * the device must be re-initialized.
+ * Also check if we need to change anything. It is preferable to not touch
+ * the device if nothing changes. As soon as we touch it, it tends to
+ * glitch. If anything changes, we reprogram all registers. This is
+ * harmless.
+ */
+ if ( ( CD2401_Channel_Info[minor].tty == 0 ) ||
+ ( cd2401->cor1 != (parodd | parenb | ignpar | csize) ) ||
+ ( cd2401->cor2 != (sw_flow_ctl | hw_flow_ctl) ) ||
+ ( cd2401->cor3 != (extra_flow_ctl | cstopb) ) ||
+ ( cd2401->cor6 != (igncr | icrnl | inlcr | ignbrk | brkint | parmrk | inpck) ) ||
+ ( cd2401->cor7 != istrip ) ||
+ ( cd2401->u1.async.schr1 != t->c_cc[VSTART] ) ||
+ ( cd2401->u1.async.schr2 != t->c_cc[VSTOP] ) ||
+ ( cd2401->rbpr != (unsigned char)rx_period ) ||
+ ( cd2401->rcor != (unsigned char)(rx_period >> 8) ) ||
+ ( cd2401->tbpr != (unsigned char)tx_period ) ||
+ ( cd2401->tcor != ( (tx_period >> 3) & 0xE0 ) ) )
+ need_reinitialization = TRUE;
+
+ /* Write to the ports */
+ rtems_interrupt_disable (level);
+
+ cd2401->car = minor; /* Select channel */
+ read_enabled = cd2401->csr & 0x80 ? TRUE : FALSE;
+
+ if ( (t->c_cflag & CREAD ? TRUE : FALSE ) != read_enabled ) {
+ /* Read enable status is changing */
+ need_reinitialization = TRUE;
+ }
+
+ if ( need_reinitialization ) {
+ /*
+ * Could not find a way to test whether the CD2401 was done transmitting.
+ * The TxEmpty interrupt does not seem to indicate that the FIFO is empty
+ * in DMA mode. So, just wait a while for output to drain. May not be
+ * enough, but it will have to do (should be long enough for 1 char at
+ * 9600 bsp)...
+ */
+ cd2401_udelay( 2000L );
+
+ /* Clear channel */
+ cd2401_chan_cmd (minor, 0x40, 1);
+
+ cd2401->car = minor; /* Select channel */
+ cd2401->cmr = 0x42; /* Interrupt Rx, DMA Tx, async mode */
+ cd2401->cor1 = parodd | parenb | ignpar | csize;
+ cd2401->cor2 = sw_flow_ctl | hw_flow_ctl;
+ cd2401->cor3 = extra_flow_ctl | cstopb;
+ cd2401->cor4 = 0x0A; /* No DSR/DCD/CTS detect; FIFO threshold of 10 */
+ cd2401->cor5 = 0x0A; /* No DSR/DCD/CTS detect; DTR threshold of 10 */
+ cd2401->cor6 = igncr | icrnl | inlcr | ignbrk | brkint | parmrk | inpck;
+ cd2401->cor7 = istrip; /* No LNext; ignore XON/XOFF if frame error; no tx translations */
+ /* Special char 1: XON character */
+ cd2401->u1.async.schr1 = t->c_cc[VSTART];
+ /* special char 2: XOFF character */
+ cd2401->u1.async.schr2 = t->c_cc[VSTOP];
+
+ /*
+ * Special chars 3 and 4, char range, LNext, RFAR[1..4] and CRC
+ * are unused, left as is.
+ */
+
+ /* Set baudrates for receiver and transmitter */
+ cd2401->rbpr = (unsigned char)rx_period;
+ cd2401->rcor = (unsigned char)(rx_period >> 8); /* no DPLL */
+ cd2401->tbpr = (unsigned char)tx_period;
+ cd2401->tcor = (tx_period >> 3) & 0xE0; /* no x1 ext clk, no loopback */
+
+ /* Timeout for 4 chars at 9600, 8 bits per char, 1 stop bit */
+ cd2401->u2.w.rtpr = 0x04; /* NEED TO LOOK AT THIS LINE! */
+
+ if ( t->c_cflag & CREAD ) {
+ /* Re-initialize channel, enable rx and tx */
+ cd2401_chan_cmd (minor, 0x2A, 1);
+ /* Enable rx data ints */
+ cd2401->ier = 0x08;
+ } else {
+ /* Re-initialize channel, enable tx, disable rx */
+ cd2401_chan_cmd (minor, 0x29, 1);
+ }
+ }
+
+ CD2401_RECORD_SET_ATTRIBUTES_INFO(( minor, need_reinitialization, csize,
+ cstopb, parodd, parenb, ignpar, inpck,
+ hw_flow_ctl, sw_flow_ctl, extra_flow_ctl,
+ icrnl, igncr, inlcr, brkint, ignbrk,
+ parmrk, istrip, tx_period, rx_period,
+ out_baud, in_baud ));
+
+ rtems_interrupt_enable (level);
+
+ /*
+ * Looks like the CD2401 needs time to settle after initialization. Give it
+ * 10 ms. I don't really believe it, but if output resumes to quickly after
+ * this call, the first few characters are not right.
+ */
+ if ( need_reinitialization )
+ cd2401_udelay( 10000L );
+
+ /* Return something */
+ return RTEMS_SUCCESSFUL;
+}
+
+/*
+ * cd2401_startRemoreTx
+ *
+ * Defined as a callback, but it would appear that it is never called. The
+ * POSIX standard states that when the tcflow() function is called with the
+ * TCION action, the system wall transmit a START character. Presumably,
+ * tcflow() is called internally when IXOFF is set in the termios c_iflag
+ * field when the input buffer can accomodate enough characters. It should
+ * probably be called from fillBufferQueue(). Clearly, the function is also
+ * explicitly callable by user code. The action is clearly to send the START
+ * character, regardless of whether START/STOP flow control is in effect.
+ *
+ * Input parameters:
+ * minor - selected channel
+ *
+ * Output parameters: NONE
+ *
+ * Return value: IGNORED
+ *
+ * PROPER START CHARACTER MUST BE PROGRAMMED IN SCHR1.
+ */
+int cd2401_startRemoteTx(
+ int minor
+)
+{
+ rtems_interrupt_level level;
+
+ rtems_interrupt_disable (level);
+
+ cd2401->car = minor; /* Select channel */
+ cd2401->stcr = 0x01; /* Send SCHR1 ahead of chars in FIFO */
+
+ CD2401_RECORD_START_REMOTE_TX_INFO(( minor ));
+
+ rtems_interrupt_enable (level);
+
+ /* Return something */
+ return RTEMS_SUCCESSFUL;
+}
+
+/*
+ * cd2401_stopRemoteTx
+ *
+ * Defined as a callback, but it would appear that it is never called. The
+ * POSIX standard states that when the tcflow() function is called with the
+ * TCIOFF function, the system wall transmit a STOP character. Presumably,
+ * tcflow() is called internally when IXOFF is set in the termios c_iflag
+ * field as the input buffer is about to overflow. It should probably be
+ * called from rtems_termios_enqueue_raw_characters(). Clearly, the function
+ * is also explicitly callable by user code. The action is clearly to send
+ * the STOP character, regardless of whether START/STOP flow control is in
+ * effect.
+ *
+ * Input parameters:
+ * minor - selected channel
+ *
+ * Output parameters: NONE
+ *
+ * Return value: IGNORED
+ *
+ * PROPER STOP CHARACTER MUST BE PROGRAMMED IN SCHR2.
+ */
+int cd2401_stopRemoteTx(
+ int minor
+)
+{
+ rtems_interrupt_level level;
+
+ rtems_interrupt_disable (level);
+
+ cd2401->car = minor; /* Select channel */
+ cd2401->stcr = 0x02; /* Send SCHR2 ahead of chars in FIFO */
+
+ CD2401_RECORD_STOP_REMOTE_TX_INFO(( minor ));
+
+ rtems_interrupt_enable (level);
+
+ /* Return something */
+ return RTEMS_SUCCESSFUL;
+}
+
+/*
+ * cd2401_write
+ *
+ * Initiate DMA output. Termios guarantees that the buffer does not wrap
+ * around, so we can do DMA strait from the supplied buffer.
+ *
+ * Input parameters:
+ * minor - selected channel
+ * buf - output buffer
+ * len - number of chars to output
+ *
+ * Output parameters: NONE
+ *
+ * Return value: IGNORED
+ *
+ * MUST BE EXECUTED WITH THE CD2401 INTERRUPTS DISABLED!
+ * The processor is placed at interrupt level CD2401_INT_LEVEL explicitly in
+ * console_write(). The processor is necessarily at interrupt level 1 in
+ * cd2401_tx_isr().
+ */
+ssize_t cd2401_write(
+ int minor,
+ const char *buf,
+ size_t len
+)
+{
+ if (len > 0) {
+ cd2401->car = minor; /* Select channel */
+
+ if ( (cd2401->dmabsts & 0x08) == 0 ) {
+ /* Next buffer is A. Wait for it to be ours. */
+ while ( cd2401->atbsts & 0x01 );
+
+ CD2401_Channel_Info[minor].own_buf_A = FALSE;
+ CD2401_Channel_Info[minor].len = len;
+ CD2401_Channel_Info[minor].buf = buf;
+ cd2401->atbadru = (uint16_t)( ( (uint32_t) buf ) >> 16 );
+ cd2401->atbadrl = (uint16_t)( (uint32_t) buf );
+ cd2401->atbcnt = len;
+ CD2401_RECORD_WRITE_INFO(( len, buf, 'A' ));
+ cd2401->atbsts = 0x03; /* CD2401 owns buffer, int when empty */
+ }
+ else {
+ /* Next buffer is B. Wait for it to be ours. */
+ while ( cd2401->btbsts & 0x01 );
+
+ CD2401_Channel_Info[minor].own_buf_B = FALSE;
+ CD2401_Channel_Info[minor].len = len;
+ CD2401_Channel_Info[minor].buf = buf;
+ cd2401->btbadru = (uint16_t)( ( (uint32_t) buf ) >> 16 );
+ cd2401->btbadrl = (uint16_t)( (uint32_t) buf );
+ cd2401->btbcnt = len;
+ CD2401_RECORD_WRITE_INFO(( len, buf, 'B' ));
+ cd2401->btbsts = 0x03; /* CD2401 owns buffer, int when empty */
+ }
+ /* Nuts -- Need TxD ints */
+ CD2401_Channel_Info[minor].txEmpty = FALSE;
+ cd2401->ier |= 0x01;
+ }
+
+ /* Return something */
+ return len;
+}
+
+#if 0
+/*
+ * cd2401_drainOutput
+ *
+ * Wait for the txEmpty indication on the specified channel.
+ *
+ * Input parameters:
+ * minor - selected channel
+ *
+ * Output parameters: NONE
+ *
+ * Return value: IGNORED
+ *
+ * MUST NOT BE EXECUTED WITH THE CD2401 INTERRUPTS DISABLED!
+ * The txEmpty flag is set by the tx ISR.
+ *
+ * DOES NOT WORK! DO NOT ENABLE THIS CODE. THE CD2401 DOES NOT COOPERATE!
+ * The code is here to document that the output FIFO is NOT empty when
+ * the CD2401 reports that the Tx buffer is empty.
+ */
+int cd2401_drainOutput(
+ int minor
+)
+{
+ CD2401_RECORD_DRAIN_OUTPUT_INFO(( CD2401_Channel_Info[minor].txEmpty,
+ CD2401_Channel_Info[minor].own_buf_A,
+ CD2401_Channel_Info[minor].own_buf_B ));
+
+ while( ! (CD2401_Channel_Info[minor].txEmpty &&
+ CD2401_Channel_Info[minor].own_buf_A &&
+ CD2401_Channel_Info[minor].own_buf_B) );
+
+ /* Return something */
+ return RTEMS_SUCCESSFUL;
+}
+#endif
+
+/*
+ * _167Bug_pollRead
+ *
+ * Read a character from the 167Bug console, and return it. Return -1
+ * if there is no character in the input FIFO.
+ *
+ * Input parameters:
+ * minor - selected channel
+ *
+ * Output parameters: NONE
+ *
+ * Return value: char returned as positive signed int
+ * -1 if no character is present in the input FIFO.
+ *
+ * CANNOT BE COMBINED WITH INTERRUPT DRIVEN I/O!
+ */
+int _167Bug_pollRead(
+ int minor
+)
+{
+ int char_not_available;
+ unsigned char c;
+ rtems_interrupt_level previous_level;
+
+ /*
+ * Redirection of .INSTAT does not work: 167-Bug crashes.
+ * Switch the input stream to the specified port.
+ * Make sure this is atomic code.
+ */
+ rtems_interrupt_disable( previous_level );
+
+ __asm__ volatile( "movew %1, -(%%sp)\n\t"/* Channel */
+ "trap #15\n\t" /* Trap to 167Bug */
+ ".short 0x61\n\t" /* Code for .REDIR_I */
+ "trap #15\n\t" /* Trap to 167Bug */
+ ".short 0x01\n\t" /* Code for .INSTAT */
+ "move %%cc, %0\n\t" /* Get condition codes */
+ "andil #4, %0" /* Keep the Zero bit */
+ : "=d" (char_not_available) : "d" (minor): "%%cc" );
+
+ if (char_not_available) {
+ rtems_interrupt_enable( previous_level );
+ return -1;
+ }
+
+ /* Read the char and return it */
+ __asm__ volatile( "subq.l #2,%%a7\n\t" /* Space for result */
+ "trap #15\n\t" /* Trap to 167 Bug */
+ ".short 0x00\n\t" /* Code for .INCHR */
+ "moveb (%%a7)+, %0" /* Pop char into c */
+ : "=d" (c) : );
+
+ rtems_interrupt_enable( previous_level );
+
+ return (int)c;
+}
+
+/*
+ * _167Bug_pollWrite
+ *
+ * Output buffer through 167Bug. Returns only once every character has been
+ * sent (polled output).
+ *
+ * Input parameters:
+ * minor - selected channel
+ * buf - output buffer
+ * len - number of chars to output
+ *
+ * Output parameters: NONE
+ *
+ * Return value: IGNORED
+ *
+ * CANNOT BE COMBINED WITH INTERRUPT DRIVEN I/O!
+ */
+ssize_t _167Bug_pollWrite(
+ int minor,
+ const char *buf,
+ size_t len
+)
+{
+ const char *endbuf = buf + len;
+
+ __asm__ volatile( "pea (%0)\n\t" /* endbuf */
+ "pea (%1)\n\t" /* buf */
+ "movew #0x21, -(%%sp)\n\t" /* Code for .OUTSTR */
+ "movew %2, -(%%sp)\n\t" /* Channel */
+ "trap #15\n\t" /* Trap to 167Bug */
+ ".short 0x60" /* Code for .REDIR */
+ :: "a" (endbuf), "a" (buf), "d" (minor) );
+
+ /* Return something */
+ return len;
+}
+
+/*
+ * do_poll_read
+ *
+ * Input characters through 167Bug. Returns has soon as a character has been
+ * received. Otherwise, if we wait for the number of requested characters, we
+ * could be here forever!
+ *
+ * CR is converted to LF on input. The terminal should not send a CR/LF pair
+ * when the return or enter key is pressed.
+ *
+ * Input parameters:
+ * major - ignored. Should be the major number for this driver.
+ * minor - selected channel.
+ * arg->buffer - where to put the received characters.
+ * arg->count - number of characters to receive before returning--Ignored.
+ *
+ * Output parameters:
+ * arg->bytes_moved - the number of characters read. Always 1.
+ *
+ * Return value: RTEMS_SUCCESSFUL
+ *
+ * CANNOT BE COMBINED WITH INTERRUPT DRIVEN I/O!
+ */
+static rtems_status_code do_poll_read(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+ rtems_libio_rw_args_t *rw_args = arg;
+ int c;
+
+ while( (c = _167Bug_pollRead (minor)) == -1 );
+ rw_args->buffer[0] = (uint8_t)c;
+ if( rw_args->buffer[0] == '\r' )
+ rw_args->buffer[0] = '\n';
+ rw_args->bytes_moved = 1;
+ return RTEMS_SUCCESSFUL;
+}
+
+/*
+ * do_poll_write
+ *
+ * Output characters through 167Bug. Returns only once every character has
+ * been sent.
+ *
+ * CR is transmitted AFTER a LF on output.
+ *
+ * Input parameters:
+ * major - ignored. Should be the major number for this driver.
+ * minor - selected channel
+ * arg->buffer - where to get the characters to transmit.
+ * arg->count - the number of characters to transmit before returning.
+ *
+ * Output parameters:
+ * arg->bytes_moved - the number of characters read
+ *
+ * Return value: RTEMS_SUCCESSFUL
+ *
+ * CANNOT BE COMBINED WITH INTERRUPT DRIVEN I/O!
+ */
+static rtems_status_code do_poll_write(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+ rtems_libio_rw_args_t *rw_args = arg;
+ uint32_t i;
+
+ for( i = 0; i < rw_args->count; i++ ) {
+ _167Bug_pollWrite(minor, &(rw_args->buffer[i]), 1);
+ if ( rw_args->buffer[i] == '\n' )
+ _167Bug_pollWrite(minor, &cr_char, 1);
+ }
+ rw_args->bytes_moved = i;
+ return RTEMS_SUCCESSFUL;
+}
+
+/*
+ * _BSP_output_char
+ *
+ * printk() function prototyped in bspIo.h. Does not use termios.
+ */
+void _BSP_output_char(char c)
+{
+ rtems_device_minor_number printk_minor;
+
+ /*
+ * Can't rely on console_initialize having been called before this function
+ * is used.
+ */
+ if ( NVRAM_CONFIGURE )
+ /* J1-4 is on, use NVRAM info for configuration */
+ printk_minor = (nvram->console_printk_port & 0x30) >> 4;
+ else
+ printk_minor = PRINTK_MINOR;
+
+ _167Bug_pollWrite(printk_minor, &c, 1);
+}
+
+/*
+ ***************
+ * BOILERPLATE *
+ ***************
+ *
+ * All these functions are prototyped in rtems/c/src/lib/include/console.h.
+ */
+
+/*
+ * Initialize and register the device
+ */
+rtems_device_driver console_initialize(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg
+)
+{
+ rtems_status_code status;
+ rtems_device_minor_number console_minor;
+
+ /*
+ * Set up TERMIOS if needed
+ */
+ if ( NVRAM_CONFIGURE ) {
+ /* J1-4 is on, use NVRAM info for configuration */
+ console_minor = nvram->console_printk_port & 0x03;
+
+ if ( nvram->console_mode & 0x01 )
+ /* termios */
+ rtems_termios_initialize ();
+ }
+ else {
+ console_minor = CONSOLE_MINOR;
+#if CD2401_USE_TERMIOS == 1
+ rtems_termios_initialize ();
+#endif
+ }
+
+ /*
+ * Do device-specific initialization
+ * Does not affect 167-Bug.
+ */
+ cd2401_initialize ();
+
+ /*
+ * Register the devices
+ */
+ status = rtems_io_register_name ("/dev/tty0", major, 0);
+ if (status != RTEMS_SUCCESSFUL)
+ rtems_fatal_error_occurred (status);
+
+ status = rtems_io_register_name ("/dev/tty1", major, 1);
+ if (status != RTEMS_SUCCESSFUL)
+ rtems_fatal_error_occurred (status);
+
+ status = rtems_io_register_name ("/dev/console", major, console_minor);
+ if (status != RTEMS_SUCCESSFUL)
+ rtems_fatal_error_occurred (status);
+
+ status = rtems_io_register_name ("/dev/tty2", major, 2);
+ if (status != RTEMS_SUCCESSFUL)
+ rtems_fatal_error_occurred (status);
+
+ status = rtems_io_register_name ("/dev/tty3", major, 3);
+ if (status != RTEMS_SUCCESSFUL)
+ rtems_fatal_error_occurred (status);
+
+ return RTEMS_SUCCESSFUL;
+}
+
+/*
+ * Open the device
+ */
+rtems_device_driver console_open(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+ static const rtems_termios_callbacks pollCallbacks = {
+ NULL, /* firstOpen */
+ NULL, /* lastClose */
+ _167Bug_pollRead, /* pollRead */
+ _167Bug_pollWrite, /* write */
+ NULL, /* setAttributes */
+ NULL, /* stopRemoteTx */
+ NULL, /* startRemoteTx */
+ 0 /* outputUsesInterrupts */
+ };
+
+ static const rtems_termios_callbacks intrCallbacks = {
+ cd2401_firstOpen, /* firstOpen */
+ cd2401_lastClose, /* lastClose */
+ NULL, /* pollRead */
+ cd2401_write, /* write */
+ cd2401_setAttributes, /* setAttributes */
+ cd2401_stopRemoteTx, /* stopRemoteTx */
+ cd2401_startRemoteTx, /* startRemoteTx */
+ 1 /* outputUsesInterrupts */
+ };
+
+ if ( NVRAM_CONFIGURE )
+ /* J1-4 is on, use NVRAM info for configuration */
+ if ( nvram->console_mode & 0x01 )
+ /* termios */
+ if ( nvram->console_mode & 0x02 )
+ /* interrupt-driven I/O */
+ return rtems_termios_open (major, minor, arg, &intrCallbacks);
+ else
+ /* polled I/O */
+ return rtems_termios_open (major, minor, arg, &pollCallbacks);
+ else
+ /* no termios -- default to polled I/O */
+ return RTEMS_SUCCESSFUL;
+#if CD2401_USE_TERMIOS == 1
+#if CD2401_IO_MODE != 1
+ else
+ /* termios & polled I/O*/
+ return rtems_termios_open (major, minor, arg, &pollCallbacks);
+#else
+ else
+ /* termios & interrupt-driven I/O*/
+ return rtems_termios_open (major, minor, arg, &intrCallbacks);
+#endif
+#else
+ else
+ /* no termios -- default to polled I/O */
+ return RTEMS_SUCCESSFUL;
+#endif
+}
+
+/*
+ * Close the device
+ */
+rtems_device_driver console_close(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+ if ( NVRAM_CONFIGURE ) {
+ /* J1-4 is on, use NVRAM info for configuration */
+ if ( nvram->console_mode & 0x01 )
+ /* termios */
+ return rtems_termios_close (arg);
+ else
+ /* no termios */
+ return RTEMS_SUCCESSFUL;
+ }
+#if CD2401_USE_TERMIOS == 1
+ else
+ /* termios */
+ return rtems_termios_close (arg);
+#else
+ else
+ /* no termios */
+ return RTEMS_SUCCESSFUL;
+#endif
+}
+
+/*
+ * Read from the device
+ */
+rtems_device_driver console_read(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+ if ( NVRAM_CONFIGURE ) {
+ /* J1-4 is on, use NVRAM info for configuration */
+ if ( nvram->console_mode & 0x01 )
+ /* termios */
+ return rtems_termios_read (arg);
+ else
+ /* no termios -- default to polled */
+ return do_poll_read (major, minor, arg);
+ }
+#if CD2401_USE_TERMIOS == 1
+ else
+ /* termios */
+ return rtems_termios_read (arg);
+#else
+ else
+ /* no termios -- default to polled */
+ return do_poll_read (major, minor, arg);
+#endif
+}
+
+/*
+ * Write to the device
+ */
+rtems_device_driver console_write(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+ if ( NVRAM_CONFIGURE ) {
+ /* J1-4 is on, use NVRAM info for configuration */
+ if ( nvram->console_mode & 0x01 )
+ /* termios */
+ return rtems_termios_write (arg);
+ else
+ /* no termios -- default to polled */
+ return do_poll_write (major, minor, arg);
+ }
+#if CD2401_USE_TERMIOS == 1
+ else
+ /* termios */
+ return rtems_termios_write (arg);
+#else
+ else
+ /* no termios -- default to polled */
+ return do_poll_write (major, minor, arg);
+#endif
+}
+
+/*
+ * Handle ioctl request.
+ */
+rtems_device_driver console_control(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+ if ( NVRAM_CONFIGURE ) {
+ /* J1-4 is on, use NVRAM info for configuration */
+ if ( nvram->console_mode & 0x01 )
+ /* termios */
+ return rtems_termios_ioctl (arg);
+ else
+ /* no termios -- default to polled */
+ return RTEMS_SUCCESSFUL;
+ }
+#if CD2401_USE_TERMIOS == 1
+ else
+ /* termios */
+ return rtems_termios_ioctl (arg);
+#else
+ else
+ /* no termios -- default to polled */
+ return RTEMS_SUCCESSFUL;
+#endif
+}
diff --git a/bsps/m68k/uC5282/console/console.c b/bsps/m68k/uC5282/console/console.c
new file mode 100644
index 0000000000..276d0c6f18
--- /dev/null
+++ b/bsps/m68k/uC5282/console/console.c
@@ -0,0 +1,774 @@
+/*
+ * Multi UART console serial I/O.
+ *
+ * TO DO: Add DMA input/output
+ *
+ * Author: W. Eric Norum <norume@aps.anl.gov>
+ *
+ * COPYRIGHT (c) 2005.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ *
+ */
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <malloc.h>
+
+#include <rtems/console.h>
+#include <rtems/libio.h>
+#include <rtems/termiostypes.h>
+#include <bsp.h>
+
+#include <rtems/bspIo.h>
+
+#define UART_INTC0_IRQ_VECTOR(x) (64+13+(x))
+
+#define MCF5282_UART_USR_ERROR ( MCF5282_UART_USR_RB | \
+ MCF5282_UART_USR_FE | \
+ MCF5282_UART_USR_PE | \
+ MCF5282_UART_USR_OE )
+
+static ssize_t IntUartPollWrite(int minor, const char *buf, size_t len);
+static ssize_t IntUartInterruptWrite (int minor, const char *buf, size_t len);
+
+static void
+_BSP_null_char( char c )
+{
+ int level;
+
+ rtems_interrupt_disable(level);
+ while ( (MCF5282_UART_USR(CONSOLE_PORT) & MCF5282_UART_USR_TXRDY) == 0 )
+ continue;
+ MCF5282_UART_UTB(CONSOLE_PORT) = c;
+ while ( (MCF5282_UART_USR(CONSOLE_PORT) & MCF5282_UART_USR_TXRDY) == 0 )
+ continue;
+ rtems_interrupt_enable(level);
+}
+
+BSP_polling_getchar_function_type BSP_poll_char = NULL;
+BSP_output_char_function_type BSP_output_char = _BSP_null_char;
+
+/*
+ * The MCF5282 has three UARTs. Enable all them here. I/O pin selection
+ * is assumed to have been done elsewher.
+ */
+#define MAX_UART_INFO 3
+#define RX_BUFFER_SIZE 512
+
+struct IntUartInfoStruct
+{
+ int iomode;
+ volatile int uimr;
+ int baud;
+ int databits;
+ int parity;
+ int stopbits;
+ int hwflow;
+ int rx_in;
+ int rx_out;
+ char rx_buffer[RX_BUFFER_SIZE];
+ void *ttyp;
+};
+
+struct IntUartInfoStruct IntUartInfo[MAX_UART_INFO];
+
+/***************************************************************************
+ Function : IntUartSet
+
+ Description : This updates the hardware UART settings.
+ ***************************************************************************/
+static void
+IntUartSet(int minor, int baud, int databits, int parity, int stopbits, int hwflow)
+{
+ int divisor;
+ uint32_t clock_speed;
+ uint8_t umr1 = 0;
+ uint8_t umr2 = 0;
+ struct IntUartInfoStruct *info = &IntUartInfo[minor];
+ int level;
+
+ rtems_interrupt_disable(level);
+
+
+ /* disable interrupts, clear RTS line, and disable the UARTS */
+ MCF5282_UART_UIMR(minor) = 0;
+ MCF5282_UART_UOP0(minor) = 1;
+ MCF5282_UART_UCR(minor) = (MCF5282_UART_UCR_TX_DISABLED | MCF5282_UART_UCR_RX_DISABLED);
+
+ /* save the current values */
+ info->uimr = 0;
+ info->baud = baud;
+ info->databits = databits;
+ info->parity = parity;
+ info->stopbits = stopbits;
+ info->hwflow = hwflow;
+
+ clock_speed = bsp_get_CPU_clock_speed();
+ /* determine the baud divisor value */
+ divisor = (clock_speed / ( 32 * baud ));
+ if ( divisor < 2 ) {
+ divisor = 2;
+ }
+
+ /* check to see if doing hardware flow control */
+ if ( hwflow )
+ {
+ /* set hardware flow options */
+ umr1 |= MCF5282_UART_UMR1_RXRTS;
+ umr2 |= MCF5282_UART_UMR2_TXCTS;
+ }
+
+ /* determine the new umr values */
+ umr1 |= (parity | databits);
+ umr2 |= (stopbits);
+
+ /* reset the uart */
+ MCF5282_UART_UCR(minor) = MCF5282_UART_UCR_RESET_ERROR;
+ MCF5282_UART_UCR(minor) = MCF5282_UART_UCR_RESET_RX;
+ MCF5282_UART_UCR(minor) = MCF5282_UART_UCR_RESET_TX;
+
+ /* reset the uart mode register and update values */
+ MCF5282_UART_UCR(minor) = MCF5282_UART_UCR_RESET_MR;
+ MCF5282_UART_UMR(minor) = umr1;
+ MCF5282_UART_UMR(minor) = umr2;
+
+ /* set the baud rate values */
+ MCF5282_UART_UCSR(minor) = (MCF5282_UART_UCSR_RCS_SYS_CLK | MCF5282_UART_UCSR_TCS_SYS_CLK);
+ MCF5282_UART_UBG1(minor) = (divisor & 0xff00) >> 8;
+ MCF5282_UART_UBG2(minor) = (divisor & 0x00ff);
+
+ /* enable the uart */
+ MCF5282_UART_UCR(minor) = (MCF5282_UART_UCR_TX_ENABLED | MCF5282_UART_UCR_RX_ENABLED);
+
+ /* check to see if interrupts need to be enabled */
+ if ( info->iomode != TERMIOS_POLLED )
+ {
+ /* enable rx interrupts */
+ info->uimr |= MCF5282_UART_UIMR_FFULL;
+ MCF5282_UART_UIMR(minor) = info->uimr;
+ }
+
+ /* check to see if doing hardware flow control */
+ if ( hwflow )
+ {
+ /* assert the RTS line */
+ MCF5282_UART_UOP1(minor) = 1;
+ }
+
+ rtems_interrupt_enable(level);
+
+}
+
+
+/***************************************************************************
+ Function : IntUartSetAttributes
+
+ Description : This provides the hardware-dependent portion of tcsetattr().
+ value and sets it. At the moment this just sets the baud rate.
+
+ Note: The highest baudrate is 115200 as this stays within
+ an error of +/- 5% at 25MHz processor clock
+ ***************************************************************************/
+static int
+IntUartSetAttributes(int minor, const struct termios *t)
+{
+ /* set default index values */
+ int baud = (int)9600;
+ int databits = (int)MCF5282_UART_UMR1_BC_8;
+ int parity = (int)MCF5282_UART_UMR1_PM_NONE;
+ int stopbits = (int)MCF5282_UART_UMR2_STOP_BITS_1;
+ int hwflow = (int)0;
+ struct IntUartInfoStruct *info = &IntUartInfo[minor];
+
+ /* check to see if input is valid */
+ if ( t != (const struct termios *)0 )
+ {
+ /* determine baud rate index */
+ baud = rtems_termios_baud_to_number(t->c_ospeed);
+
+ /* determine data bits */
+ switch ( t->c_cflag & CSIZE )
+ {
+ case CS5:
+ databits = (int)MCF5282_UART_UMR1_BC_5;
+ break;
+ case CS6:
+ databits = (int)MCF5282_UART_UMR1_BC_6;
+ break;
+ case CS7:
+ databits = (int)MCF5282_UART_UMR1_BC_7;
+ break;
+ case CS8:
+ databits = (int)MCF5282_UART_UMR1_BC_8;
+ break;
+ }
+
+ /* determine if parity is enabled */
+ if ( t->c_cflag & PARENB )
+ {
+ if ( t->c_cflag & PARODD )
+ {
+ /* odd parity */
+ parity = (int)MCF5282_UART_UMR1_PM_ODD;
+ }
+ else
+ {
+ /* even parity */
+ parity = (int)MCF5282_UART_UMR1_PM_EVEN;
+ }
+ }
+
+ /* determine stop bits */
+ if ( t->c_cflag & CSTOPB )
+ {
+ /* two stop bits */
+ stopbits = (int)MCF5282_UART_UMR2_STOP_BITS_2;
+ }
+
+ /* check to see if hardware flow control */
+ if ( t->c_cflag & CRTSCTS )
+ {
+ hwflow = 1;
+ }
+ }
+
+ /* check to see if values have changed */
+ if ( ( baud != info->baud ) ||
+ ( databits != info->databits ) ||
+ ( parity != info->parity ) ||
+ ( stopbits != info->stopbits ) ||
+ ( hwflow != info->hwflow ) )
+ {
+
+ /* call function to set values */
+ IntUartSet(minor, baud, databits, parity, stopbits, hwflow);
+ }
+
+ return( RTEMS_SUCCESSFUL );
+
+}
+
+/***************************************************************************
+ Function : IntUartInterruptHandler
+
+ Description : This is the interrupt handler for the internal uart. It
+ determines which channel caused the interrupt before queueing any received
+ chars and dequeueing chars waiting for transmission.
+ ***************************************************************************/
+static rtems_isr
+IntUartInterruptHandler(rtems_vector_number v)
+{
+ unsigned int chan = v - UART_INTC0_IRQ_VECTOR(0);
+ struct IntUartInfoStruct *info = &IntUartInfo[chan];
+
+ /* check to see if received data */
+ if ( MCF5282_UART_UISR(chan) & MCF5282_UART_UISR_RXRDY )
+ {
+ /* read data and put into the receive buffer */
+ while ( MCF5282_UART_USR(chan) & MCF5282_UART_USR_RXRDY )
+ {
+
+ if ( MCF5282_UART_USR(chan) & MCF5282_UART_USR_ERROR )
+ {
+ /* clear the error */
+ MCF5282_UART_UCR(chan) = MCF5282_UART_UCR_RESET_ERROR;
+ }
+ /* put data in rx buffer and check for errors */
+ info->rx_buffer[info->rx_in] = MCF5282_UART_URB(chan);
+
+ /* update buffer values */
+ info->rx_in++;
+
+ if ( info->rx_in >= RX_BUFFER_SIZE )
+ {
+ info->rx_in = 0;
+ }
+ }
+ /* Make sure the port has been opened */
+ if ( info->ttyp )
+ {
+
+ /* check to see if task driven */
+ if ( info->iomode == TERMIOS_TASK_DRIVEN )
+ {
+ /* notify rx task that rx buffer has data */
+ rtems_termios_rxirq_occured(info->ttyp);
+ }
+ else
+ {
+ /* Push up the received data */
+ rtems_termios_enqueue_raw_characters(info->ttyp, info->rx_buffer, info->rx_in);
+ info->rx_in = 0;
+ }
+ }
+ }
+
+ /* check to see if data needs to be transmitted */
+ if ( ( info->uimr & MCF5282_UART_UIMR_TXRDY ) &&
+ ( MCF5282_UART_UISR(chan) & MCF5282_UART_UISR_TXRDY ) )
+ {
+
+ /* disable tx interrupts */
+ info->uimr &= ~MCF5282_UART_UIMR_TXRDY;
+ MCF5282_UART_UIMR(chan) = info->uimr;
+
+ /* tell upper level that character has been sent */
+ if ( info->ttyp )
+ rtems_termios_dequeue_characters(info->ttyp, 1);
+ }
+}
+
+
+
+/***************************************************************************
+ Function : IntUartInitialize
+
+ Description : This initialises the internal uart hardware for all
+ internal uarts. If the internal uart is to be interrupt driven then the
+ interrupt vectors are hooked.
+ ***************************************************************************/
+static void
+IntUartInitialize(void)
+{
+ unsigned int chan;
+ struct IntUartInfoStruct *info;
+ rtems_isr_entry old_handler;
+ int level;
+
+ for ( chan = 0; chan < MAX_UART_INFO; chan++ )
+ {
+ info = &IntUartInfo[chan];
+
+ info->ttyp = NULL;
+ info->rx_in = 0;
+ info->rx_out = 0;
+ info->baud = -1;
+ info->databits = -1;
+ info->parity = -1;
+ info->stopbits = -1;
+ info->hwflow = -1;
+
+ MCF5282_UART_UACR(chan) = 0;
+ MCF5282_UART_UIMR(chan) = 0;
+ if ( info->iomode != TERMIOS_POLLED )
+ {
+ rtems_interrupt_catch (IntUartInterruptHandler,
+ UART_INTC0_IRQ_VECTOR(chan),
+ &old_handler);
+ }
+
+ /* set uart default values */
+ IntUartSetAttributes(chan, NULL);
+
+ /* unmask interrupt */
+ rtems_interrupt_disable(level);
+ switch(chan) {
+ case 0:
+ bsp_allocate_interrupt(UART0_IRQ_LEVEL, UART0_IRQ_PRIORITY);
+ MCF5282_INTC0_ICR13 = MCF5282_INTC_ICR_IL(UART0_IRQ_LEVEL) |
+ MCF5282_INTC_ICR_IP(UART0_IRQ_PRIORITY);
+ MCF5282_INTC0_IMRL &= ~(MCF5282_INTC_IMRL_INT13 |
+ MCF5282_INTC_IMRL_MASKALL);
+ break;
+
+ case 1:
+ bsp_allocate_interrupt(UART1_IRQ_LEVEL, UART1_IRQ_PRIORITY);
+ MCF5282_INTC0_ICR14 = MCF5282_INTC_ICR_IL(UART1_IRQ_LEVEL) |
+ MCF5282_INTC_ICR_IP(UART1_IRQ_PRIORITY);
+ MCF5282_INTC0_IMRL &= ~(MCF5282_INTC_IMRL_INT14 |
+ MCF5282_INTC_IMRL_MASKALL);
+ break;
+
+ case 2:
+ bsp_allocate_interrupt(UART2_IRQ_LEVEL, UART2_IRQ_PRIORITY);
+ MCF5282_INTC0_ICR15 = MCF5282_INTC_ICR_IL(UART2_IRQ_LEVEL) |
+ MCF5282_INTC_ICR_IP(UART2_IRQ_PRIORITY);
+ MCF5282_INTC0_IMRL &= ~(MCF5282_INTC_IMRL_INT15 |
+ MCF5282_INTC_IMRL_MASKALL);
+ break;
+ }
+ rtems_interrupt_enable(level);
+
+ } /* of chan loop */
+
+
+} /* IntUartInitialise */
+
+
+/***************************************************************************
+ Function : IntUartInterruptWrite
+
+ Description : This writes a single character to the appropriate uart
+ channel. This is either called during an interrupt or in the user's task
+ to initiate a transmit sequence. Calling this routine enables Tx
+ interrupts.
+ ***************************************************************************/
+static ssize_t
+IntUartInterruptWrite (int minor, const char *buf, size_t len)
+{
+ if (len > 0) {
+ /* write out character */
+ MCF5282_UART_UTB(minor) = *buf;
+
+ /* enable tx interrupt */
+ IntUartInfo[minor].uimr |= MCF5282_UART_UIMR_TXRDY;
+ MCF5282_UART_UIMR(minor) = IntUartInfo[minor].uimr;
+ }
+
+ return 0;
+}
+
+/***************************************************************************
+ Function : IntUartInterruptOpen
+
+ Description : This enables interrupts when the tty is opened.
+ ***************************************************************************/
+static int
+IntUartInterruptOpen(int major, int minor, void *arg)
+{
+ struct IntUartInfoStruct *info = &IntUartInfo[minor];
+ int level;
+
+ /*
+ * Enable serial I/O pin assignments
+ */
+ rtems_interrupt_disable(level);
+ switch(minor) {
+ case 0:
+ MCF5282_GPIO_PUAPAR |= MCF5282_GPIO_PUAPAR_PUAPA1|MCF5282_GPIO_PUAPAR_PUAPA0;
+ break;
+ case 1:
+ MCF5282_GPIO_PUAPAR |= MCF5282_GPIO_PUAPAR_PUAPA3|MCF5282_GPIO_PUAPAR_PUAPA2;
+ break;
+ case 2:
+ MCF5282_GPIO_PASPAR =
+ (MCF5282_GPIO_PASPAR
+ & ~(MCF5282_GPIO_PASPAR_PASPA3(3)|MCF5282_GPIO_PASPAR_PASPA2(3)))
+ | (MCF5282_GPIO_PASPAR_PASPA3(2)|MCF5282_GPIO_PASPAR_PASPA2(2));
+ break;
+ }
+ rtems_interrupt_enable(level);
+ /* enable the uart */
+ MCF5282_UART_UCR(minor) = (MCF5282_UART_UCR_TX_ENABLED | MCF5282_UART_UCR_RX_ENABLED);
+
+ /* check to see if interrupts need to be enabled */
+ if ( info->iomode != TERMIOS_POLLED )
+ {
+ /* enable rx interrupts */
+ info->uimr |= MCF5282_UART_UIMR_FFULL;
+ MCF5282_UART_UIMR(minor) = info->uimr;
+ }
+
+ /* check to see if doing hardware flow control */
+ if ( info->hwflow )
+ {
+ /* assert the RTS line */
+ MCF5282_UART_UOP1(minor) = 1;
+ }
+
+ return( 0 );
+}
+
+
+
+/***************************************************************************
+ Function : IntUartInterruptClose
+
+ Description : This disables interrupts when the tty is closed.
+ ***************************************************************************/
+static int
+IntUartInterruptClose(int major, int minor, void *arg)
+{
+ struct IntUartInfoStruct *info = &IntUartInfo[minor];
+
+ /* disable the interrupts and the uart */
+ MCF5282_UART_UIMR(minor) = 0;
+ MCF5282_UART_UCR(minor) = (MCF5282_UART_UCR_TX_DISABLED | MCF5282_UART_UCR_RX_DISABLED);
+
+ /* reset values */
+ info->ttyp = NULL;
+ info->uimr = 0;
+ info->rx_in = 0;
+ info->rx_out = 0;
+
+ return( 0 );
+}
+
+/***************************************************************************
+ Function : IntUartTaskRead
+
+ Description : This reads all available characters from the internal uart
+ and places them into the termios buffer. The rx interrupts will be
+ re-enabled after all data has been read.
+ ***************************************************************************/
+static int
+IntUartTaskRead(int minor)
+{
+ char buffer[RX_BUFFER_SIZE];
+ int count;
+ int rx_in;
+ int index = 0;
+ struct IntUartInfoStruct *info = &IntUartInfo[minor];
+
+ /* determine number of values to copy out */
+ rx_in = info->rx_in;
+ if ( info->rx_out <= rx_in )
+ {
+ count = rx_in - info->rx_out;
+ }
+ else
+ {
+ count = (RX_BUFFER_SIZE - info->rx_out) + rx_in;
+ }
+
+ /* copy data into local buffer from rx buffer */
+ while ( ( index < count ) && ( index < RX_BUFFER_SIZE ) )
+ {
+ /* copy data byte */
+ buffer[index] = info->rx_buffer[info->rx_out];
+ index++;
+
+ /* increment rx buffer values */
+ info->rx_out++;
+ if ( info->rx_out >= RX_BUFFER_SIZE )
+ {
+ info->rx_out = 0;
+ }
+ }
+
+ /* check to see if buffer is not empty */
+ if ( count > 0 )
+ {
+ /* set characters into termios buffer */
+ rtems_termios_enqueue_raw_characters(info->ttyp, buffer, count);
+ }
+
+ return( EOF );
+}
+
+
+
+/***************************************************************************
+ Function : IntUartPollRead
+
+ Description : This reads a character from the internal uart. It returns
+ to the caller without blocking if not character is waiting.
+ ***************************************************************************/
+static int
+IntUartPollRead (int minor)
+{
+ if ( (MCF5282_UART_USR(minor) & MCF5282_UART_USR_RXRDY) == 0 )
+ return(-1);
+
+ return(MCF5282_UART_URB(minor));
+}
+
+
+/***************************************************************************
+ Function : IntUartPollWrite
+
+ Description : This writes out each character in the buffer to the
+ appropriate internal uart channel waiting till each one is sucessfully
+ transmitted.
+ ***************************************************************************/
+static ssize_t
+IntUartPollWrite (int minor, const char *buf, size_t len)
+{
+ size_t retval = len;
+ /* loop over buffer */
+ while ( len-- )
+ {
+ /* block until we can transmit */
+ while ( (MCF5282_UART_USR(minor) & MCF5282_UART_USR_TXRDY) == 0 )
+ continue;
+ /* transmit data byte */
+ MCF5282_UART_UTB(minor) = *buf++;
+ }
+ return retval;
+}
+
+/***************************************************************************
+ Function : console_initialize
+
+ Description : This initialises termios, all uart hardware before
+ registering /dev/tty devices for each channel and the system /dev/console.
+ ***************************************************************************/
+rtems_device_driver console_initialize(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg )
+{
+ rtems_status_code status;
+ int chan;
+
+ /* Set up TERMIOS */
+ rtems_termios_initialize ();
+
+ /* set io modes for the different channels and initialize device */
+ for ( chan = 0; chan < MAX_UART_INFO; chan++ )
+ IntUartInfo[chan].iomode = TERMIOS_IRQ_DRIVEN;
+ IntUartInitialize();
+
+ /* Register the console port */
+ status = rtems_io_register_name ("/dev/console", major, CONSOLE_PORT);
+ if ( status != RTEMS_SUCCESSFUL )
+ {
+ rtems_fatal_error_occurred (status);
+ }
+
+ /* Register the other ports */
+ if ( CONSOLE_PORT != 0 )
+ {
+ status = rtems_io_register_name ("/dev/tty00", major, 0);
+ if ( status != RTEMS_SUCCESSFUL )
+ {
+ rtems_fatal_error_occurred (status);
+ }
+ }
+ if ( CONSOLE_PORT != 1 )
+ {
+ status = rtems_io_register_name ("/dev/tty01", major, 1);
+ if ( status != RTEMS_SUCCESSFUL )
+ {
+ rtems_fatal_error_occurred (status);
+ }
+ }
+ status = rtems_io_register_name ("/dev/tty02", major, 2);
+ if ( status != RTEMS_SUCCESSFUL )
+ {
+ rtems_fatal_error_occurred (status);
+ }
+
+ return(RTEMS_SUCCESSFUL);
+}
+
+/***************************************************************************
+ Function : console_open
+
+ Description : This actually opens the device depending on the minor
+ number set during initialisation. The device specific access routines are
+ passed to termios when the devices is opened depending on whether it is
+ polled or not.
+ ***************************************************************************/
+rtems_device_driver console_open(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg)
+{
+ rtems_status_code status = RTEMS_INVALID_NUMBER;
+ rtems_libio_open_close_args_t *args = (rtems_libio_open_close_args_t *)arg;
+ struct IntUartInfoStruct *info;
+
+ static const rtems_termios_callbacks IntUartPollCallbacks = {
+ NULL, /* firstOpen */
+ NULL, /* lastClose */
+ IntUartPollRead, /* pollRead */
+ IntUartPollWrite, /* write */
+ IntUartSetAttributes, /* setAttributes */
+ NULL, /* stopRemoteTx */
+ NULL, /* startRemoteTx */
+ TERMIOS_POLLED /* mode */
+ };
+ static const rtems_termios_callbacks IntUartIntrCallbacks = {
+ IntUartInterruptOpen, /* firstOpen */
+ IntUartInterruptClose, /* lastClose */
+ NULL, /* pollRead */
+ IntUartInterruptWrite, /* write */
+ IntUartSetAttributes, /* setAttributes */
+ NULL, /* stopRemoteTx */
+ NULL, /* startRemoteTx */
+ TERMIOS_IRQ_DRIVEN /* mode */
+ };
+
+ static const rtems_termios_callbacks IntUartTaskCallbacks = {
+ IntUartInterruptOpen, /* firstOpen */
+ IntUartInterruptClose, /* lastClose */
+ IntUartTaskRead, /* pollRead */
+ IntUartInterruptWrite, /* write */
+ IntUartSetAttributes, /* setAttributes */
+ NULL, /* stopRemoteTx */
+ NULL, /* startRemoteTx */
+ TERMIOS_TASK_DRIVEN /* mode */
+ };
+
+ /* open the port depending on the minor device number */
+ if ( ( minor >= 0 ) && ( minor < MAX_UART_INFO ) )
+ {
+ info = &IntUartInfo[minor];
+ switch ( info->iomode )
+ {
+ case TERMIOS_POLLED:
+ status = rtems_termios_open(major, minor, arg, &IntUartPollCallbacks);
+ break;
+ case TERMIOS_IRQ_DRIVEN:
+ status = rtems_termios_open(major, minor, arg, &IntUartIntrCallbacks);
+ info->ttyp = args->iop->data1;
+ break;
+ case TERMIOS_TASK_DRIVEN:
+ status = rtems_termios_open(major, minor, arg, &IntUartTaskCallbacks);
+ info->ttyp = args->iop->data1;
+ break;
+ }
+ }
+
+ return( status );
+}
+
+/***************************************************************************
+ Function : console_close
+
+ Description : This closes the device via termios
+ ***************************************************************************/
+rtems_device_driver console_close(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg)
+{
+ return(rtems_termios_close (arg));
+}
+
+/******************
+*********************************************************
+ Function : console_read
+
+ Description : Read from the device via termios
+ ***************************************************************************/
+rtems_device_driver console_read(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg)
+{
+ return(rtems_termios_read (arg));
+}
+
+/***************************************************************************
+ Function : console_write
+
+ Description : Write to the device via termios
+ ***************************************************************************/
+rtems_device_driver console_write(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg)
+{
+ return(rtems_termios_write (arg));
+}
+
+/***************************************************************************
+ Function : console_ioctl
+
+ Description : Pass the IOCtl call to termios
+ ***************************************************************************/
+rtems_device_driver console_control(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg)
+{
+ return( rtems_termios_ioctl (arg) );
+}
+