--- /dev/null
+Index: rtems/c/src/lib/libbsp/arm/csb336/console/uart.c
+===================================================================
+--- rtems.orig/c/src/lib/libbsp/arm/csb336/console/uart.c
++++ rtems/c/src/lib/libbsp/arm/csb336/console/uart.c
+@@ -1,262 +1,453 @@
+ /*
+- * console driver for MC9328XML UARTs
++ * Console driver for MC9328XML UARTs.
+ *
+- * This driver uses the shared console driver in
+- * ...../libbsp/shared/console.c
++ * Written Jay Monkman <jtm@lopingdog.com>
++ * Copyright (c) 2005 by Loping Dog Embedded Systems
+ *
+- * If you want the driver to be interrupt driven, you
+- * need to write the ISR, and in the ISR insert the
+- * chars into termios's queue.
++ * The license and distribution terms for this file may be
++ * found in the file LICENSE in this distribution or at
++ * http://www.rtems.com/license
+ *
+- * Copyright (c) 2004 Cogent Computer Systems
+- * Written by Jay Monkman <jtm@lopingdog.com>
+- *
+- * The license and distribution terms for this file may be
+- * found in the file LICENSE in this distribution or at
+- *
+- * http://www.OARcorp.com/rtems/license.html.
+- *
+- *
+- * $Id: uart.c,v 1.1 2004/07/15 06:12:05 jtm Exp $
+-*/
+-#include <bsp.h> /* Must be before libio.h */
++ * $Id:$
++ */
++#include <bsp.h>
+ #include <rtems/libio.h>
+-#include <termios.h>
++#include <libchip/sersupp.h>
++#include <rtems/error.h>
+ #include <rtems/bspIo.h>
+-
+-/* Put the CPU (or UART) specific header file #include here */
++#include <termios.h>
++#include <irq.h>
+ #include <mc9328mxl.h>
+-#include <libchip/serial.h>
+-#include <libchip/sersupp.h>
++
++
++/* Define this to use interrupt driver UART driver */
++#define USE_INTERRUPTS 1
+
+ /* How many serial ports? */
+ #define NUM_DEVS 2
++#define poll_write(c) imx_uart_poll_write_char(0, c)
++#define poll_read() imx_uart_poll_read_char(0)
+
+-int uart_poll_read(int minor);
++static int imx_uart_first_open(int, int, void *);
++static int imx_uart_last_close(int, int, void *);
++static int imx_uart_poll_read(int);
++static int imx_uart_set_attrs(int, const struct termios *);
++static void imx_uart_init(int minor);
++static void imx_uart_set_baud(int, int);
++static int imx_uart_poll_write(int, const char *, int);
++
++#if defined(USE_INTERRUPTS)
++static void imx_uart_tx_isr(rtems_irq_hdl_param);
++static void imx_uart_rx_isr(rtems_irq_hdl_param);
++static void imx_uart_isr_on(const rtems_irq_connect_data *irq);
++static void imx_uart_isr_off(const rtems_irq_connect_data *irq);
++static int imx_uart_isr_is_on(const rtems_irq_connect_data *irq);
++static int imx_uart_intr_write(int, const char *, int);
++#endif
+
+-int dbg_dly;
+
+-/* static function prototypes */
+-static int uart_first_open(int major, int minor, void *arg);
+-static int uart_last_close(int major, int minor, void *arg);
+-static int uart_read(int minor);
+-static int uart_write(int minor, const char *buf, int len);
+-static void uart_init(int minor);
+-static void uart_write_polled(int minor, char c);
+-static int uart_set_attributes(int minor, const struct termios *t);
+-
+-/* These are used by code in console.c */
+-unsigned long Console_Port_Count = NUM_DEVS;
+-console_data Console_Port_Data[NUM_DEVS];
+-
+-/* rtems console uses the following minor number */
+-rtems_device_minor_number Console_Port_Minor = 0;
+-
+-/* Pointers to functions for handling the UART. */
+-console_fns uart_fns =
+-{
+- libchip_serial_default_probe,
+- uart_first_open,
+- uart_last_close,
+- uart_read,
+- uart_write,
+- uart_init,
+- uart_write_polled, /* not used in this driver */
+- uart_set_attributes,
+- FALSE /* TRUE if interrupt driven, FALSE if not. */
++
++/* TERMIOS callbacks */
++#if defined(USE_INTERRUPTS)
++rtems_termios_callbacks imx_uart_cbacks = {
++ .firstOpen = imx_uart_first_open,
++ .lastClose = imx_uart_last_close,
++ .pollRead = NULL,
++ .write = imx_uart_intr_write,
++ .setAttributes = imx_uart_set_attrs,
++ .stopRemoteTx = NULL,
++ .startRemoteTx = NULL,
++ .outputUsesInterrupts = 1,
++};
++#else
++rtems_termios_callbacks imx_uart_cbacks = {
++ .firstOpen = imx_uart_first_open,
++ .lastClose = imx_uart_last_close,
++ .pollRead = imx_uart_poll_read,
++ .write = imx_uart_poll_write,
++ .setAttributes = imx_uart_set_attrs,
++ .stopRemoteTx = NULL,
++ .startRemoteTx = NULL,
++ .outputUsesInterrupts = 0,
+ };
++#endif
+
+-/*
+- * There's one item in array for each UART.
+- *
+- * Some of these fields are marked "NOT USED". They are not used
+- * by console.c, but may be used by drivers in libchip
+- *
+- */
+-console_tbl Console_Port_Tbl[] = {
+- {
+- "/dev/com0", /* sDeviceName */
+- SERIAL_CUSTOM, /* deviceType */
+- &uart_fns, /* pDeviceFns */
+- NULL, /* deviceProbe */
+- NULL, /* pDeviceFlow */
+- 0, /* ulMargin - NOT USED */
+- 0, /* ulHysteresis - NOT USED */
+- NULL, /* pDeviceParams */
+- 0, /* ulCtrlPort1 - NOT USED */
+- 0, /* ulCtrlPort2 - NOT USED */
+- 0, /* ulDataPort - NOT USED */
+- NULL, /* getRegister - NOT USED */
+- NULL, /* setRegister - NOT USED */
+- NULL, /* getData - NOT USED */
+- NULL, /* setData - NOT USED */
+- 0, /* ulClock - NOT USED */
+- 0 /* ulIntVector - NOT USED */
+- },
+- {
+- "/dev/com1", /* sDeviceName */
+- SERIAL_CUSTOM, /* deviceType */
+- &uart_fns, /* pDeviceFns */
+- NULL, /* deviceProbe */
+- NULL, /* pDeviceFlow */
+- 0, /* ulMargin - NOT USED */
+- 0, /* ulHysteresis - NOT USED */
+- NULL, /* pDeviceParams */
+- 0, /* ulCtrlPort1 - NOT USED */
+- 0, /* ulCtrlPort2 - NOT USED */
+- 0, /* ulDataPort - NOT USED */
+- NULL, /* getRegister - NOT USED */
+- NULL, /* setRegister - NOT USED */
+- NULL, /* getData - NOT USED */
+- NULL, /* setData - NOT USED */
+- 0, /* ulClock - NOT USED */
+- 0 /* ulIntVector - NOT USED */
++#if defined(USE_INTERRUPTS)
++static rtems_irq_connect_data imx_uart_tx_isr_data[NUM_DEVS];
++static rtems_irq_connect_data imx_uart_rx_isr_data[NUM_DEVS];
++#endif
++
++typedef struct {
++ int minor;
++ mc9328mxl_uart_regs_t * regs;
++ volatile const char *buf;
++ volatile int len;
++ volatile int idx;
++ void *tty;
++} imx_uart_data_t;
++
++static imx_uart_data_t imx_uart_data[NUM_DEVS];
++
++rtems_device_driver console_initialize(
++ rtems_device_major_number major,
++ rtems_device_minor_number minor,
++ void *arg
++)
++{
++ rtems_status_code status;
++ int i;
++
++ for (i = 0; i < NUM_DEVS; i++) {
++ imx_uart_init(i);
+ }
+-};
+
+-/*********************************************************************/
+-/* Functions called via termios callbacks (i.e. the ones in uart_fns */
+-/*********************************************************************/
+-
+-/*
+- * This is called the first time each device is opened. If the driver
+- * is interrupt driven, you should enable interrupts here. Otherwise,
+- * it's probably safe to do nothing.
+- *
+- * Since micromonitor already set up the UART, we do nothing.
+- */
+-static int uart_first_open(int major, int minor, void *arg)
++ rtems_termios_initialize();
++
++ /* /dev/console and /dev/tty0 are the same */
++ status = rtems_io_register_name("/dev/console", major, 0);
++ if (status != RTEMS_SUCCESSFUL) {
++ rtems_panic("%s:%d Error registering /dev/console :: %d\n",
++ __FUNCTION__, __LINE__, status);
++ }
++
++ status = rtems_io_register_name("/dev/tty0", major, 0);
++ if (status != RTEMS_SUCCESSFUL) {
++ rtems_panic("%s:%d Error registering /dev/tty0 :: %d\n",
++ __FUNCTION__, __LINE__, status);
++ }
++
++ status = rtems_io_register_name("/dev/tty1", major, 1);
++ if (status != RTEMS_SUCCESSFUL) {
++ rtems_panic("%s:%d Error registering /dev/tty1 :: %d\n",
++ __FUNCTION__, __LINE__, status);
++ }
++ return RTEMS_SUCCESSFUL;
++}
++
++rtems_device_driver console_open(
++ rtems_device_major_number major,
++ rtems_device_minor_number minor,
++ void * arg
++)
+ {
+- return 0;
++ rtems_status_code rc;
++
++ if (minor > (NUM_DEVS - 1)) {
++ return RTEMS_INVALID_NUMBER;
++ }
++
++ rc = rtems_termios_open(major, minor, arg, &imx_uart_cbacks);
++
++ return rc;
+ }
+
++rtems_device_driver console_close(
++ rtems_device_major_number major,
++ rtems_device_minor_number minor,
++ void * arg
++)
++{
++ return rtems_termios_close(arg);
++}
+
+-/*
+- * This is called the last time each device is closed. If the driver
+- * is interrupt driven, you should disable interrupts here. Otherwise,
+- * it's probably safe to do nothing.
+- */
+-static int uart_last_close(int major, int minor, void *arg)
++rtems_device_driver console_read(
++ rtems_device_major_number major,
++ rtems_device_minor_number minor,
++ void * arg
++)
+ {
+- return 0;
++ return rtems_termios_read(arg);
+ }
+
++rtems_device_driver console_write(
++ rtems_device_major_number major,
++ rtems_device_minor_number minor,
++ void * arg
++)
++{
++ return rtems_termios_write(arg);
++}
+
+-/*
+- * Read one character from UART.
+- *
+- * Return -1 if there's no data, otherwise return
+- * the character in lowest 8 bits of returned int.
+- */
+-static int uart_read(int minor)
++rtems_device_driver console_control(
++ rtems_device_major_number major,
++ rtems_device_minor_number minor,
++ void * arg
++)
+ {
+- char c;
++ return rtems_termios_ioctl(arg);
++}
++
++static void imx_uart_init(int minor)
++{
++ imx_uart_data[minor].minor = minor;
++ imx_uart_data[minor].buf = NULL;
++ imx_uart_data[minor].len = 0;
++ imx_uart_data[minor].idx = 0;
+
+ if (minor == 0) {
+- if (MC9328MXL_UART1_SR2 & MC9328MXL_UART_SR2_RDR) {
+- c = MC9328MXL_UART1_RXD & MC9328MXL_UART_RXD_CHARMASK;
+- return c;
+- } else {
+- return -1;
+- }
++#if defined(USE_INTERRUPTS)
++ imx_uart_tx_isr_data[minor].name = BSP_INT_UART1_TX;
++ imx_uart_rx_isr_data[minor].name = BSP_INT_UART1_RX;
++#endif
++ imx_uart_data[minor].regs =
++ (mc9328mxl_uart_regs_t *) MC9328MXL_UART1_BASE;
+ } else if (minor == 1) {
+- if (MC9328MXL_UART2_SR2 & MC9328MXL_UART_SR2_RDR) {
+- c = MC9328MXL_UART2_RXD & MC9328MXL_UART_RXD_CHARMASK;
+- return c;
+- } else {
+- return -1;
+- }
++#if defined(USE_INTERRUPTS)
++ imx_uart_tx_isr_data[minor].name = BSP_INT_UART2_TX;
++ imx_uart_rx_isr_data[minor].name = BSP_INT_UART2_RX;
++#endif
++ imx_uart_data[minor].regs =
++ (mc9328mxl_uart_regs_t *) MC9328MXL_UART2_BASE;
+ } else {
+- printk("Unknown console minor number: %d\n", minor);
+- return -1;
++ rtems_panic("%s:%d Unknown UART minor number %d\n",
++ __FUNCTION__, __LINE__, minor);
+ }
+
++#if defined(USE_INTERRUPTS)
++ imx_uart_tx_isr_data[minor].hdl = imx_uart_tx_isr;
++ imx_uart_tx_isr_data[minor].handle = &imx_uart_data[minor];
++ imx_uart_tx_isr_data[minor].on = imx_uart_isr_on;
++ imx_uart_tx_isr_data[minor].off = imx_uart_isr_off;
++ imx_uart_tx_isr_data[minor].isOn = imx_uart_isr_is_on;
++
++ imx_uart_rx_isr_data[minor].hdl = imx_uart_rx_isr;
++ imx_uart_rx_isr_data[minor].handle = &imx_uart_data[minor];
++ imx_uart_rx_isr_data[minor].on = imx_uart_isr_on;
++ imx_uart_rx_isr_data[minor].off = imx_uart_isr_off;
++ imx_uart_rx_isr_data[minor].isOn = imx_uart_isr_is_on;
++#endif
++
++ imx_uart_data[minor].regs->cr1 = (
++ MC9328MXL_UART_CR1_UARTCLKEN |
++ MC9328MXL_UART_CR1_UARTEN);
++
++ imx_uart_data[minor].regs->cr2 = (
++ MC9328MXL_UART_CR2_IRTS |
++ MC9328MXL_UART_CR2_WS |
++ MC9328MXL_UART_CR2_TXEN |
++ MC9328MXL_UART_CR2_RXEN |
++ MC9328MXL_UART_CR2_SRST);
++
++ imx_uart_data[minor].regs->cr3 = 0;
++
++ imx_uart_data[minor].regs->cr4 = 0;
++
++ imx_uart_data[minor].regs->fcr = (
++ MC9328MXL_UART_FCR_TXTL(32) |
++ MC9328MXL_UART_FCR_RFDIV_1 |
++ MC9328MXL_UART_FCR_RXTL(1));
++
++ imx_uart_set_baud(minor, 38400);
++
+ }
+
++static int imx_uart_first_open(int major, int minor, void *arg)
++{
++ rtems_libio_open_close_args_t *args = arg;
+
+-/*
+- * Write buffer to UART
+- *
+- * return 1 on success, -1 on error
+- */
+-static int uart_write(int minor, const char *buf, int len)
++ imx_uart_data[minor].tty = args->iop->data1;
++
++#if defined(USE_INTERRUPTS)
++ BSP_install_rtems_irq_handler(&imx_uart_tx_isr_data[minor]);
++ BSP_install_rtems_irq_handler(&imx_uart_rx_isr_data[minor]);
++
++ imx_uart_data[minor].regs->cr1 |= MC9328MXL_UART_CR1_RRDYEN;
++#endif
++
++ return 0;
++}
++
++static int imx_uart_last_close(int major, int minor, void *arg)
+ {
+- int i;
++#if defined(USE_INTERRUPTS)
++ BSP_remove_rtems_irq_handler(&imx_uart_tx_isr_data[minor]);
++ BSP_remove_rtems_irq_handler(&imx_uart_rx_isr_data[minor]);
++#endif
+
+- if (minor == 0) {
+- for (i = 0; i < len; i++) {
+- /* Wait for fifo to have room */
+- while(!(MC9328MXL_UART1_SR2 & MC9328MXL_UART_SR2_TXDC)) {
+- continue;
+- }
+-
+- MC9328MXL_UART1_TXD = (char) buf[i];
+- }
+- } else if (minor == 1) {
+- for (i = 0; i < len; i++) {
+- /* Wait for fifo to have room */
+- while(!(MC9328MXL_UART2_SR2 & MC9328MXL_UART_SR2_TXDC)) {
+- continue;
+- }
+-
+- MC9328MXL_UART2_TXD = (char) buf[i];
+- }
++ return 0;
++}
++
++static int imx_uart_poll_read(int minor)
++{
++ if (imx_uart_data[minor].regs->sr2 & MC9328MXL_UART_SR2_RDR) {
++ return imx_uart_data[minor].regs->rxd & 0xff;
+ } else {
+- printk("Unknown console minor number: %d\n", minor);
+ return -1;
+ }
+-
+- return 1;
+ }
+
+
+-/* Set up the UART. */
+-static void uart_init(int minor)
++static int imx_uart_poll_write(int minor, const char *buf, int len)
+ {
+- /* leave the debug sio port as setup by umon */
++ int i;
++ for (i = 0; i < len; i++) {
++ /* Wait for there to be room in the fifo */
++ while (!(imx_uart_data[minor].regs->sr2 & MC9328MXL_UART_SR2_TXDC)) {
++ continue;
++ }
++
++ imx_uart_data[minor].regs->txd = buf[i];
++ }
++ return 1;
++
+ }
+
+-/* I'm not sure this is needed for the shared console driver. */
+-static void uart_write_polled(int minor, char c)
++#if defined(USE_INTERRUPTS)
++static int imx_uart_intr_write(int minor, const char *buf, int len)
+ {
+- uart_write(minor, &c, 1);
++ imx_uart_data[minor].buf = buf;
++ imx_uart_data[minor].len = len;
++ imx_uart_data[minor].idx = 0;
++
++ imx_uart_data[minor].regs->cr1 |= MC9328MXL_UART_CR1_TXMPTYEN;
++
++ return 1;
+ }
++#endif
++
+
+ /* This is for setting baud rate, bits, etc. */
+-static int uart_set_attributes(int minor, const struct termios *t)
++static int imx_uart_set_attrs(int minor, const struct termios *t)
+ {
++ int baud;
++
++ baud = termios_baud_to_number(t->c_cflag & CBAUD);
++ imx_uart_set_baud(minor, baud);
++
+ return 0;
+ }
+
+-/***********************************************************************/
++#if defined(USE_INTERRUPTS)
++static void imx_uart_isr_on(const rtems_irq_connect_data *irq)
++{
++ MC9328MXL_AITC_INTENNUM = irq->name;
++}
++static void imx_uart_isr_off(const rtems_irq_connect_data *irq)
++{
++ MC9328MXL_AITC_INTDISNUM = irq->name;
++}
++static int imx_uart_isr_is_on(const rtems_irq_connect_data *irq)
++{
++ int irq_num = (int)irq->name;
++ if (irq_num < 32) {
++ return MC9328MXL_AITC_INTENABLEL & (1 << irq_num);
++ } else {
++ return MC9328MXL_AITC_INTENABLEH & (1 << (irq_num - 32));
++ }
++}
++
++static void imx_uart_rx_isr(rtems_irq_hdl_param param)
++{
++ imx_uart_data_t *uart_data = param;
++ char buf[32];
++ int i=0;
++
++ while (uart_data->regs->sr2 & MC9328MXL_UART_SR2_RDR) {
++ buf[i] = uart_data->regs->rxd & 0xff;
++ i++;
++ }
++
++ rtems_termios_enqueue_raw_characters(uart_data->tty, buf, i);
++}
++
++static void imx_uart_tx_isr(rtems_irq_hdl_param param)
++{
++ imx_uart_data_t *uart_data = param;
++ int len;
++ int minor = uart_data->minor;
++
++
++ if (uart_data->idx < uart_data->len) {
++ while ( (uart_data->regs->sr1 & MC9328MXL_UART_SR1_TRDY) &&
++ (uart_data->idx < uart_data->len)) {
++ uart_data->regs->txd = uart_data->buf[uart_data->idx];
++ uart_data->idx++;
++ }
++ } else {
++ len = uart_data->len;
++ uart_data->len = 0;
++ imx_uart_data[minor].regs->cr1 &= ~MC9328MXL_UART_CR1_TXMPTYEN;
++ rtems_termios_dequeue_characters(uart_data->tty, len);
++ }
++}
++#endif
++
+ /*
+- * The following functions are not used by TERMIOS, but other RTEMS
+- * functions use them instead.
++ * Set the UART's baud rate. The calculation is:
++ * (baud * 16) / ref_freq = num/demom
++ *
++ * ref_freq = perclk1 / RFDIV[2:0]
++ * BIR = num - 1
++ * BMR = demom - 1
++ *
++ * Setting 'num' to 16 yields this equation:
++ * demom = ref_freq / baud
+ */
+-/***********************************************************************/
+-/*
+- * Read from UART. This is used in the exit code, and can't
+- * rely on interrupts.
+-*/
+-int uart_poll_read(int minor)
++static void imx_uart_set_baud(int minor, int baud)
+ {
+- return uart_read(minor);
++ unsigned int perclk1;
++ unsigned int denom;
++ unsigned int ref_freq = 0;
++ uint32_t fcr;
++
++ perclk1 = get_perclk1_freq();
++ fcr = imx_uart_data[minor].regs->fcr;
++
++ switch(fcr & MC9328MXL_UART_FCR_RFDIV_MASK) {
++ case MC9328MXL_UART_FCR_RFDIV_1: ref_freq = perclk1/1; break;
++ case MC9328MXL_UART_FCR_RFDIV_2: ref_freq = perclk1/2; break;
++ case MC9328MXL_UART_FCR_RFDIV_3: ref_freq = perclk1/3; break;
++ case MC9328MXL_UART_FCR_RFDIV_4: ref_freq = perclk1/4; break;
++ case MC9328MXL_UART_FCR_RFDIV_5: ref_freq = perclk1/5; break;
++ case MC9328MXL_UART_FCR_RFDIV_6: ref_freq = perclk1/6; break;
++ case MC9328MXL_UART_FCR_RFDIV_7: ref_freq = perclk1/7; break;
++ default:
++ rtems_panic("%s:%d Unknown RFDIV: 0x%x",
++ __FUNCTION__, __LINE__,
++ fcr & MC9328MXL_UART_FCR_RFDIV_MASK);
++ break;
++ }
++
++ denom = ref_freq / baud;
++
++ imx_uart_data[minor].regs->bir = 0xf;
++ imx_uart_data[minor].regs->bmr = denom;
+ }
+
+
+ /*
+- * Write a character to the console. This is used by printk() and
+- * maybe other low level functions. It should not use interrupts or any
+- * RTEMS system calls. It needs to be very simple
++ * Polled, non-blocking read from UART
++ */
++int imx_uart_poll_read_char(int minor)
++{
++ return imx_uart_poll_read(minor);
++}
++
++/*
++ * Polled, blocking write from UART
+ */
+-static void _BSP_put_char( char c ) {
+- uart_write_polled(0, c);
++void imx_uart_poll_write_char(int minor, char c)
++{
++ imx_uart_poll_write(minor, &c, 1);
++}
++
++/*
++ * Functions for printk() and friends.
++ */
++void _BSP_output_char(char c)
++{
++ poll_write(c);
+ if (c == '\n') {
+- uart_write_polled(0, '\r');
++ poll_write('\r');
+ }
+ }
++BSP_output_char_function_type BSP_output_char = _BSP_output_char;
+
+-BSP_output_char_function_type BSP_output_char = _BSP_put_char;
+
++char _BSP_poll_char()
++{
++ return poll_read();
++}
++BSP_polling_getchar_function_type BSP_poll_char = _BSP_poll_char;
+
+
+Index: rtems/c/src/lib/libbsp/arm/csb336/Makefile.am
+===================================================================
+--- rtems.orig/c/src/lib/libbsp/arm/csb336/Makefile.am
++++ rtems/c/src/lib/libbsp/arm/csb336/Makefile.am
+@@ -35,7 +35,7 @@ startup_rel_CPPFLAGS = $(AM_CPPFLAGS)
+ startup_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
+
+ noinst_PROGRAMS += console.rel
+-console_rel_SOURCES = console/uart.c ../../shared/console.c
++console_rel_SOURCES = console/uart.c
+ console_rel_CPPFLAGS = $(AM_CPPFLAGS)
+ console_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
+