leon, cons: drvmgr cons interface uses new TERMIOS

LEON driver manager console driver interface (cons) and the APBUART cons driver
(apbuart_cons) have been updated for recent TERMIOS interface changes. The
legacy callback API is not used anymore and deprecated functions are
eliminated.

This new implementation is based on RTEMS BSP and Device Driver Development
Guide, chapter named "Console Driver".
- Functions marked as deprecated (rtems_termios_open() and
  rtems_termios_close()) have been updated with the present-day versions.
- The legacy "callback" interface is replaced with the "handler" interface.
- Implementation is inspired by the documentation example, the non-driver
  manager driver for APBUART (apbuart_termios).
- Polled, interrupt and task mode is supported.
This commit is contained in:
Martin Aberg
2017-02-01 16:48:51 +01:00
committed by Daniel Hellstrom
parent 7cb9325047
commit fd9fb2154a
3 changed files with 231 additions and 204 deletions

View File

@@ -16,22 +16,20 @@
#ifndef __CONS_H__ #ifndef __CONS_H__
#define __CONS_H__ #define __CONS_H__
#include <rtems/termiostypes.h>
struct console_dev; struct console_dev;
#define CONSOLE_FLAG_SYSCON 0x01 #define CONSOLE_FLAG_SYSCON 0x01
struct console_cons_ops {
void (*get_uart_attrs)(struct console_dev *, struct termios *t);
};
struct console_dev { struct console_dev {
/* Set to non-zero if this UART should be system console and/or rtems_termios_device_context base;
/* Set to CONSOLE_FLAG_SYSCON if this UART should be system console and/or
* debug console. * debug console.
*/ */
int flags; int flags;
char *fsname; /* File system prefix */ char *fsname; /* File system prefix */
const struct rtems_termios_callbacks *callbacks; /* TERMIOS Callbacks */ const rtems_termios_device_handler *handler;
struct console_cons_ops ops;
}; };
extern void console_dev_register(struct console_dev *dev); extern void console_dev_register(struct console_dev *dev);

View File

