summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/powerpc/gen5200/console
diff options
context:
space:
mode:
authorRalf Corsepius <ralf.corsepius@rtems.org>2005-12-31 05:09:26 +0000
committerRalf Corsepius <ralf.corsepius@rtems.org>2005-12-31 05:09:26 +0000
commitca680bc5890abe0d6bfe7eb4a40a0229f1b6bd36 (patch)
tree805a5ddce1250235d6133376ddabb5543eb2cf82 /c/src/lib/libbsp/powerpc/gen5200/console
parentAdd BuildRoot. (diff)
downloadrtems-ca680bc5890abe0d6bfe7eb4a40a0229f1b6bd36.tar.bz2
New (CVS import Thomas Doerfler <Thomas.Doerfler@embedded-brains.de>'s
submission).
Diffstat (limited to 'c/src/lib/libbsp/powerpc/gen5200/console')
-rw-r--r--c/src/lib/libbsp/powerpc/gen5200/console/console.c851
1 files changed, 851 insertions, 0 deletions
diff --git a/c/src/lib/libbsp/powerpc/gen5200/console/console.c b/c/src/lib/libbsp/powerpc/gen5200/console/console.c
new file mode 100644
index 0000000000..7fc4e3b1a2
--- /dev/null
+++ b/c/src/lib/libbsp/powerpc/gen5200/console/console.c
@@ -0,0 +1,851 @@
+/*===============================================================*\
+| Project: RTEMS generic MPC5200 BSP |
++-----------------------------------------------------------------+
+| File: console.c
++-----------------------------------------------------------------+
+| Partially based on the code references which are named below. |
+| Adaptions, modifications, enhancements and any recent parts of |
+| the code are: |
+| Copyright (c) 2005 |
+| Embedded Brains GmbH |
+| Obere Lagerstr. 30 |
+| D-82178 Puchheim |
+| Germany |
+| rtems@embedded-brains.de |
++-----------------------------------------------------------------+
+| 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/LICENSE. |
+| |
++-----------------------------------------------------------------+
+| this file contains the console driver functions |
++-----------------------------------------------------------------+
+| date history ID |
+| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
+| 01.12.05 creation doe |
+|*****************************************************************|
+|*CVS information: |
+|*(the following information is created automatically, |
+|*do not edit here) |
+|*****************************************************************|
+|* $Log$
+|* Revision 1.11 2005/12/09 08:57:03 thomas
+|* added/modifed file headers
+|*
+ *
+|*****************************************************************|
+\*===============================================================*/
+/***********************************************************************/
+/* */
+/* Module: console.c */
+/* Date: 07/17/2003 */
+/* Purpose: RTEMS MPC5x00 console driver */
+/* */
+/*---------------------------------------------------------------------*/
+/* */
+/* Description: */
+/* */
+/* The PSCs of mpc5200 are assigned as follows */
+/* */
+/* Channel Device Minor Note */
+/* PSC1 /dev/tty0 0 */
+/* PSC2 /dev/tty1 1 */
+/* PSC3 /dev/tty2 2 */
+/* */
+/*---------------------------------------------------------------------*/
+/* */
+/* Code */
+/* References: Serial driver for MPC8260ads */
+/* Module: console-generic.c */
+/* Project: RTEMS 4.6.0pre1 / MPC8260ads BSP */
+/* Version 1.3 */
+/* Date: 2002/11/04 */
+/* */
+/* Author(s) / Copyright(s): */
+/* */
+/* Author: Jay Monkman (jmonkman@frasca.com) */
+/* Copyright (C) 1998 by Frasca International, Inc. */
+/* */
+/* Derived from c/src/lib/libbsp/m68k/gen360/console/console.c */
+/* written by: */
+/* W. Eric Norum */
+/* Saskatchewan Accelerator Laboratory */
+/* University of Saskatchewan */
+/* Saskatoon, Saskatchewan, CANADA */
+/* eric@skatter.usask.ca */
+/* */
+/* COPYRIGHT (c) 1989-1998. */
+/* On-Line Applications Research Corporation (OAR). */
+/* */
+/* Modifications by Darlene Stewart <Darlene.Stewart@iit.nrc.ca> */
+/* and Charles-Antoine Gauthier <charles.gauthier@iit.nrc.ca> */
+/* Copyright (c) 1999, National Research Council of Canada */
+/* */
+/* Modifications by Andy Dachs <a.dachs@sstl.co.uk> to add MPC8260 */
+/* support. */
+/* Copyright (c) 2001, Surrey Satellite Technology Ltd */
+/* */
+/* 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. */
+/* */
+/*---------------------------------------------------------------------*/
+/* */
+/* Partially based on the code references which are named above. */
+/* Adaptions, modifications, enhancements and any recent parts of */
+/* the code are under the right of */
+/* */
+/* IPR Engineering, Dachauer Straße 38, D-80335 München */
+/* Copyright(C) 2003 */
+/* */
+/*---------------------------------------------------------------------*/
+/* */
+/* IPR Engineering makes no representation or warranties with */
+/* respect to the performance of this computer program, and */
+/* specifically disclaims any responsibility for any damages, */
+/* special or consequential, connected with the use of this program. */
+/* */
+/*---------------------------------------------------------------------*/
+/* */
+/* Version history: 1.0 */
+/* */
+/***********************************************************************/
+
+#include <rtems.h>
+#include "../include/mpc5200.h"
+#include "../include/bsp.h"
+#include "../irq/irq.h"
+
+#include <rtems/bspIo.h>
+#include <rtems/libio.h>
+#include <string.h>
+
+
+#define NUM_PORTS MPC5200_PSC_NO
+
+#define PSC1_MINOR 0
+#define PSC2_MINOR 1
+#define PSC3_MINOR 2
+#define PSC4_MINOR 3
+#define PSC5_MINOR 4
+#define PSC6_MINOR 5
+
+uint32_t mpc5200_uart_avail_mask = GEN5200_UART_AVAIL_MASK;
+
+uint8_t psc_minor_to_irqname[NUM_PORTS] =
+ {BSP_SIU_IRQ_PSC1,
+ BSP_SIU_IRQ_PSC2,
+ BSP_SIU_IRQ_PSC3,
+ BSP_SIU_IRQ_PSC4,
+ BSP_SIU_IRQ_PSC5,
+ BSP_SIU_IRQ_PSC6};
+static int mpc5200_psc_irqname_to_minor(int name)
+{
+ int minor;
+ uint8_t *chrptr;
+
+ chrptr = memchr(psc_minor_to_irqname,
+ name,
+ sizeof(psc_minor_to_irqname));
+ if (chrptr != NULL) {
+ minor = chrptr - psc_minor_to_irqname;
+ }
+ else {
+ minor = -1;
+ }
+ return minor;
+}
+
+static void A_BSP_output_char(char c);
+BSP_output_char_function_type BSP_output_char = A_BSP_output_char;
+
+/* Used to handle premature outputs of printk */
+uint32_t console_initialized = FALSE;
+
+/* per channel info structure */
+struct per_channel_info
+ {
+ uint16_t shadow_imr;
+ uint8_t shadow_mode1;
+ uint8_t shadow_mode2;
+ int cur_tx_len;
+ int rx_interrupts;
+ int tx_interrupts;
+ int rx_characters;
+ int tx_characters;
+ int breaks_detected;
+ int framing_errors;
+ int parity_errors;
+ int overrun_errors;
+ };
+
+/* Used to handle more than one channel */
+struct per_channel_info channel_info[NUM_PORTS];
+
+ /*
+ * XXX: there are only 6 PSCs, but PSC6 has an extra register gap
+ * from PSC5, therefore we instantiate seven(!) PSC register sets
+ */
+uint8_t psc_minor_to_regset[MPC5200_PSC_NO] = {0,1,2,3,4,6};
+
+/* Used to track termios private data for callbacks */
+struct rtems_termios_tty *ttyp[NUM_PORTS];
+
+int mpc5200_psc_setAttributes(int minor, const struct termios *t)
+ {
+ int baud;
+ uint8_t csize=0, cstopb, parenb, parodd;
+ struct mpc5200_psc *psc =
+ (struct mpc5200_psc *)(&mpc5200.psc[psc_minor_to_regset[minor]]);
+
+ /* Baud rate */
+ switch(t->c_cflag & CBAUD)
+ {
+ default: baud = -1; break;
+ case B50: baud = 50; break;
+ case B75: baud = 75; break;
+ case B110: baud = 110; break;
+ case B134: baud = 134; break;
+ case B150: baud = 150; break;
+ case B200: baud = 200; break;
+ case B300: baud = 300; break;
+ case B600: baud = 600; break;
+ case B1200: baud = 1200; break;
+ case B1800: baud = 1800; break;
+ case B2400: baud = 2400; break;
+ case B4800: baud = 4800; break;
+ case B9600: baud = 9600; break;
+ case B19200: baud = 19200; break;
+ case B38400: baud = 38400; break;
+ case B57600: baud = 57600; break;
+ case B115200: baud = 115200; break;
+ case B230400: baud = 230400; break;
+ case B460800: baud = 460800; break;
+ }
+
+ if(baud > 0)
+ {
+
+ /*
+ * Calculate baud rate
+ */
+ baud = IPB_CLOCK / (baud * 32);
+
+ }
+
+ /* Number of data bits */
+ switch ( t->c_cflag & CSIZE )
+ {
+ case CS5: csize = 0x00; break;
+ case CS6: csize = 0x01; break;
+ case CS7: csize = 0x02; break;
+ case CS8: csize = 0x03; break;
+ }
+
+ /* Stop bits */
+ if(csize == 0)
+ {
+
+ if(t->c_cflag & CSTOPB)
+ cstopb = 0x0F; /* Two stop bits */
+ else
+ cstopb = 0x00; /* One stop bit */
+
+ }
+ else
+ {
+
+ if(t->c_cflag & CSTOPB)
+ cstopb = 0x0F; /* Two stop bits */
+ else
+ cstopb = 0x07; /* One stop bit */
+
+ }
+
+ /* Parity */
+ if (t->c_cflag & PARENB)
+ parenb = 0x00; /* Parity enabled on Tx and Rx */
+ else
+ parenb = 0x10; /* No parity on Tx and Rx */
+
+ if (t->c_cflag & PARODD)
+ parodd = 0x04; /* Odd parity */
+ else
+ parodd = 0x00;
+
+ /*
+ * Set upper timer counter
+ */
+ psc->ctur = (uint16_t)(baud >> 16);
+
+ /*
+ * Set lower timer counter
+ */
+ psc->ctlr = (uint16_t)(baud & 0x0000FFFF);
+
+ /*
+ * Reset mode pointer
+ */
+ psc->cr = ((1 << 4) << 8);
+
+ /*
+ * Set mode1 register
+ */
+ channel_info[minor].shadow_mode1 &= ~(0x1F);
+ psc->mr = channel_info[minor].shadow_mode1 | (csize | parenb | parodd);
+
+ /*
+ * Set mode2 register
+ */
+ channel_info[minor].shadow_mode2 &= ~(0x0F);
+ psc->mr = channel_info[minor].shadow_mode2 | cstopb;
+
+ return 0;
+
+ }
+
+
+int mpc5200_uart_setAttributes(int minor, const struct termios *t)
+ {
+
+
+ /*
+ * Check that port number is valid
+ */
+ if( (minor < PSC1_MINOR) || (minor > NUM_PORTS-1) )
+ return 0;
+
+ return mpc5200_psc_setAttributes(minor, t);
+
+ }
+
+
+#ifdef UARTS_USE_TERMIOS_INT
+/*
+ * Interrupt handlers
+ */
+static void mpc5200_psc_interrupt_handler(rtems_irq_hdl_param handle)
+ {
+ unsigned char c;
+ uint16_t isr;
+ int nb_overflow;
+ int minor = (int)handle;
+ struct mpc5200_psc *psc =
+ (struct mpc5200_psc *)(&mpc5200.psc[psc_minor_to_regset[minor]]);
+
+ /*
+ * get content of psc interrupt status
+ */
+ isr = psc->isr_imr;
+
+ /*
+ * Character received?
+ */
+ if(isr & ISR_RX_RDY_FULL)
+ {
+
+ channel_info[minor].rx_interrupts++;
+
+
+#ifndef SINGLE_CHAR_MODE
+ while(psc->rfnum)
+ {
+#endif
+
+ /*
+ * get the character
+ */
+ c = (psc->rb_tb >> 24);
+
+ nb_overflow = rtems_termios_enqueue_raw_characters((void *)ttyp[minor], (char *)&c, (int)1);
+
+ channel_info[minor].rx_characters++;
+
+#ifndef SINGLE_CHAR_MODE
+ }
+#endif
+
+ }
+
+ /*
+ * Character transmitted ?
+ */
+ if(isr & ISR_TX_RDY & channel_info[minor].shadow_imr)
+ {
+
+ channel_info[minor].tx_interrupts++;
+
+ /*
+ * mask interrupt
+ */
+ psc->isr_imr = channel_info[minor].shadow_imr &= ~(IMR_TX_RDY);
+
+#ifndef SINGLE_CHAR_MODE
+ rtems_termios_dequeue_characters((void *)ttyp[minor], channel_info[minor].cur_tx_len);
+
+ channel_info[minor].tx_characters += channel_info[minor].cur_tx_len;
+#else
+ rtems_termios_dequeue_characters((void *)ttyp[minor], (int)1);
+
+ channel_info[minor].tx_characters++;
+#endif
+
+ }
+
+ if(isr & ISR_ERROR)
+ {
+
+ if(isr & ISR_RB)
+ channel_info[minor].breaks_detected++;
+
+ if(isr & ISR_FE)
+ channel_info[minor].framing_errors++;
+
+ if(isr & ISR_PE)
+ channel_info[minor].parity_errors++;
+
+ if(isr & ISR_PE)
+ channel_info[minor].overrun_errors++;
+
+ /*
+ * Reset error status
+ */
+ psc->cr = ((4 << 4) << 8);
+
+ }
+
+ }
+
+void mpc5200_psc_enable(const rtems_irq_connect_data* ptr) {
+ struct mpc5200_psc *psc;
+ int minor = mpc5200_psc_irqname_to_minor(ptr->name);
+
+ if (minor >= 0) {
+ psc = (struct mpc5200_psc *)(&mpc5200.psc[psc_minor_to_regset[minor]]);
+ psc->isr_imr = channel_info[minor].shadow_imr |=
+ (IMR_RX_RDY_FULL | IMR_TX_RDY);
+ }
+}
+
+
+void mpc5200_psc_disable(const rtems_irq_connect_data* ptr) {
+ struct mpc5200_psc *psc;
+ int minor = mpc5200_psc_irqname_to_minor(ptr->name);
+
+ if (minor >= 0) {
+ psc = (struct mpc5200_psc *)(&mpc5200.psc[psc_minor_to_regset[minor]]);
+ psc->isr_imr = channel_info[minor].shadow_imr &=
+ ~(IMR_RX_RDY_FULL | IMR_TX_RDY);
+ }
+}
+
+
+int mpc5200_psc_isOn(const rtems_irq_connect_data* ptr) {
+ struct mpc5200_psc *psc;
+ int minor = mpc5200_psc_irqname_to_minor(ptr->name);
+
+ if (minor >= 0) {
+ psc = (struct mpc5200_psc *)(&mpc5200.psc[psc_minor_to_regset[minor]]);
+ return ((psc->isr_imr & IMR_RX_RDY_FULL) & (psc->isr_imr & IMR_TX_RDY));
+ }
+ else {
+ return FALSE;
+ }
+}
+
+
+static rtems_irq_connect_data consoleIrqData;
+#endif
+
+void mpc5200_uart_psc_initialize(int minor) {
+ uint32_t baud_divider;
+ struct mpc5200_psc *psc =
+ (struct mpc5200_psc *)(&mpc5200.psc[psc_minor_to_regset[minor]]);
+
+ /*
+ * Check that minor number is valid
+ */
+ if((minor < PSC1_MINOR) || (minor >= (PSC1_MINOR + NUM_PORTS)))
+ return;
+
+ /*
+ * Clear per channel info
+ */
+ memset((void *)&channel_info[minor], 0, sizeof(struct per_channel_info));
+
+
+ /*
+ * Reset receiver and transmitter
+ */
+ psc->cr = ((2 << 4) << 8);
+ psc->cr = ((3 << 4) << 8);
+
+ /*
+ * Reset mode pointer
+ */
+ psc->cr = ((1 << 4) << 8);
+
+ /*
+ * Set clock select register
+ */
+ psc->sr_csr = 0;
+
+ /*
+ * Set mode1 register
+ */
+ psc->mr = channel_info[minor].shadow_mode1 = 0x33; /* 8Bit / no parity */
+
+ /*
+ * Set mode2 register
+ */
+ psc->mr = channel_info[minor].shadow_mode2 = 7; /* 1 stop bit */
+
+ /*
+ * Set rx FIFO alarm
+ */
+ psc->rfalarm = RX_FIFO_SIZE - 1;
+
+ /*
+ * Set tx FIFO alarm
+ */
+ psc->tfalarm = 1;
+
+ baud_divider = IPB_CLOCK / (9600 * 32);
+ /*
+ * Set upper timer counter
+ */
+ psc->ctur = baud_divider >> 16;
+
+
+ /*
+ * Set lower timer counter
+ */
+
+ psc->ctlr = baud_divider & 0x0000ffff;
+
+ /*
+ * Disable Frame mode / set granularity 0
+ */
+ psc->tfcntl = 0;
+
+#ifdef UARTS_USE_TERMIOS_INT
+ /*
+ * Tie interrupt dependent routines
+ */
+ consoleIrqData.on = mpc5200_psc_enable;
+ consoleIrqData.off = mpc5200_psc_disable;
+ consoleIrqData.isOn = mpc5200_psc_isOn;
+ consoleIrqData.handle = (rtems_irq_hdl_param)minor;
+ consoleIrqData.hdl = (rtems_irq_hdl)mpc5200_psc_interrupt_handler;
+
+ /*
+ * Tie interrupt handler
+ */
+ consoleIrqData.name = psc_minor_to_irqname[minor];
+
+ /*
+ * Install rtems irq handler
+ */
+ if(!BSP_install_rtems_irq_handler (&consoleIrqData))
+ {
+
+ printk("Unable to connect PSC Irq handler\n");
+ rtems_fatal_error_occurred(1);
+
+ }
+#endif
+
+ /*
+ * Reset rx fifo errors Error/UF/OF
+ */
+ psc->rfstat |= 0x70;
+
+ /*
+ * Reset tx fifo errors Error/UF/OF
+ */
+ psc->tfstat |= 0x70;
+
+#ifdef UARTS_USE_TERMIOS_INT
+ /*
+ * Unmask receive interrupt
+ */
+ psc->isr_imr = channel_info[minor].shadow_imr = IMR_RX_RDY_FULL;
+#endif
+
+ /*
+ * Enable receiver
+ */
+ psc->cr = ((1 << 0) << 8);
+
+ /*
+ * Enable transmitter
+ */
+ psc->cr = ((1 << 2) << 8);
+
+ }
+
+
+int mpc5200_uart_pollRead(int minor)
+ {
+ unsigned char c;
+ struct mpc5200_psc *psc =
+ (struct mpc5200_psc *)(&mpc5200.psc[psc_minor_to_regset[minor]]);
+
+ if(psc->sr_csr & (1 << 8))
+ c = (psc->rb_tb >> 24);
+ else
+ return -1;
+
+ return c;
+
+ }
+
+
+int mpc5200_uart_pollWrite(int minor, const char *buf, int len)
+ {
+ const char *tmp_buf = buf;
+ struct mpc5200_psc *psc =
+ (struct mpc5200_psc *)(&mpc5200.psc[psc_minor_to_regset[minor]]);
+
+ while(len--)
+ {
+
+ while(!(psc->sr_csr & (1 << 11)))
+ continue;
+
+ /*rtems_cache_flush_multiple_data_lines( (void *)buf, 1);*/
+
+ psc->rb_tb = (*tmp_buf << 24);
+
+ tmp_buf++;
+
+ }
+
+ return 0;
+
+ }
+
+
+int mpc5200_uart_write(int minor, const char *buf, int len)
+ {
+ int frame_len = len;
+ const char *frame_buf = buf;
+ struct mpc5200_psc *psc =
+ (struct mpc5200_psc *)(&mpc5200.psc[psc_minor_to_regset[minor]]);
+
+ /*
+ * Check tx fifo space
+ */
+ if(len > (TX_FIFO_SIZE - psc->tfnum))
+ frame_len = TX_FIFO_SIZE - psc->tfnum;
+
+#ifndef SINGLE_CHAR_MODE
+ channel_info[minor].cur_tx_len = frame_len;
+#else
+ frame_len = 1;
+#endif
+
+ /*rtems_cache_flush_multiple_data_lines( (void *)frame_buf, frame_len);*/
+
+ while(frame_len--)
+ /* perform byte write to avoid extra NUL characters */
+ (* (volatile char *)&(psc->rb_tb)) = *frame_buf++;
+
+ /*
+ * unmask interrupt
+ */
+ psc->isr_imr = channel_info[minor].shadow_imr |= IMR_TX_RDY;
+
+ return 0;
+
+ }
+
+/*
+ * Print functions prototyped in bspIo.h
+ */
+static void A_BSP_output_char( char c )
+ {
+ char cr = '\r';
+
+
+ if(console_initialized == TRUE)
+ {
+
+#define PRINTK_WRITE mpc5200_uart_pollWrite
+
+ PRINTK_WRITE(PRINTK_MINOR, &c, 1 );
+
+ if( c == '\n' )
+ PRINTK_WRITE( PRINTK_MINOR, &cr, 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;
+ char dev_name[] = "/dev/ttyx";
+ /*
+ * Always use and set up TERMIOS
+ */
+ console_minor = PSC1_MINOR;
+ rtems_termios_initialize();
+
+ for (console_minor = PSC1_MINOR;
+ console_minor < PSC1_MINOR + NUM_PORTS;
+ console_minor++) {
+ /*
+ * check, whether UART is available for this board
+ */
+ if (0 != ((1 << console_minor) & (mpc5200_uart_avail_mask))) {
+ /*
+ * Do device-specific initialization and registration for Motorola IceCube
+ */
+ mpc5200_uart_psc_initialize(console_minor); /* /dev/tty0 */
+ dev_name[8] = '0' + console_minor - PSC1_MINOR;
+ status = rtems_io_register_name (dev_name, major, console_minor);
+
+ if(status != RTEMS_SUCCESSFUL)
+ rtems_fatal_error_occurred(status);
+ }
+ }
+ /* Now register the RTEMS console */
+ status = rtems_io_register_name ("/dev/console", major, PSC1_MINOR);
+
+ if(status != RTEMS_SUCCESSFUL)
+ rtems_fatal_error_occurred (status);
+
+ console_initialized = TRUE;
+ return RTEMS_SUCCESSFUL;
+
+ }
+
+
+/*
+ * Open the device
+ */
+rtems_device_driver console_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+ {
+#ifdef UARTS_USE_TERMIOS_INT
+ rtems_libio_open_close_args_t *args = arg;
+#endif
+ rtems_status_code sc;
+
+#ifdef UARTS_USE_TERMIOS_INT
+ static const rtems_termios_callbacks intrCallbacks =
+ {
+ NULL, /* firstOpen */
+ NULL, /* lastClose */
+ NULL, /* pollRead */
+ mpc5200_uart_write, /* write */
+ mpc5200_uart_setAttributes, /* setAttributes */
+ NULL,
+ NULL,
+ 1 /* outputUsesInterrupts */
+ };
+#else
+ static const rtems_termios_callbacks pollCallbacks =
+ {
+ NULL, /* firstOpen */
+ NULL, /* lastClose */
+ mpc5200_uart_pollRead, /* pollRead */
+ mpc5200_uart_pollWrite, /* write */
+ mpc5200_uart_setAttributes, /* setAttributes */
+ NULL,
+ NULL,
+ 0 /* output don't use Interrupts */
+ };
+#endif
+
+ if(minor > NUM_PORTS - 1)
+ return RTEMS_INVALID_NUMBER;
+
+#ifdef UARTS_USE_TERMIOS_INT
+ sc = rtems_termios_open( major, minor, arg, &intrCallbacks );
+ ttyp[minor] = args->iop->data1; /* Keep cookie returned by termios_open */
+#else /* RTEMS polled I/O with termios */
+ sc = rtems_termios_open( major, minor, arg, &pollCallbacks );
+#endif
+
+ return sc;
+
+ }
+
+
+/*
+ * Close the device
+ */
+rtems_device_driver console_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+ {
+
+ if ( minor > NUM_PORTS-1 )
+ return RTEMS_INVALID_NUMBER;
+
+ return rtems_termios_close( arg );
+
+ return 0;
+
+ }
+
+
+/*
+ * Read from the device
+ */
+rtems_device_driver console_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
+ {
+
+ if(minor > NUM_PORTS-1)
+ return RTEMS_INVALID_NUMBER;
+
+ return rtems_termios_read(arg);
+
+ return 0;
+
+ }
+
+
+/*
+ * Write to the device
+ */
+rtems_device_driver console_write(rtems_device_major_number major,rtems_device_minor_number minor,void *arg)
+ {
+
+ if( minor > NUM_PORTS-1 )
+ return RTEMS_INVALID_NUMBER;
+
+ return rtems_termios_write(arg);
+
+ return 0;
+ }
+
+
+/*
+ * Handle ioctl request.
+ */
+rtems_device_driver console_control(rtems_device_major_number major,rtems_device_minor_number minor,void *arg)
+ {
+
+ if ( minor > NUM_PORTS-1 )
+ return RTEMS_INVALID_NUMBER;
+
+ return rtems_termios_ioctl(arg);
+
+ return 0;
+
+ }