@@ -18,7 +18,6 @@
/******************* Driver manager interface ***********************/ /******************* Driver manager interface ***********************/
#include <bsp.h> #include <bsp.h>
#include <rtems/libio.h>
#include <stdlib.h> #include <stdlib.h>
#include <assert.h> #include <assert.h>
#include <rtems/bspIo.h> #include <rtems/bspIo.h>
@@ -55,23 +54,63 @@ struct apbuart_priv {
struct console_dev condev; struct console_dev condev;
struct drvmgr_dev *dev; struct drvmgr_dev *dev;
struct apbuart_regs *regs; struct apbuart_regs *regs;
struct rtems_termios_tty *tty;
char devName[32]; char devName[32];
void *cookie; volatile int sending;
int sending;
int mode; int mode;
}; };
/* TERMIOS Layer Callback functions */ /* Getters for different interfaces. It happens to be just casting which we do
void apbuart_get_attributes(struct console_dev *condev, struct termios *t); * in one place to avoid getting cast away. */
int apbuart_set_attributes(int minor, const struct termios *t); static struct console_dev *base_get_condev(rtems_termios_device_context *base)
ssize_t apbuart_write_polled(int minor, const char *buf, size_t len); {
int apbuart_pollRead(int minor); return (struct console_dev *) base;
ssize_t apbuart_write_intr(int minor, const char *buf, size_t len); }
int apbuart_pollRead_task(int minor);
int apbuart_firstOpen(int major, int minor, void *arg);
int apbuart_lastClose(int major, int minor, void *arg);
void apbuart_isr(void *arg); static struct apbuart_priv *condev_get_priv(struct console_dev *condev)
{
return (struct apbuart_priv *) condev;
}
static struct apbuart_priv *base_get_priv(rtems_termios_device_context *base)
{
return condev_get_priv(base_get_condev(base));
}
/* TERMIOS Layer Callback functions */
static bool first_open(
rtems_termios_tty *tty,
rtems_termios_device_context *base,
struct termios *term,
rtems_libio_open_close_args_t *args
);
static void last_close(
rtems_termios_tty *tty,
rtems_termios_device_context *base,
rtems_libio_open_close_args_t *args
);
static void write_interrupt(
rtems_termios_device_context *base,
const char *buf,
size_t len
);
static bool set_attributes(
rtems_termios_device_context *base,
const struct termios *t
);
static void get_attributes(
rtems_termios_device_context *base,
struct termios *t
);
static int read_polled(rtems_termios_device_context *base);
static int read_task(rtems_termios_device_context *base);
static void write_polled(
rtems_termios_device_context *base,
const char *buf,
size_t len
);
static void apbuart_cons_isr(void *arg);
int apbuart_get_baud(struct apbuart_priv *uart); int apbuart_get_baud(struct apbuart_priv *uart);
int apbuart_init1(struct drvmgr_dev *dev); int apbuart_init1(struct drvmgr_dev *dev);
@@ -121,40 +160,30 @@ void apbuart_cons_register_drv (void)
drvmgr_drv_register(&apbuart_drv_info.general); drvmgr_drv_register(&apbuart_drv_info.general);
} }
/* Interrupt mode routines */ static const rtems_termios_device_handler handler_interrupt = {
static const rtems_termios_callbacks Callbacks_intr = { .first_open = first_open,
apbuart_firstOpen, /* firstOpen */ .last_close = last_close,
apbuart_lastClose, /* lastClose */ .write = write_interrupt,
NULL, /* pollRead */ .set_attributes = set_attributes,
apbuart_write_intr, /* write */ .mode = TERMIOS_IRQ_DRIVEN
apbuart_set_attributes, /* setAttributes */
NULL, /* stopRemoteTx */
NULL, /* startRemoteTx */
TERMIOS_IRQ_DRIVEN /* outputUsesInterrupts */
}; };
/* Polling mode routines */ static const rtems_termios_device_handler handler_task = {
static const rtems_termios_callbacks Callbacks_task = { .first_open = first_open,
apbuart_firstOpen, /* firstOpen */ .last_close = last_close,
apbuart_lastClose, /* lastClose */ .poll_read = read_task,
apbuart_pollRead_task, /* pollRead */ .write = write_interrupt,
apbuart_write_intr, /* write */ .set_attributes = set_attributes,
apbuart_set_attributes, /* setAttributes */ .mode = TERMIOS_TASK_DRIVEN
NULL, /* stopRemoteTx */
NULL, /* startRemoteTx */
TERMIOS_TASK_DRIVEN /* outputUsesInterrupts */
}; };
/* Polling mode routines */ static const rtems_termios_device_handler handler_polled = {
static const rtems_termios_callbacks Callbacks_poll = { .first_open = first_open,
apbuart_firstOpen, /* firstOpen */ .last_close = last_close,
apbuart_lastClose, /* lastClose */ .poll_read = read_polled,
apbuart_pollRead, /* pollRead */ .write = write_polled,
apbuart_write_polled, /* write */ .set_attributes = set_attributes,
apbuart_set_attributes, /* setAttributes */ .mode = TERMIOS_POLLED
NULL, /* stopRemoteTx */
NULL, /* startRemoteTx */
TERMIOS_POLLED /* outputUsesInterrupts */
}; };
int apbuart_init1(struct drvmgr_dev *dev) int apbuart_init1(struct drvmgr_dev *dev)
@@ -247,7 +276,6 @@ int apbuart_init1(struct drvmgr_dev *dev)
} }
priv->condev.fsname = NULL; priv->condev.fsname = NULL;
priv->condev.ops.get_uart_attrs = apbuart_get_attributes;
/* Select 0=Polled, 1=IRQ, 2=Task-Driven UART Mode */ /* Select 0=Polled, 1=IRQ, 2=Task-Driven UART Mode */
value = drvmgr_dev_key_get(priv->dev, "mode", DRVMGR_KT_INT); value = drvmgr_dev_key_get(priv->dev, "mode", DRVMGR_KT_INT);
@@ -255,12 +283,13 @@ int apbuart_init1(struct drvmgr_dev *dev)
priv->mode = value->i; priv->mode = value->i;
else else
priv->mode = TERMIOS_POLLED; priv->mode = TERMIOS_POLLED;
/* TERMIOS device handlers */
if (priv->mode == TERMIOS_IRQ_DRIVEN) { if (priv->mode == TERMIOS_IRQ_DRIVEN) {
priv->condev.callbacks = &Callbacks_intr; priv->condev.handler = &handler_interrupt;
} else if (priv->mode == TERMIOS_TASK_DRIVEN) { } else if (priv->mode == TERMIOS_TASK_DRIVEN) {
priv->condev.callbacks = &Callbacks_task; priv->condev.handler = &handler_task;
} else { } else {
priv->condev.callbacks = &Callbacks_poll; priv->condev.handler = &handler_polled;
} }
/* Get Filesystem name prefix */ /* Get Filesystem name prefix */
@@ -367,39 +396,58 @@ int apbuart_inbyte_nonblocking(struct apbuart_regs *regs)
} }
#endif #endif
int apbuart_firstOpen(int major, int minor, void *arg) static bool first_open(
rtems_termios_tty *tty,
rtems_termios_device_context *base,
struct termios *term,
rtems_libio_open_close_args_t *args
)
{ {
struct apbuart_priv *uart = (struct apbuart_priv *)minor; struct apbuart_priv *uart = base_get_priv(base);
rtems_libio_open_close_args_t *ioarg = arg;
if ( ioarg && ioarg->iop ) uart->tty = tty;
uart->cookie = ioarg->iop->data1;
else /* Preserve values set by bootloader */
uart->cookie = NULL; get_attributes(base, term);
term->c_oflag |= ONLCR;
set_attributes(base, term);
/* Enable TX/RX */ /* Enable TX/RX */
uart->regs->ctrl |= LEON_REG_UART_CTRL_RE | LEON_REG_UART_CTRL_TE; uart->regs->ctrl |= APBUART_CTRL_RE | APBUART_CTRL_TE;
if (uart->mode != TERMIOS_POLLED) { if (uart->mode != TERMIOS_POLLED) {
int ret;
/* Register interrupt and enable it */ /* Register interrupt and enable it */
drvmgr_interrupt_register(uart->dev, 0, "apbuart", ret = drvmgr_interrupt_register(
apbuart_isr, uart); uart->dev, 0, "apbuart", apbuart_cons_isr, tty
);
if (ret) {
return false;
}
uart->sending = 0; uart->sending = 0;
/* Turn on RX interrupts */ /* Turn on RX interrupts */
uart->regs->ctrl |= LEON_REG_UART_CTRL_RI; uart->regs->ctrl |= APBUART_CTRL_RI;
} }
return 0; return true;
} }
int apbuart_lastClose(int major, int minor, void *arg) static void last_close(
rtems_termios_tty *tty,
rtems_termios_device_context *base,
rtems_libio_open_close_args_t *args
)
{ {
struct apbuart_priv *uart = (struct apbuart_priv *)minor; struct apbuart_priv *uart = base_get_priv(base);
rtems_interrupt_lock_context lock_context;
if (uart->mode != TERMIOS_POLLED) { if (uart->mode != TERMIOS_POLLED) {
/* Turn off RX interrupts */ /* Turn off RX interrupts */
uart->regs->ctrl &= ~(LEON_REG_UART_CTRL_RI); rtems_termios_device_lock_acquire(base, &lock_context);
uart->regs->ctrl &= ~(APBUART_CTRL_RI);
rtems_termios_device_lock_release(base, &lock_context);
/**** Flush device ****/ /**** Flush device ****/
while (uart->sending) { while (uart->sending) {
@@ -407,42 +455,42 @@ int apbuart_lastClose(int major, int minor, void *arg)
} }
/* Disable and unregister interrupt handler */ /* Disable and unregister interrupt handler */
drvmgr_interrupt_unregister(uart->dev, 0, apbuart_isr, uart); drvmgr_interrupt_unregister(uart->dev, 0, apbuart_cons_isr, tty);
} }
#ifdef LEON3 #ifdef LEON3
/* Disable TX/RX if not used for DEBUG */ /* Disable TX/RX if not used for DEBUG */
if (uart->regs != dbg_uart) if (uart->regs != dbg_uart)
uart->regs->ctrl &= ~(LEON_REG_UART_CTRL_RE | LEON_REG_UART_CTRL_TE); uart->regs->ctrl &= ~(APBUART_CTRL_RE | APBUART_CTRL_TE);
#endif #endif
return 0;
} }
int apbuart_pollRead(int minor) static int read_polled(rtems_termios_device_context *base)
{ {
struct apbuart_priv *uart = (struct apbuart_priv *)minor; struct apbuart_priv *uart = base_get_priv(base);
return apbuart_inbyte_nonblocking(uart->regs); return apbuart_inbyte_nonblocking(uart->regs);
} }
int apbuart_pollRead_task(int minor) static int read_task(rtems_termios_device_context *base)
{ {
struct apbuart_priv *uart = (struct apbuart_priv *)minor; struct apbuart_priv *uart = base_get_priv(base);
int c, tot; int c, tot;
char buf[32]; char buf[32];
struct rtems_termios_tty *tty;
tty = uart->tty;
tot = 0; tot = 0;
while ((c=apbuart_inbyte_nonblocking(uart->regs)) != EOF) { while ((c=apbuart_inbyte_nonblocking(uart->regs)) != EOF) {
buf[tot] = c; buf[tot] = c;
tot++; tot++;
if (tot > 31) { if (tot > 31) {
rtems_termios_enqueue_raw_characters(uart->cookie, buf, tot); rtems_termios_enqueue_raw_characters(tty, buf, tot);
tot = 0; tot = 0;
} }
} }
if (tot > 0) if (tot > 0)
rtems_termios_enqueue_raw_characters(uart->cookie, buf, tot); rtems_termios_enqueue_raw_characters(tty, buf, tot);
return EOF; return EOF;
} }
@@ -517,13 +565,17 @@ static struct apbuart_baud *apbuart_get_baud_closest(struct apbuart_priv *uart)
return apbuart_baud_find_closest(apbuart_get_baud(uart)); return apbuart_baud_find_closest(apbuart_get_baud(uart));
} }
int apbuart_set_attributes(int minor, const struct termios *t) static bool set_attributes(
rtems_termios_device_context *base,
const struct termios *t
)
{ {
unsigned int core_clk_hz; unsigned int core_clk_hz;
unsigned int scaler; unsigned int scaler;
unsigned int ctrl; unsigned int ctrl;
int baud; int baud;
struct apbuart_priv *uart = (struct apbuart_priv *)minor; struct apbuart_priv *uart = base_get_priv(base);
rtems_interrupt_lock_context lock_context;
switch(t->c_cflag & CSIZE) { switch(t->c_cflag & CSIZE) {
default: default:
@@ -531,11 +583,13 @@ int apbuart_set_attributes(int minor, const struct termios *t)
case CS6: case CS6:
case CS7: case CS7:
/* Hardware doesn't support other than CS8 */ /* Hardware doesn't support other than CS8 */
return -1; return false;
case CS8: case CS8:
break; break;
} }
rtems_termios_device_lock_acquire(base, &lock_context);
/* Read out current value */ /* Read out current value */
ctrl = uart->regs->ctrl; ctrl = uart->regs->ctrl;
@@ -566,6 +620,8 @@ int apbuart_set_attributes(int minor, const struct termios *t)
/* Update new settings */ /* Update new settings */
uart->regs->ctrl = ctrl; uart->regs->ctrl = ctrl;
rtems_termios_device_lock_release(base, &lock_context);
/* Baud rate */ /* Baud rate */
baud = apbuart_baud_num2baud(t->c_ospeed); baud = apbuart_baud_num2baud(t->c_ospeed);
if (baud > 0){ if (baud > 0){
@@ -579,12 +635,15 @@ int apbuart_set_attributes(int minor, const struct termios *t)
uart->regs->scaler = scaler; uart->regs->scaler = scaler;
} }
return 0; return true;
} }
void apbuart_get_attributes(struct console_dev *condev, struct termios *t) static void get_attributes(
rtems_termios_device_context *base,
struct termios *t
)
{ {
struct apbuart_priv *uart = (struct apbuart_priv *)condev; struct apbuart_priv *uart = base_get_priv(base);
unsigned int ctrl; unsigned int ctrl;
struct apbuart_baud *baud; struct apbuart_baud *baud;
@@ -609,82 +668,109 @@ void apbuart_get_attributes(struct console_dev *condev, struct termios *t)
t->c_cflag |= baud->num; t->c_cflag |= baud->num;
} }
ssize_t apbuart_write_polled(int minor, const char *buf, size_t len) static void write_polled(
rtems_termios_device_context *base,
const char *buf,
size_t len
)
{ {
struct apbuart_priv *uart = base_get_priv(base);
int nwrite = 0; int nwrite = 0;
struct apbuart_priv *uart = (struct apbuart_priv *)minor;
while (nwrite < len) { while (nwrite < len) {
apbuart_outbyte_polled(uart->regs, *buf++, 0, 0); apbuart_outbyte_polled(uart->regs, *buf++, 0, 0);
nwrite++; nwrite++;
} }
return nwrite;
} }
ssize_t apbuart_write_intr(int minor, const char *buf, size_t len) static void write_interrupt(
rtems_termios_device_context *base,
const char *buf,
size_t len
)
{ {
struct apbuart_priv *uart = (struct apbuart_priv *)minor; struct apbuart_priv *uart = base_get_priv(base);
unsigned int oldLevel; struct apbuart_regs *regs = uart->regs;
int sending;
unsigned int ctrl; unsigned int ctrl;
rtems_interrupt_disable(oldLevel); ctrl = regs->ctrl;
/* Enable TX interrupt */ if (len > 0) {
ctrl = uart->regs->ctrl; /*
uart->regs->ctrl = ctrl | LEON_REG_UART_CTRL_TI; * sending is used to remember how much we have outstanding so
* we can tell termios later.
*/
/* Enable TX interrupt (interrupt is edge-triggered) */
regs->ctrl = ctrl | APBUART_CTRL_TI;
if (ctrl & LEON_REG_UART_CTRL_FA) { if (ctrl & APBUART_CTRL_FA) {
/* APBUART with FIFO.. Fill as many as FIFO allows */ /* APBUART with FIFO.. Fill as many as FIFO allows */
uart->sending = 0; sending = 0;
while (((uart->regs->status & LEON_REG_UART_STATUS_TF) == 0) && while (
(uart->sending < len)) { ((regs->status & APBUART_STATUS_TF) == 0) &&
uart->regs->data = *buf; (sending < len)
buf++; ) {
uart->sending++; regs->data = *buf;
buf++;
sending++;
}
} else {
/* start UART TX, this will result in an interrupt when done */
regs->data = *buf;
sending = 1;
} }
} else { } else {
/* start UART TX, this will result in an interrupt when done */ /* No more to send, disable TX interrupts */
uart->regs->data = *buf; regs->ctrl = ctrl & ~APBUART_CTRL_TI;
uart->sending = 1; /* Tell close that we sent everything */
sending = 0;
} }
rtems_interrupt_enable(oldLevel); uart->sending = sending;
return 0;
} }
/* Handle UART interrupts */ /* Handle UART interrupts */
void apbuart_isr(void *arg) static void apbuart_cons_isr(void *arg)
{ {
struct apbuart_priv *uart = arg; rtems_termios_tty *tty = arg;
struct console_dev *condev = rtems_termios_get_device_context(tty);
struct apbuart_priv *uart = condev_get_priv(condev);
struct apbuart_regs *regs = uart->regs;
unsigned int status; unsigned int status;
char data; char data;
int cnt; int cnt;
/* Get all received characters */
if (uart->mode == TERMIOS_TASK_DRIVEN) { if (uart->mode == TERMIOS_TASK_DRIVEN) {
if ((status=uart->regs->status) & LEON_REG_UART_STATUS_DR) if ((status=regs->status) & APBUART_STATUS_DR) {
rtems_termios_rxirq_occured(uart->cookie); /* Activate termios RX daemon task */
rtems_termios_rxirq_occured(tty);
}
} else { } else {
while ((status=uart->regs->status) & LEON_REG_UART_STATUS_DR) { /* Get all received characters */
while ((status=regs->status) & APBUART_STATUS_DR) {
/* Data has arrived, get new data */ /* Data has arrived, get new data */
data = uart->regs->data; data = regs->data;
/* Tell termios layer about new character */ /* Tell termios layer about new character */
rtems_termios_enqueue_raw_characters(uart->cookie, &data, 1); rtems_termios_enqueue_raw_characters(tty, &data, 1);
} }
} }
if (uart->sending && (status & LEON_REG_UART_STATUS_THE)) { if (uart->sending && (status & APBUART_STATUS_TE)) {
/* Sent the one char, we disable TX interrupts */
uart->regs->ctrl &= ~LEON_REG_UART_CTRL_TI;
/* Tell close that we sent everything */ /* Tell close that we sent everything */
cnt = uart->sending; cnt = uart->sending;
uart->sending = 0; uart->sending = 0;
/* apbuart_write_intr() will get called from this function */ /*
rtems_termios_dequeue_characters(uart->cookie, cnt); * Tell termios how much we have sent. dequeue() may call
* write_interrupt() to refill the transmitter.
* write_interrupt() will eventually be called with 0 len to
* disable TX interrupts.
*/
rtems_termios_dequeue_characters(tty, cnt);
} }
} }

View File

@@ -14,9 +14,8 @@
#include <bsp.h> #include <bsp.h>
#include <stdlib.h> #include <stdlib.h>
#include <rtems/libio.h>
#include <rtems/bspIo.h>
#include <bsp/cons.h> #include <bsp/cons.h>
#include <rtems/console.h>
#ifdef RTEMS_DRVMGR_STARTUP #ifdef RTEMS_DRVMGR_STARTUP
@@ -26,25 +25,26 @@
* handle interrupts. * handle interrupts.
*/ */
int console_initialized = 0; static int console_initialized = 0;
rtems_device_major_number console_major = 0;
#define FLAG_SYSCON 0x01 #define FLAG_SYSCON 0x01
struct console_priv { struct console_priv {
unsigned char flags; /* 0x1=SystemConsole */ int flags; /* 0x1=SystemConsole */
unsigned char minor; int minor;
struct console_dev *dev; struct console_dev *dev;
}; };
#define CONSOLE_MAX BSP_NUMBER_OF_TERMIOS_PORTS #define CONSOLE_MAX BSP_NUMBER_OF_TERMIOS_PORTS
struct console_priv cons[CONSOLE_MAX] = {{0,0},}; struct console_priv cons[CONSOLE_MAX] = {{0,0},};
/* Register Console to TERMIOS layer and initialize it */ /* Install Console in TERMIOS layer */
static void console_dev_init(struct console_priv *con, int minor) static void console_dev_init(struct console_priv *con)
{ {
char name[16], *fsname; char name[16], *fsname;
rtems_status_code status; rtems_status_code status;
int minor;
minor = con->minor;
if (!con->dev->fsname) { if (!con->dev->fsname) {
strcpy(name, "/dev/console_a"); strcpy(name, "/dev/console_a");
/* Special console name and MINOR for SYSTEM CONSOLE */ /* Special console name and MINOR for SYSTEM CONSOLE */
@@ -55,11 +55,18 @@ static void console_dev_init(struct console_priv *con, int minor)
} else { } else {
fsname = con->dev->fsname; fsname = con->dev->fsname;
} }
status = rtems_io_register_name(fsname, console_major, minor); status = rtems_termios_device_install(
if ((minor == 0) && (status != RTEMS_SUCCESSFUL)) fsname,
con->dev->handler,
NULL,
&con->dev->base
);
if (status != RTEMS_SUCCESSFUL) {
rtems_fatal_error_occurred(status); rtems_fatal_error_occurred(status);
}
} }
/* Called by device driver to register itself to the cons interface. */
void console_dev_register(struct console_dev *dev) void console_dev_register(struct console_dev *dev)
{ {
int i, minor = 0; int i, minor = 0;
@@ -87,11 +94,12 @@ void console_dev_register(struct console_dev *dev)
con->dev = dev; con->dev = dev;
con->minor = minor; con->minor = minor;
/* Console layer is already initialized, that means that we can if (console_initialized) {
* register termios interface directly. /* Console layer is already initialized, that means that we can
*/ * register termios interface directly.
if (console_initialized) */
console_dev_init(con, minor); console_dev_init(con);
}
} }
#if 0 #if 0
@@ -108,14 +116,12 @@ rtems_device_driver console_initialize(
{ {
int i; int i;
console_major = major;
rtems_termios_initialize(); rtems_termios_initialize();
/* Register all Console a file system device node */ /* Register all Console a file system device node */
for (i=0; i<CONSOLE_MAX; i++) { for (i=0; i<CONSOLE_MAX; i++) {
if (cons[i].dev) if (cons[i].dev)
console_dev_init(&cons[i], i); console_dev_init(&cons[i]);
} }
console_initialized = 1; console_initialized = 1;
@@ -123,67 +129,4 @@ rtems_device_driver console_initialize(
return RTEMS_SUCCESSFUL; return RTEMS_SUCCESSFUL;
} }
rtems_device_driver console_open(
rtems_device_major_number major,
rtems_device_minor_number minor,
void *arg)
{
rtems_status_code status;
struct termios term;
if ((minor >= CONSOLE_MAX) || !cons[minor].dev)
return RTEMS_INVALID_NUMBER;
status = rtems_termios_open(
major,
(int)cons[minor].dev,
arg,
cons[minor].dev->callbacks);
/* Inherit UART hardware parameters from bootloader on system console */
if ((status == RTEMS_SUCCESSFUL) && (cons[minor].flags & FLAG_SYSCON) &&
(cons[minor].dev->ops.get_uart_attrs != NULL)) {
if (tcgetattr(STDIN_FILENO, &term) >= 0) {
cons[minor].dev->ops.get_uart_attrs(cons[minor].dev,
&term);
term.c_oflag |= ONLCR;
tcsetattr(STDIN_FILENO, TCSANOW, &term);
}
}
return status;
}
rtems_device_driver console_close(
rtems_device_major_number major,
rtems_device_minor_number minor,
void *arg)
{
return rtems_termios_close(arg);
}
rtems_device_driver console_read(
rtems_device_major_number major,
rtems_device_minor_number minor,
void *arg)
{
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);
}
rtems_device_driver console_control(
rtems_device_major_number major,
rtems_device_minor_number minor,
void *arg)
{
return rtems_termios_ioctl(arg);
}
#endif #endif