termios: Partially hide rtems_termios_tty

Move interrupt lock to device context and expose only this structure to
the read, write and set attributes device handler.  This makes these
device handler independent of the general Termios infrastructure
suitable for direct use in printk() support.
This commit is contained in:
Sebastian Huber
2014-10-07 16:28:04 +02:00
parent a830cb864d
commit 7fd5e89c96
12 changed files with 325 additions and 197 deletions

View File

@@ -26,7 +26,6 @@
#include <bspopts.h> #include <bspopts.h>
#include <termios.h> #include <termios.h>
#include <rtems/termiostypes.h> #include <rtems/termiostypes.h>
#include <libchip/sersupp.h>
#include <bsp/tms570-sci.h> #include <bsp/tms570-sci.h>
#include <bsp/tms570-sci-driver.h> #include <bsp/tms570-sci-driver.h>
#include <rtems/console.h> #include <rtems/console.h>
@@ -43,11 +42,13 @@
*/ */
const tms570_sci_context driver_context_table[] = { const tms570_sci_context driver_context_table[] = {
{ {
.base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER("TMS570 SCI1"),
.device_name = "/dev/console", .device_name = "/dev/console",
.regs = &TMS570_SCI, .regs = &TMS570_SCI,
.irq = TMS570_IRQ_SCI_LEVEL_0, .irq = TMS570_IRQ_SCI_LEVEL_0,
}, },
{ {
.base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER("TMS570 SCI2"),
.device_name = "/dev/ttyS1", .device_name = "/dev/ttyS1",
.regs = &TMS570_SCI2, .regs = &TMS570_SCI2,
.irq = TMS570_IRQ_SCI2_LEVEL_0, .irq = TMS570_IRQ_SCI2_LEVEL_0,
@@ -104,7 +105,7 @@ rtems_device_driver console_initialize(
minor, minor,
handler, handler,
NULL, NULL,
(void *) ctx RTEMS_DECONST(rtems_termios_device_context *, &ctx->base)
); );
if ( sc != RTEMS_SUCCESSFUL ) { if ( sc != RTEMS_SUCCESSFUL ) {
bsp_fatal(BSP_FATAL_CONSOLE_NO_DEV); bsp_fatal(BSP_FATAL_CONSOLE_NO_DEV);
@@ -196,21 +197,21 @@ static int tms570_sci_transmitted_chars(tms570_sci_context * ctx)
* *
* Sets attributes of the HW peripheral (parity, baud rate, etc.) * Sets attributes of the HW peripheral (parity, baud rate, etc.)
* *
* @param[in] tty rtems_termios_tty * @param[in] base context of the driver
* @param[in] t termios driver * @param[in] t termios driver
* @retval true peripheral setting is changed * @retval true peripheral setting is changed
*/ */
static bool tms570_sci_set_attributes( static bool tms570_sci_set_attributes(
rtems_termios_tty *tty, rtems_termios_device_context *base,
const struct termios *t const struct termios *t
) )
{ {
tms570_sci_context *ctx = rtems_termios_get_device_context(tty); tms570_sci_context *ctx = (tms570_sci_context *) base;
rtems_interrupt_lock_context lock_context; rtems_interrupt_lock_context lock_context;
int32_t bauddiv; int32_t bauddiv;
int32_t baudrate; int32_t baudrate;
rtems_termios_interrupt_lock_acquire(tty, &lock_context); rtems_termios_device_lock_acquire(base, &lock_context);
ctx->regs->SCIGCR1 &= ~( (1<<7) | (1<<25) | (1<<24) ); ctx->regs->SCIGCR1 &= ~( (1<<7) | (1<<25) | (1<<24) );
@@ -245,7 +246,7 @@ static bool tms570_sci_set_attributes(
ctx->regs->SCIGCR1 |= (1<<7) | (1<<25) | (1<<24); ctx->regs->SCIGCR1 |= (1<<7) | (1<<25) | (1<<24);
rtems_termios_interrupt_lock_release(tty, &lock_context); rtems_termios_device_lock_release(base, &lock_context);
return true; return true;
} }
@@ -300,18 +301,18 @@ static void tms570_sci_interrupt_handler(void * arg)
* TMS570 does not have write data buffer asociated with SCI * TMS570 does not have write data buffer asociated with SCI
* so only one character can be written. * so only one character can be written.
* *
* @param[in] tty rtems_termios_tty * @param[in] base context of the driver
* @param[in] buf buffer of characters pending to send * @param[in] buf buffer of characters pending to send
* @param[in] len size of the buffer * @param[in] len size of the buffer
* @retval Void * @retval Void
*/ */
static void tms570_sci_interrupt_write( static void tms570_sci_interrupt_write(
rtems_termios_tty *tty, rtems_termios_device_context *base,
const char *buf, const char *buf,
size_t len size_t len
) )
{ {
tms570_sci_context *ctx = rtems_termios_get_device_context(tty); tms570_sci_context *ctx = (tms570_sci_context *) base;
if ( len > 0 ) { if ( len > 0 ) {
/* start UART TX, this will result in an interrupt when done */ /* start UART TX, this will result in an interrupt when done */
@@ -334,18 +335,18 @@ static void tms570_sci_interrupt_write(
* Blocking write function. Waits until HW peripheral is ready and then writes * Blocking write function. Waits until HW peripheral is ready and then writes
* character to HW peripheral. Writes all characters in the buffer. * character to HW peripheral. Writes all characters in the buffer.
* *
* @param[in] tty rtems_termios_tty * @param[in] base context of the driver
* @param[in] buf buffer of characters pending to send * @param[in] buf buffer of characters pending to send
* @param[in] len size of the buffer * @param[in] len size of the buffer
* @retval Void * @retval Void
*/ */
static void tms570_sci_poll_write( static void tms570_sci_poll_write(
rtems_termios_tty *tty, rtems_termios_device_context *base,
const char *buf, const char *buf,
size_t n size_t n
) )
{ {
tms570_sci_context *ctx = rtems_termios_get_device_context(tty); tms570_sci_context *ctx = (tms570_sci_context *) base;
size_t i; size_t i;
/* Write */ /* Write */
@@ -394,13 +395,13 @@ static char TMS570_sci_read_char(
* *
* check if there is recieved character to be read and reads it. * check if there is recieved character to be read and reads it.
* *
* @param[in] tty rtems_termios_tty (context of the driver) * @param[in] base context of the driver
* @retval -1 No character to be read * @retval -1 No character to be read
* @retval x Read character * @retval x Read character
*/ */
static int tms570_sci_poll_read(rtems_termios_tty *tty) static int tms570_sci_poll_read(rtems_termios_device_context *base)
{ {
tms570_sci_context *ctx = rtems_termios_get_device_context(tty); tms570_sci_context *ctx = (tms570_sci_context *) base;
/* Check if a character is available */ /* Check if a character is available */
if ( TMS570_sci_can_read_char(ctx) ) { if ( TMS570_sci_can_read_char(ctx) ) {
@@ -416,20 +417,24 @@ static int tms570_sci_poll_read(rtems_termios_tty *tty)
* initialization of the HW peripheral specified in contex of the driver. * initialization of the HW peripheral specified in contex of the driver.
* This function is called only once when opening the driver. * This function is called only once when opening the driver.
* *
* @param[in] tty context of the driver * @param[in] tty Termios control
* @param[in] ctx context of the driver
* @param[in] term Termios attributes
* @param[in] args * @param[in] args
* @retval false Error occured during initialization * @retval false Error occured during initialization
* @retval true Driver is open and ready * @retval true Driver is open and ready
*/ */
static bool tms570_sci_poll_first_open( static bool tms570_sci_poll_first_open(
rtems_termios_tty *tty, rtems_termios_tty *tty,
rtems_termios_device_context *ctx,
struct termios *term,
rtems_libio_open_close_args_t *args rtems_libio_open_close_args_t *args
) )
{ {
bool ok; bool ok;
rtems_termios_set_best_baud(tty, TMS570_SCI_BAUD_RATE); rtems_termios_set_best_baud(term, TMS570_SCI_BAUD_RATE);
ok = tms570_sci_set_attributes(tty, rtems_termios_get_termios(tty)); ok = tms570_sci_set_attributes(ctx, term);
if ( !ok ) { if ( !ok ) {
return false; return false;
} }
@@ -442,21 +447,24 @@ static bool tms570_sci_poll_first_open(
* calls tms570_sci_poll_first_open function. * calls tms570_sci_poll_first_open function.
* install and enables interrupts. * install and enables interrupts.
* *
* @param[in] tty context of the driver * @param[in] tty Termios control
* @param[in] base context of the driver
* @param[in] args * @param[in] args
* @retval false Error occured during initialization * @retval false Error occured during initialization
* @retval true Driver is open and ready * @retval true Driver is open and ready
*/ */
static bool tms570_sci_interrupt_first_open( static bool tms570_sci_interrupt_first_open(
rtems_termios_tty *tty, rtems_termios_tty *tty,
rtems_termios_device_context *base,
struct termios *term,
rtems_libio_open_close_args_t *args rtems_libio_open_close_args_t *args
) )
{ {
tms570_sci_context *ctx = rtems_termios_get_device_context(tty); tms570_sci_context *ctx = (tms570_sci_context *) base;
rtems_status_code sc; rtems_status_code sc;
bool ret; bool ret;
ret = tms570_sci_poll_first_open(tty,args); ret = tms570_sci_poll_first_open(tty, base, term, args);
if ( ret == false ) { if ( ret == false ) {
return false; return false;
} }
@@ -471,20 +479,22 @@ static bool tms570_sci_interrupt_first_open(
if ( sc != RTEMS_SUCCESSFUL ) { if ( sc != RTEMS_SUCCESSFUL ) {
return false; return false;
} }
tms570_sci_enable_interrupts(rtems_termios_get_device_context(tty)); tms570_sci_enable_interrupts(ctx);
return true; return true;
} }
/** /**
* @brief closes sci peripheral * @brief closes sci peripheral
* *
* @param[in] tty context of the driver * @param[in] tty Termios control
* @param[in] base context of the driver
* @param[in] args * @param[in] args
* @retval false Error occured during initialization * @retval false Error occured during initialization
* @retval true Driver is open and ready * @retval true Driver is open and ready
*/ */
static void tms570_sci_poll_last_close( static void tms570_sci_poll_last_close(
rtems_termios_tty *tty, rtems_termios_tty *tty,
rtems_termios_device_context *base,
rtems_libio_open_close_args_t *args rtems_libio_open_close_args_t *args
) )
{ {
@@ -496,23 +506,25 @@ static void tms570_sci_poll_last_close(
* *
* calls tms570_sci_poll_last_close and disables interrupts * calls tms570_sci_poll_last_close and disables interrupts
* *
* @param[in] tty context of the driver * @param[in] tty Termios control
* @param[in] base context of the driver
* @param[in] args * @param[in] args
* @retval false Error occured during initialization * @retval false Error occured during initialization
* @retval true Driver is open and ready * @retval true Driver is open and ready
*/ */
static void tms570_sci_interrupt_last_close( static void tms570_sci_interrupt_last_close(
rtems_termios_tty *tty, rtems_termios_tty *tty,
rtems_termios_device_context *base,
rtems_libio_open_close_args_t *args rtems_libio_open_close_args_t *args
) )
{ {
tms570_sci_context *ctx = rtems_termios_get_device_context(tty); tms570_sci_context *ctx = (tms570_sci_context *) base;
rtems_interrupt_lock_context lock_context; rtems_interrupt_lock_context lock_context;
/* Turn off RX interrupts */ /* Turn off RX interrupts */
rtems_termios_interrupt_lock_acquire(tty, &lock_context); rtems_termios_device_lock_acquire(base, &lock_context);
tms570_sci_disable_interrupts(ctx); tms570_sci_disable_interrupts(ctx);
rtems_termios_interrupt_lock_release(tty, &lock_context); rtems_termios_device_lock_release(base, &lock_context);
/* Flush device */ /* Flush device */
while ( ( ctx->regs->SCIFLR & (1<<11) ) > 0 ) { while ( ( ctx->regs->SCIFLR & (1<<11) ) > 0 ) {
@@ -522,7 +534,7 @@ static void tms570_sci_interrupt_last_close(
/* uninstall ISR */ /* uninstall ISR */
rtems_interrupt_handler_remove(ctx->irq, tms570_sci_interrupt_handler, tty); rtems_interrupt_handler_remove(ctx->irq, tms570_sci_interrupt_handler, tty);
tms570_sci_poll_last_close(tty,args); tms570_sci_poll_last_close(tty, base, args);
} }
/** /**

View File

@@ -36,6 +36,7 @@ extern "C" {
/* Low-level driver specific data structure */ /* Low-level driver specific data structure */
typedef struct { typedef struct {
rtems_termios_device_context base;
const char *device_name; const char *device_name;
volatile tms570_sci_t *regs; volatile tms570_sci_t *regs;
int tx_chars_in_hw; int tx_chars_in_hw;

View File

@@ -36,7 +36,7 @@ int syscon_uart_index __attribute__((weak)) = 0;
static struct apbuart_context apbuarts[BSP_NUMBER_OF_TERMIOS_PORTS]; static struct apbuart_context apbuarts[BSP_NUMBER_OF_TERMIOS_PORTS];
static int uarts = 0; static int uarts = 0;
static struct apbuart_context *leon3_console_get_uart(int minor) static rtems_termios_device_context *leon3_console_get_context(int minor)
{ {
struct apbuart_context *uart; struct apbuart_context *uart;
@@ -45,7 +45,9 @@ static struct apbuart_context *leon3_console_get_uart(int minor)
else else
uart = &apbuarts[minor - 1]; uart = &apbuarts[minor - 1];
return uart; rtems_termios_device_context_initialize(&uart->base, "APBUART");
return &uart->base;
} }
/* AMBA PP find routine. Extract AMBA PnP information into data structure. */ /* AMBA PP find routine. Extract AMBA PnP information into data structure. */
@@ -132,7 +134,7 @@ rtems_device_driver console_initialize(
minor, minor,
handler, handler,
NULL, NULL,
leon3_console_get_uart(syscon_uart_index) leon3_console_get_context(syscon_uart_index)
); );
if (status != RTEMS_SUCCESSFUL) if (status != RTEMS_SUCCESSFUL)
bsp_fatal(LEON3_FATAL_CONSOLE_REGISTER_DEV); bsp_fatal(LEON3_FATAL_CONSOLE_REGISTER_DEV);
@@ -149,7 +151,7 @@ rtems_device_driver console_initialize(
minor, minor,
handler, handler,
NULL, NULL,
leon3_console_get_uart(syscon_uart_index) leon3_console_get_context(syscon_uart_index)
); );
} }

View File

@@ -22,6 +22,7 @@ extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
struct apbuart_context { struct apbuart_context {
rtems_termios_device_context base;
struct apbuart_regs *regs; struct apbuart_regs *regs;
unsigned int freq_hz; unsigned int freq_hz;
rtems_vector_number irq; rtems_vector_number irq;

View File

@@ -41,12 +41,12 @@ static void apbuart_isr(void *arg)
} }
static void apbuart_write_support( static void apbuart_write_support(
rtems_termios_tty *tty, rtems_termios_device_context *base,
const char *buf, const char *buf,
size_t len size_t len
) )
{ {
struct apbuart_context *uart = rtems_termios_get_device_context(tty); struct apbuart_context *uart = (struct apbuart_context *) base;
int sending; int sending;
if (len > 0) { if (len > 0) {
@@ -69,12 +69,12 @@ static void apbuart_write_support(
} }
static void apbuart_write_polled( static void apbuart_write_polled(
rtems_termios_tty *tty, rtems_termios_device_context *base,
const char *buf, const char *buf,
size_t len size_t len
) )
{ {
struct apbuart_context *uart = rtems_termios_get_device_context(tty); struct apbuart_context *uart = (struct apbuart_context *) base;
size_t nwrite = 0; size_t nwrite = 0;
while (nwrite < len) { while (nwrite < len) {
@@ -83,19 +83,19 @@ static void apbuart_write_polled(
} }
} }
static int apbuart_poll_read(rtems_termios_tty *tty) static int apbuart_poll_read(rtems_termios_device_context *base)
{ {
struct apbuart_context *uart = rtems_termios_get_device_context(tty); struct apbuart_context *uart = (struct apbuart_context *) base;
return apbuart_inbyte_nonblocking(uart->regs); return apbuart_inbyte_nonblocking(uart->regs);
} }
static bool apbuart_set_attributes( static bool apbuart_set_attributes(
rtems_termios_tty *tty, rtems_termios_device_context *base,
const struct termios *t const struct termios *t
) )
{ {
struct apbuart_context *uart = rtems_termios_get_device_context(tty); struct apbuart_context *uart = (struct apbuart_context *) base;
rtems_interrupt_lock_context lock_context; rtems_interrupt_lock_context lock_context;
unsigned int scaler; unsigned int scaler;
unsigned int ctrl; unsigned int ctrl;
@@ -112,7 +112,7 @@ static bool apbuart_set_attributes(
break; break;
} }
rtems_termios_interrupt_lock_acquire(tty, &lock_context); rtems_termios_device_lock_acquire(base, &lock_context);
/* Read out current value */ /* Read out current value */
ctrl = uart->regs->ctrl; ctrl = uart->regs->ctrl;
@@ -145,7 +145,7 @@ static bool apbuart_set_attributes(
/* Update new settings */ /* Update new settings */
uart->regs->ctrl = ctrl; uart->regs->ctrl = ctrl;
rtems_termios_interrupt_lock_release(tty, &lock_context); rtems_termios_device_lock_release(base, &lock_context);
/* Baud rate */ /* Baud rate */
baud = rtems_termios_baud_to_number(t->c_cflag); baud = rtems_termios_baud_to_number(t->c_cflag);
@@ -161,23 +161,25 @@ static bool apbuart_set_attributes(
} }
static void apbuart_set_best_baud( static void apbuart_set_best_baud(
rtems_termios_tty *tty, const struct apbuart_context *uart,
const struct apbuart_context *uart struct termios *term
) )
{ {
uint32_t baud = (uart->freq_hz * 10) / ((uart->regs->scaler * 10 + 5) * 8); uint32_t baud = (uart->freq_hz * 10) / ((uart->regs->scaler * 10 + 5) * 8);
rtems_termios_set_best_baud(tty, baud); rtems_termios_set_best_baud(term, baud);
} }
static bool apbuart_first_open_polled( static bool apbuart_first_open_polled(
rtems_termios_tty *tty, rtems_termios_tty *tty,
rtems_termios_device_context *base,
struct termios *term,
rtems_libio_open_close_args_t *args rtems_libio_open_close_args_t *args
) )
{ {
struct apbuart_context *uart = rtems_termios_get_device_context(tty); struct apbuart_context *uart = (struct apbuart_context *) base;
apbuart_set_best_baud(tty, uart); apbuart_set_best_baud(uart, term);
/* Initialize UART on opening */ /* Initialize UART on opening */
uart->regs->ctrl |= APBUART_CTRL_RE | APBUART_CTRL_TE; uart->regs->ctrl |= APBUART_CTRL_RE | APBUART_CTRL_TE;
@@ -188,13 +190,15 @@ static bool apbuart_first_open_polled(
static bool apbuart_first_open_interrupt( static bool apbuart_first_open_interrupt(
rtems_termios_tty *tty, rtems_termios_tty *tty,
rtems_termios_device_context *base,
struct termios *term,
rtems_libio_open_close_args_t *args rtems_libio_open_close_args_t *args
) )
{ {
struct apbuart_context *uart = rtems_termios_get_device_context(tty); struct apbuart_context *uart = (struct apbuart_context *) base;
rtems_status_code sc; rtems_status_code sc;
apbuart_set_best_baud(tty, uart); apbuart_set_best_baud(uart, term);
/* Register Interrupt handler */ /* Register Interrupt handler */
sc = rtems_interrupt_handler_install(uart->irq, "console", sc = rtems_interrupt_handler_install(uart->irq, "console",
@@ -217,16 +221,17 @@ static bool apbuart_first_open_interrupt(
static void apbuart_last_close_interrupt( static void apbuart_last_close_interrupt(
rtems_termios_tty *tty, rtems_termios_tty *tty,
rtems_termios_device_context *base,
rtems_libio_open_close_args_t *args rtems_libio_open_close_args_t *args
) )
{ {
struct apbuart_context *uart = rtems_termios_get_device_context(tty); struct apbuart_context *uart = (struct apbuart_context *) base;
rtems_interrupt_lock_context lock_context; rtems_interrupt_lock_context lock_context;
/* Turn off RX interrupts */ /* Turn off RX interrupts */
rtems_termios_interrupt_lock_acquire(tty, &lock_context); rtems_termios_device_lock_acquire(base, &lock_context);
uart->regs->ctrl &= ~(APBUART_CTRL_RI); uart->regs->ctrl &= ~(APBUART_CTRL_RI);
rtems_termios_interrupt_lock_release(tty, &lock_context); rtems_termios_device_lock_release(base, &lock_context);
/**** Flush device ****/ /**** Flush device ****/
while (uart->sending) { while (uart->sending) {

View File

@@ -62,6 +62,42 @@ typedef enum {
struct rtems_termios_tty; struct rtems_termios_tty;
/**
* @brief Termios device context.
*
* @see RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER(),
* rtems_termios_device_context_initialize() and
* rtems_termios_device_install().
*/
typedef struct rtems_termios_device_context {
rtems_interrupt_lock interrupt_lock;
} rtems_termios_device_context;
/**
* @brief Initializes a device context.
*
* @param[in] context The Termios device context.
* @param[in] name The name for the interrupt lock. This name must be a
* string persistent throughout the life time of this lock. The name is only
* used if profiling is enabled.
*/
RTEMS_INLINE_ROUTINE void rtems_termios_device_context_initialize(
rtems_termios_device_context *context,
const char *name
)
{
rtems_interrupt_lock_initialize( &context->interrupt_lock, name );
}
/**
* @brief Initializer for static initialization of Termios device contexts.
*
* @param name The name for the interrupt lock. It must be a string. The name
* is only used if profiling is enabled.
*/
#define RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER( name ) \
{ RTEMS_INTERRUPT_LOCK_INITIALIZER( name ) }
/** /**
* @brief Termios device handler. * @brief Termios device handler.
* *
@@ -71,18 +107,24 @@ typedef struct {
/** /**
* @brief First open of this device. * @brief First open of this device.
* *
* @param[in] tty The Termios control. * @param[in] tty The Termios control. This parameter may be passed to
* interrupt service routines since it must be provided for the
* rtems_termios_enqueue_raw_characters() and
* rtems_termios_dequeue_characters() functions.
* @param[in] context The Termios device context.
* @param[in] term The current Termios attributes.
* @param[in] args The open/close arguments. This is parameter provided to * @param[in] args The open/close arguments. This is parameter provided to
* support legacy drivers. It must not be used by new drivers. * support legacy drivers. It must not be used by new drivers.
* *
* @retval true Successful operation. * @retval true Successful operation.
* @retval false Cannot open device. * @retval false Cannot open device.
* *
* @see rtems_termios_get_device_context(), rtems_termios_set_best_baud() and * @see rtems_termios_get_device_context() and rtems_termios_set_best_baud().
* rtems_termios_get_termios().
*/ */
bool (*first_open)( bool (*first_open)(
struct rtems_termios_tty *tty, struct rtems_termios_tty *tty,
rtems_termios_device_context *context,
struct termios *term,
rtems_libio_open_close_args_t *args rtems_libio_open_close_args_t *args
); );
@@ -90,13 +132,13 @@ typedef struct {
* @brief Last close of this device. * @brief Last close of this device.
* *
* @param[in] tty The Termios control. * @param[in] tty The Termios control.
* @param[in] context The Termios device context.
* @param[in] args The open/close arguments. This is parameter provided to * @param[in] args The open/close arguments. This is parameter provided to
* support legacy drivers. It must not be used by new drivers. * support legacy drivers. It must not be used by new drivers.
*
* @see rtems_termios_get_device_context().
*/ */
void (*last_close)( void (*last_close)(
struct rtems_termios_tty *tty, struct rtems_termios_tty *tty,
rtems_termios_device_context *context,
rtems_libio_open_close_args_t *args rtems_libio_open_close_args_t *args
); );
@@ -106,41 +148,39 @@ typedef struct {
* In case mode is TERMIOS_IRQ_DRIVEN or TERMIOS_TASK_DRIVEN, then data is * In case mode is TERMIOS_IRQ_DRIVEN or TERMIOS_TASK_DRIVEN, then data is
* received via rtems_termios_enqueue_raw_characters(). * received via rtems_termios_enqueue_raw_characters().
* *
* @param[in] tty The Termios control. * @param[in] context The Termios device context.
* *
* @retval char The received data encoded as unsigned char. * @retval char The received data encoded as unsigned char.
* @retval -1 No data currently available. * @retval -1 No data currently available.
*
* @see rtems_termios_get_device_context().
*/ */
int (*poll_read)(struct rtems_termios_tty *tty); int (*poll_read)(rtems_termios_device_context *context);
/** /**
* @brief Polled write in case mode is TERMIOS_POLLED or write support * @brief Polled write in case mode is TERMIOS_POLLED or write support
* otherwise. * otherwise.
* *
* @param[in] tty The Termios control. * @param[in] context The Termios device context.
* @param[in] buf The output buffer. * @param[in] buf The output buffer.
* @param[in] len The output buffer length in characters. * @param[in] len The output buffer length in characters.
*
* @see rtems_termios_get_device_context().
*/ */
void (*write)(struct rtems_termios_tty *tty, const char *buf, size_t len); void (*write)(
rtems_termios_device_context *context,
const char *buf,
size_t len
);
/** /**
* @brief Set attributes after a Termios settings change. * @brief Set attributes after a Termios settings change.
* *
* @param[in] tty The Termios control. * @param[in] context The Termios device context.
* @param[in] term The new Termios attributes. * @param[in] term The new Termios attributes.
* *
* @retval true Successful operation. * @retval true Successful operation.
* @retval false Invalid attributes. * @retval false Invalid attributes.
*
* @see rtems_termios_get_device_context().
*/ */
bool (*set_attributes)( bool (*set_attributes)(
struct rtems_termios_tty *tty, rtems_termios_device_context *context,
const struct termios *term const struct termios *term
); );
/** /**
@@ -158,20 +198,16 @@ typedef struct {
/** /**
* @brief Indicate to stop remote transmitter. * @brief Indicate to stop remote transmitter.
* *
* @param[in] tty The Termios control. * @param[in] context The Termios device context.
*
* @see rtems_termios_get_device_context().
*/ */
void (*stop_remote_tx)(struct rtems_termios_tty *tty); void (*stop_remote_tx)(rtems_termios_device_context *context);
/** /**
* @brief Indicate to start remote transmitter. * @brief Indicate to start remote transmitter.
* *
* @param[in] tty The Termios control. * @param[in] context The Termios device context.
*
* @see rtems_termios_get_device_context().
*/ */
void (*start_remote_tx)(struct rtems_termios_tty *tty); void (*start_remote_tx)(rtems_termios_device_context *context);
} rtems_termios_device_flow; } rtems_termios_device_flow;
/** /**
@@ -185,7 +221,7 @@ typedef struct rtems_termios_device_node {
rtems_device_minor_number minor; rtems_device_minor_number minor;
const rtems_termios_device_handler *handler; const rtems_termios_device_handler *handler;
const rtems_termios_device_flow *flow; const rtems_termios_device_flow *flow;
void *context; rtems_termios_device_context *context;
struct rtems_termios_tty *tty; struct rtems_termios_tty *tty;
} rtems_termios_device_node; } rtems_termios_device_node;
@@ -257,6 +293,11 @@ typedef struct rtems_termios_tty {
*/ */
rtems_termios_callbacks device; rtems_termios_callbacks device;
/**
* @brief Context for legacy devices using the callbacks.
*/
rtems_termios_device_context legacy_device_context;
/** /**
* @brief The device handler. * @brief The device handler.
*/ */
@@ -289,8 +330,6 @@ typedef struct rtems_termios_tty {
struct ttywakeup tty_rcv; struct ttywakeup tty_rcv;
int tty_rcvwakeup; int tty_rcvwakeup;
rtems_interrupt_lock interrupt_lock;
/** /**
* @brief Corresponding device node. * @brief Corresponding device node.
*/ */
@@ -298,10 +337,8 @@ typedef struct rtems_termios_tty {
/** /**
* @brief Context for device driver. * @brief Context for device driver.
*
* @see rtems_termios_get_device_context().
*/ */
void *device_context; rtems_termios_device_context *device_context;
} rtems_termios_tty; } rtems_termios_tty;
/** /**
@@ -335,7 +372,7 @@ rtems_status_code rtems_termios_device_install(
rtems_device_minor_number minor, rtems_device_minor_number minor,
const rtems_termios_device_handler *handler, const rtems_termios_device_handler *handler,
const rtems_termios_device_flow *flow, const rtems_termios_device_flow *flow,
void *context rtems_termios_device_context *context
); );
/** /**
@@ -382,6 +419,8 @@ rtems_status_code rtems_termios_device_close(void *arg);
/** /**
* @brief Returns the device context of an installed Termios device. * @brief Returns the device context of an installed Termios device.
*
* @param[in] tty The Termios control.
*/ */
RTEMS_INLINE_ROUTINE void *rtems_termios_get_device_context( RTEMS_INLINE_ROUTINE void *rtems_termios_get_device_context(
const rtems_termios_tty *tty const rtems_termios_tty *tty
@@ -391,16 +430,33 @@ RTEMS_INLINE_ROUTINE void *rtems_termios_get_device_context(
} }
/** /**
* @brief Returns the Termios structure. * @brief Acquires the device lock.
* *
* It can be used for example in the first open handler to adjust or obtain the * @param[in] context The device context.
* initial attributes. * @param[in] lock_context The local interrupt lock context for an acquire and
* release pair.
*/ */
RTEMS_INLINE_ROUTINE struct termios *rtems_termios_get_termios( RTEMS_INLINE_ROUTINE void rtems_termios_device_lock_acquire(
rtems_termios_tty *tty rtems_termios_device_context *context,
rtems_interrupt_lock_context *lock_context
) )
{ {
return &tty->termios; rtems_interrupt_lock_acquire( &context->interrupt_lock, lock_context );
}
/**
* @brief Releases the device lock.
*
* @param[in] context The device context.
* @param[in] lock_context The local interrupt lock context for an acquire and
* release pair.
*/
RTEMS_INLINE_ROUTINE void rtems_termios_device_lock_release(
rtems_termios_device_context *context,
rtems_interrupt_lock_context *lock_context
)
{
rtems_interrupt_lock_release( &context->interrupt_lock, lock_context );
} }
/** /**
@@ -409,12 +465,12 @@ RTEMS_INLINE_ROUTINE struct termios *rtems_termios_get_termios(
* The valid Termios baud values are between 0 and 460800. The Termios baud * The valid Termios baud values are between 0 and 460800. The Termios baud
* value is chosen which minimizes the difference to the value specified. * value is chosen which minimizes the difference to the value specified.
* *
* @param[in] tty The Termios control. * @param[in] term The Termios attributes.
* @param[in] baud The current baud setting of the device. * @param[in] baud The current baud setting of the device.
*/ */
void rtems_termios_set_best_baud( void rtems_termios_set_best_baud(
rtems_termios_tty *tty, struct termios *term,
uint32_t baud uint32_t baud
); );
struct rtems_termios_linesw { struct rtems_termios_linesw {
@@ -498,12 +554,6 @@ int rtems_termios_set_initial_baud(
rtems_termios_baud_t baud rtems_termios_baud_t baud
); );
#define rtems_termios_interrupt_lock_acquire(tty, level) \
rtems_interrupt_lock_acquire(&tty->interrupt_lock, level)
#define rtems_termios_interrupt_lock_release(tty, level) \
rtems_interrupt_lock_release(&tty->interrupt_lock, level)
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -134,7 +134,7 @@ rtems_status_code rtems_termios_device_install(
rtems_device_minor_number minor, rtems_device_minor_number minor,
const rtems_termios_device_handler *handler, const rtems_termios_device_handler *handler,
const rtems_termios_device_flow *flow, const rtems_termios_device_flow *flow,
void *context rtems_termios_device_context *context
) )
{ {
rtems_status_code sc; rtems_status_code sc;
@@ -227,12 +227,23 @@ rtems_status_code rtems_termios_device_remove(
return RTEMS_SUCCESSFUL; return RTEMS_SUCCESSFUL;
} }
static rtems_termios_tty *
legacyContextToTTY (rtems_termios_device_context *ctx)
{
return RTEMS_CONTAINER_OF (ctx, rtems_termios_tty, legacy_device_context);
}
static bool static bool
rtems_termios_callback_firstOpen( rtems_termios_callback_firstOpen(
rtems_termios_tty *tty, rtems_termios_tty *tty,
rtems_termios_device_context *ctx,
struct termios *term,
rtems_libio_open_close_args_t *args rtems_libio_open_close_args_t *args
) )
{ {
(void) ctx;
(void) term;
(*tty->device.firstOpen) (tty->major, tty->minor, args); (*tty->device.firstOpen) (tty->major, tty->minor, args);
return true; return true;
@@ -241,48 +252,61 @@ rtems_termios_callback_firstOpen(
static void static void
rtems_termios_callback_lastClose( rtems_termios_callback_lastClose(
rtems_termios_tty *tty, rtems_termios_tty *tty,
rtems_termios_device_context *ctx,
rtems_libio_open_close_args_t *args rtems_libio_open_close_args_t *args
) )
{ {
(void) ctx;
(*tty->device.lastClose) (tty->major, tty->minor, args); (*tty->device.lastClose) (tty->major, tty->minor, args);
} }
static int static int
rtems_termios_callback_pollRead (struct rtems_termios_tty *tty) rtems_termios_callback_pollRead (rtems_termios_device_context *ctx)
{ {
rtems_termios_tty *tty = legacyContextToTTY (ctx);
return (*tty->device.pollRead) (tty->minor); return (*tty->device.pollRead) (tty->minor);
} }
static void static void
rtems_termios_callback_write( rtems_termios_callback_write(
rtems_termios_tty *tty, rtems_termios_device_context *ctx,
const char *buf, const char *buf,
size_t len size_t len
) )
{ {
rtems_termios_tty *tty = legacyContextToTTY (ctx);
(*tty->device.write) (tty->minor, buf, len); (*tty->device.write) (tty->minor, buf, len);
} }
static bool static bool
rtems_termios_callback_setAttributes( rtems_termios_callback_setAttributes(
rtems_termios_tty *tty, rtems_termios_device_context *ctx,
const struct termios *term const struct termios *term
) )
{ {
rtems_termios_tty *tty = legacyContextToTTY (ctx);
(*tty->device.setAttributes) (tty->minor, term); (*tty->device.setAttributes) (tty->minor, term);
return true; return true;
} }
static void static void
rtems_termios_callback_stopRemoteTx (rtems_termios_tty *tty) rtems_termios_callback_stopRemoteTx (rtems_termios_device_context *ctx)
{ {
rtems_termios_tty *tty = legacyContextToTTY (ctx);
(*tty->device.stopRemoteTx) (tty->minor); (*tty->device.stopRemoteTx) (tty->minor);
} }
static void static void
rtems_termios_callback_startRemoteTx (rtems_termios_tty *tty) rtems_termios_callback_startRemoteTx (rtems_termios_device_context *ctx)
{ {
rtems_termios_tty *tty = legacyContextToTTY (ctx);
(*tty->device.startRemoteTx) (tty->minor); (*tty->device.startRemoteTx) (tty->minor);
} }
@@ -292,21 +316,22 @@ rtems_termios_callback_startRemoteTx (rtems_termios_tty *tty)
static void static void
drainOutput (struct rtems_termios_tty *tty) drainOutput (struct rtems_termios_tty *tty)
{ {
rtems_termios_device_context *ctx = tty->device_context;
rtems_interrupt_lock_context lock_context; rtems_interrupt_lock_context lock_context;
rtems_status_code sc; rtems_status_code sc;
if (tty->handler.mode != TERMIOS_POLLED) { if (tty->handler.mode != TERMIOS_POLLED) {
rtems_termios_interrupt_lock_acquire (tty, &lock_context); rtems_termios_device_lock_acquire (ctx, &lock_context);
while (tty->rawOutBuf.Tail != tty->rawOutBuf.Head) { while (tty->rawOutBuf.Tail != tty->rawOutBuf.Head) {
tty->rawOutBufState = rob_wait; tty->rawOutBufState = rob_wait;
rtems_termios_interrupt_lock_release (tty, &lock_context); rtems_termios_device_lock_release (ctx, &lock_context);
sc = rtems_semaphore_obtain( sc = rtems_semaphore_obtain(
tty->rawOutBuf.Semaphore, RTEMS_WAIT, RTEMS_NO_TIMEOUT); tty->rawOutBuf.Semaphore, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
if (sc != RTEMS_SUCCESSFUL) if (sc != RTEMS_SUCCESSFUL)
rtems_fatal_error_occurred (sc); rtems_fatal_error_occurred (sc);
rtems_termios_interrupt_lock_acquire (tty, &lock_context); rtems_termios_device_lock_acquire (ctx, &lock_context);
} }
rtems_termios_interrupt_lock_release (tty, &lock_context); rtems_termios_device_lock_release (ctx, &lock_context);
} }
} }
@@ -344,7 +369,7 @@ rtems_termios_destroy_tty (rtems_termios_tty *tty, void *arg, bool last_close)
rtems_fatal_error_occurred (sc); rtems_fatal_error_occurred (sc);
} }
if (last_close && tty->handler.last_close) if (last_close && tty->handler.last_close)
(*tty->handler.last_close)(tty, arg); (*tty->handler.last_close)(tty, tty->device_context, arg);
if (tty->device_node != NULL) if (tty->device_node != NULL)
tty->device_node->tty = NULL; tty->device_node->tty = NULL;
@@ -355,7 +380,10 @@ rtems_termios_destroy_tty (rtems_termios_tty *tty, void *arg, bool last_close)
if ((tty->handler.poll_read == NULL) || if ((tty->handler.poll_read == NULL) ||
(tty->handler.mode == TERMIOS_TASK_DRIVEN)) (tty->handler.mode == TERMIOS_TASK_DRIVEN))
rtems_semaphore_delete (tty->rawInBuf.Semaphore); rtems_semaphore_delete (tty->rawInBuf.Semaphore);
rtems_interrupt_lock_destroy (&tty->interrupt_lock);
if (tty->device_context == &tty->legacy_device_context)
rtems_interrupt_lock_destroy (&tty->legacy_device_context.interrupt_lock);
free (tty->rawInBuf.theBuf); free (tty->rawInBuf.theBuf);
free (tty->rawOutBuf.theBuf); free (tty->rawOutBuf.theBuf);
free (tty->cbuf); free (tty->cbuf);
@@ -489,7 +517,10 @@ rtems_termios_open_tty(
tty->device = *callbacks; tty->device = *callbacks;
} }
rtems_interrupt_lock_initialize (&tty->interrupt_lock, "Termios"); if (tty->device_context == NULL) {
tty->device_context = &tty->legacy_device_context;
rtems_termios_device_context_initialize (tty->device_context, "Termios");
}
/* /*
* Create I/O tasks * Create I/O tasks
@@ -569,8 +600,8 @@ rtems_termios_open_tty(
} }
args->iop->data1 = tty; args->iop->data1 = tty;
if (!tty->refcount++) { if (!tty->refcount++) {
if (tty->handler.first_open && if (tty->handler.first_open && !(*tty->handler.first_open)(
!(*tty->handler.first_open)(tty, args)) { tty, tty->device_context, &tty->termios, args)) {
rtems_termios_destroy_tty(tty, args, false); rtems_termios_destroy_tty(tty, args, false);
return NULL; return NULL;
} }
@@ -683,24 +714,26 @@ rtems_termios_open (
static void static void
flushOutput (struct rtems_termios_tty *tty) flushOutput (struct rtems_termios_tty *tty)
{ {
rtems_termios_device_context *ctx = tty->device_context;
rtems_interrupt_lock_context lock_context; rtems_interrupt_lock_context lock_context;
rtems_termios_interrupt_lock_acquire (tty, &lock_context); rtems_termios_device_lock_acquire (ctx, &lock_context);
tty->rawOutBuf.Tail = 0; tty->rawOutBuf.Tail = 0;
tty->rawOutBuf.Head = 0; tty->rawOutBuf.Head = 0;
tty->rawOutBufState = rob_idle; tty->rawOutBufState = rob_idle;
rtems_termios_interrupt_lock_release (tty, &lock_context); rtems_termios_device_lock_release (ctx, &lock_context);
} }
static void static void
flushInput (struct rtems_termios_tty *tty) flushInput (struct rtems_termios_tty *tty)
{ {
rtems_termios_device_context *ctx = tty->device_context;
rtems_interrupt_lock_context lock_context; rtems_interrupt_lock_context lock_context;
rtems_termios_interrupt_lock_acquire (tty, &lock_context); rtems_termios_device_lock_acquire (ctx, &lock_context);
tty->rawInBuf.Tail = 0; tty->rawInBuf.Tail = 0;
tty->rawInBuf.Head = 0; tty->rawInBuf.Head = 0;
rtems_termios_interrupt_lock_release (tty, &lock_context); rtems_termios_device_lock_release (ctx, &lock_context);
} }
static void static void
@@ -784,6 +817,7 @@ rtems_status_code rtems_termios_bufsize (
static void static void
termios_set_flowctrl(struct rtems_termios_tty *tty) termios_set_flowctrl(struct rtems_termios_tty *tty)
{ {
rtems_termios_device_context *ctx = tty->device_context;
rtems_interrupt_lock_context lock_context; rtems_interrupt_lock_context lock_context;
/* /*
* check for flow control options to be switched off * check for flow control options to be switched off
@@ -798,16 +832,16 @@ termios_set_flowctrl(struct rtems_termios_tty *tty)
/* has output been stopped due to received XOFF? */ /* has output been stopped due to received XOFF? */
if (tty->flow_ctrl & FL_OSTOP) { if (tty->flow_ctrl & FL_OSTOP) {
/* disable interrupts */ /* disable interrupts */
rtems_termios_interrupt_lock_acquire (tty, &lock_context); rtems_termios_device_lock_acquire (ctx, &lock_context);
tty->flow_ctrl &= ~FL_OSTOP; tty->flow_ctrl &= ~FL_OSTOP;
/* check for chars in output buffer (or rob_state?) */ /* check for chars in output buffer (or rob_state?) */
if (tty->rawOutBufState != rob_idle) { if (tty->rawOutBufState != rob_idle) {
/* if chars available, call write function... */ /* if chars available, call write function... */
(*tty->handler.write)( (*tty->handler.write)(
tty, &tty->rawOutBuf.theBuf[tty->rawOutBuf.Tail],1); ctx, &tty->rawOutBuf.theBuf[tty->rawOutBuf.Tail],1);
} }
/* reenable interrupts */ /* reenable interrupts */
rtems_termios_interrupt_lock_release (tty, &lock_context); rtems_termios_device_lock_release (ctx, &lock_context);
} }
} }
/* check for incoming XON/XOFF flow control switched off */ /* check for incoming XON/XOFF flow control switched off */
@@ -826,7 +860,7 @@ termios_set_flowctrl(struct rtems_termios_tty *tty)
/* restart remote Tx, if it was stopped */ /* restart remote Tx, if it was stopped */
if ((tty->flow_ctrl & FL_IRTSOFF) && if ((tty->flow_ctrl & FL_IRTSOFF) &&
(tty->flow.start_remote_tx != NULL)) { (tty->flow.start_remote_tx != NULL)) {
tty->flow.start_remote_tx(tty); tty->flow.start_remote_tx(ctx);
} }
tty->flow_ctrl &= ~(FL_IRTSOFF); tty->flow_ctrl &= ~(FL_IRTSOFF);
} }
@@ -906,7 +940,7 @@ rtems_termios_ioctl (void *arg)
} }
} }
if (tty->handler.set_attributes) { if (tty->handler.set_attributes) {
sc = (*tty->handler.set_attributes)(tty, &tty->termios) ? sc = (*tty->handler.set_attributes)(tty->device_context, &tty->termios) ?
RTEMS_SUCCESSFUL : RTEMS_IO_ERROR; RTEMS_SUCCESSFUL : RTEMS_IO_ERROR;
} }
break; break;
@@ -1003,7 +1037,7 @@ startXmit (
nToSend = 0; nToSend = 0;
/* stop transmitter */ /* stop transmitter */
if (transmitting) { if (transmitting) {
(*tty->handler.write) (tty, NULL, 0); (*tty->handler.write) (tty->device_context, NULL, 0);
} }
} else { } else {
/* when flow control XON or XOF, don't send blocks of data */ /* when flow control XON or XOF, don't send blocks of data */
@@ -1017,7 +1051,7 @@ startXmit (
nToSend = tty->rawOutBuf.Head - newTail; nToSend = tty->rawOutBuf.Head - newTail;
(*tty->handler.write)( (*tty->handler.write)(
tty, &tty->rawOutBuf.theBuf[newTail], nToSend); tty->device_context, &tty->rawOutBuf.theBuf[newTail], nToSend);
} }
return nToSend; return nToSend;
@@ -1032,11 +1066,12 @@ rtems_termios_puts (
{ {
const char *buf = _buf; const char *buf = _buf;
unsigned int newHead; unsigned int newHead;
rtems_termios_device_context *ctx = tty->device_context;
rtems_interrupt_lock_context lock_context; rtems_interrupt_lock_context lock_context;
rtems_status_code sc; rtems_status_code sc;
if (tty->handler.mode == TERMIOS_POLLED) { if (tty->handler.mode == TERMIOS_POLLED) {
(*tty->handler.write)(tty, buf, len); (*tty->handler.write)(ctx, buf, len);
return; return;
} }
@@ -1049,15 +1084,15 @@ rtems_termios_puts (
if (newHead >= tty->rawOutBuf.Size) if (newHead >= tty->rawOutBuf.Size)
newHead -= tty->rawOutBuf.Size; newHead -= tty->rawOutBuf.Size;
rtems_termios_interrupt_lock_acquire (tty, &lock_context); rtems_termios_device_lock_acquire (ctx, &lock_context);
while (newHead == tty->rawOutBuf.Tail) { while (newHead == tty->rawOutBuf.Tail) {
tty->rawOutBufState = rob_wait; tty->rawOutBufState = rob_wait;
rtems_termios_interrupt_lock_release (tty, &lock_context); rtems_termios_device_lock_release (ctx, &lock_context);
sc = rtems_semaphore_obtain( sc = rtems_semaphore_obtain(
tty->rawOutBuf.Semaphore, RTEMS_WAIT, RTEMS_NO_TIMEOUT); tty->rawOutBuf.Semaphore, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
if (sc != RTEMS_SUCCESSFUL) if (sc != RTEMS_SUCCESSFUL)
rtems_fatal_error_occurred (sc); rtems_fatal_error_occurred (sc);
rtems_termios_interrupt_lock_acquire (tty, &lock_context); rtems_termios_device_lock_acquire (ctx, &lock_context);
} }
/* Determine free space up to current tail or end of ring buffer */ /* Determine free space up to current tail or end of ring buffer */
@@ -1090,7 +1125,7 @@ rtems_termios_puts (
startXmit (tty, tty->rawOutBuf.Tail, false); startXmit (tty, tty->rawOutBuf.Tail, false);
} }
rtems_termios_interrupt_lock_release (tty, &lock_context); rtems_termios_device_lock_release (ctx, &lock_context);
buf += nToCopy; buf += nToCopy;
len -= nToCopy; len -= nToCopy;
@@ -1371,7 +1406,7 @@ fillBufferPoll (struct rtems_termios_tty *tty)
if (tty->termios.c_lflag & ICANON) { if (tty->termios.c_lflag & ICANON) {
for (;;) { for (;;) {
n = (*tty->handler.poll_read)(tty); n = (*tty->handler.poll_read)(tty->device_context);
if (n < 0) { if (n < 0) {
rtems_task_wake_after (1); rtems_task_wake_after (1);
} else { } else {
@@ -1384,7 +1419,7 @@ fillBufferPoll (struct rtems_termios_tty *tty)
then = rtems_clock_get_ticks_since_boot(); then = rtems_clock_get_ticks_since_boot();
for (;;) { for (;;) {
n = (*tty->handler.poll_read)(tty); n = (*tty->handler.poll_read)(tty->device_context);
if (n < 0) { if (n < 0) {
if (tty->termios.c_cc[VMIN]) { if (tty->termios.c_cc[VMIN]) {
if (tty->termios.c_cc[VTIME] && tty->ccount) { if (tty->termios.c_cc[VTIME] && tty->ccount) {
@@ -1447,12 +1482,12 @@ fillBufferQueue (struct rtems_termios_tty *tty)
|| (tty->flow_ctrl & FL_OSTOP))) { || (tty->flow_ctrl & FL_OSTOP))) {
/* XON should be sent now... */ /* XON should be sent now... */
(*tty->handler.write)( (*tty->handler.write)(
tty, (void *)&(tty->termios.c_cc[VSTART]), 1); tty->device_context, (void *)&(tty->termios.c_cc[VSTART]), 1);
} else if (tty->flow_ctrl & FL_MDRTS) { } else if (tty->flow_ctrl & FL_MDRTS) {
tty->flow_ctrl &= ~FL_IRTSOFF; tty->flow_ctrl &= ~FL_IRTSOFF;
/* activate RTS line */ /* activate RTS line */
if (tty->flow.start_remote_tx != NULL) { if (tty->flow.start_remote_tx != NULL) {
tty->flow.start_remote_tx(tty); tty->flow.start_remote_tx(tty->device_context);
} }
} }
} }
@@ -1550,6 +1585,7 @@ rtems_termios_enqueue_raw_characters (void *ttyp, const char *buf, int len)
char c; char c;
int dropped = 0; int dropped = 0;
bool flow_rcv = false; /* true, if flow control char received */ bool flow_rcv = false; /* true, if flow control char received */
rtems_termios_device_context *ctx = tty->device_context;
rtems_interrupt_lock_context lock_context; rtems_interrupt_lock_context lock_context;
if (rtems_termios_linesw[tty->t_line].l_rint != NULL) { if (rtems_termios_linesw[tty->t_line].l_rint != NULL) {
@@ -1598,21 +1634,21 @@ rtems_termios_enqueue_raw_characters (void *ttyp, const char *buf, int len)
/* restart output according to FL_ORCVXOF flag */ /* restart output according to FL_ORCVXOF flag */
if ((tty->flow_ctrl & (FL_ORCVXOF | FL_OSTOP)) == FL_OSTOP) { if ((tty->flow_ctrl & (FL_ORCVXOF | FL_OSTOP)) == FL_OSTOP) {
/* disable interrupts */ /* disable interrupts */
rtems_termios_interrupt_lock_acquire (tty, &lock_context); rtems_termios_device_lock_acquire (ctx, &lock_context);
tty->flow_ctrl &= ~FL_OSTOP; tty->flow_ctrl &= ~FL_OSTOP;
/* check for chars in output buffer (or rob_state?) */ /* check for chars in output buffer (or rob_state?) */
if (tty->rawOutBufState != rob_idle) { if (tty->rawOutBufState != rob_idle) {
/* if chars available, call write function... */ /* if chars available, call write function... */
(*tty->handler.write)( (*tty->handler.write)(
tty, &tty->rawOutBuf.theBuf[tty->rawOutBuf.Tail], 1); ctx, &tty->rawOutBuf.theBuf[tty->rawOutBuf.Tail], 1);
} }
/* reenable interrupts */ /* reenable interrupts */
rtems_termios_interrupt_lock_release (tty, &lock_context); rtems_termios_device_lock_release (ctx, &lock_context);
} }
} else { } else {
newTail = (tty->rawInBuf.Tail + 1) % tty->rawInBuf.Size; newTail = (tty->rawInBuf.Tail + 1) % tty->rawInBuf.Size;
/* if chars_in_buffer > highwater */ /* if chars_in_buffer > highwater */
rtems_termios_interrupt_lock_acquire (tty, &lock_context); rtems_termios_device_lock_acquire (ctx, &lock_context);
if ((((newTail - tty->rawInBuf.Head + tty->rawInBuf.Size) if ((((newTail - tty->rawInBuf.Head + tty->rawInBuf.Size)
% tty->rawInBuf.Size) > tty->highwater) && % tty->rawInBuf.Size) > tty->highwater) &&
!(tty->flow_ctrl & FL_IREQXOF)) { !(tty->flow_ctrl & FL_IREQXOF)) {
@@ -1625,20 +1661,20 @@ rtems_termios_enqueue_raw_characters (void *ttyp, const char *buf, int len)
/* if tx is stopped due to XOFF or out of data */ /* if tx is stopped due to XOFF or out of data */
/* call write function here */ /* call write function here */
tty->flow_ctrl |= FL_ISNTXOF; tty->flow_ctrl |= FL_ISNTXOF;
(*tty->handler.write)(tty, (*tty->handler.write)(ctx,
(void *)&(tty->termios.c_cc[VSTOP]), 1); (void *)&(tty->termios.c_cc[VSTOP]), 1);
} }
} else if ((tty->flow_ctrl & (FL_MDRTS | FL_IRTSOFF)) == (FL_MDRTS) ) { } else if ((tty->flow_ctrl & (FL_MDRTS | FL_IRTSOFF)) == (FL_MDRTS) ) {
tty->flow_ctrl |= FL_IRTSOFF; tty->flow_ctrl |= FL_IRTSOFF;
/* deactivate RTS line */ /* deactivate RTS line */
if (tty->flow.stop_remote_tx != NULL) { if (tty->flow.stop_remote_tx != NULL) {
tty->flow.stop_remote_tx(tty); tty->flow.stop_remote_tx(ctx);
} }
} }
} }
/* reenable interrupts */ /* reenable interrupts */
rtems_termios_interrupt_lock_release (tty, &lock_context); rtems_termios_device_lock_release (ctx, &lock_context);
if (newTail == tty->rawInBuf.Head) { if (newTail == tty->rawInBuf.Head) {
dropped++; dropped++;
@@ -1672,16 +1708,17 @@ rtems_termios_refill_transmitter (struct rtems_termios_tty *tty)
bool wakeUpWriterTask = false; bool wakeUpWriterTask = false;
unsigned int newTail; unsigned int newTail;
int nToSend; int nToSend;
rtems_termios_device_context *ctx = tty->device_context;
rtems_interrupt_lock_context lock_context; rtems_interrupt_lock_context lock_context;
int len; int len;
rtems_termios_interrupt_lock_acquire (tty, &lock_context); rtems_termios_device_lock_acquire (ctx, &lock_context);
/* check for XOF/XON to send */ /* check for XOF/XON to send */
if ((tty->flow_ctrl & (FL_MDXOF | FL_IREQXOF | FL_ISNTXOF)) if ((tty->flow_ctrl & (FL_MDXOF | FL_IREQXOF | FL_ISNTXOF))
== (FL_MDXOF | FL_IREQXOF)) { == (FL_MDXOF | FL_IREQXOF)) {
/* XOFF should be sent now... */ /* XOFF should be sent now... */
(*tty->handler.write)(tty, (void *)&(tty->termios.c_cc[VSTOP]), 1); (*tty->handler.write)(ctx, (void *)&(tty->termios.c_cc[VSTOP]), 1);
tty->t_dqlen--; tty->t_dqlen--;
tty->flow_ctrl |= FL_ISNTXOF; tty->flow_ctrl |= FL_ISNTXOF;
@@ -1697,7 +1734,7 @@ rtems_termios_refill_transmitter (struct rtems_termios_tty *tty)
* buffer, although the corresponding data is not yet out! * buffer, although the corresponding data is not yet out!
* Therefore the dequeue "length" should be reduced by 1 * Therefore the dequeue "length" should be reduced by 1
*/ */
(*tty->handler.write)(tty, (void *)&(tty->termios.c_cc[VSTART]), 1); (*tty->handler.write)(ctx, (void *)&(tty->termios.c_cc[VSTART]), 1);
tty->t_dqlen--; tty->t_dqlen--;
tty->flow_ctrl &= ~FL_ISNTXOF; tty->flow_ctrl &= ~FL_ISNTXOF;
@@ -1714,7 +1751,7 @@ rtems_termios_refill_transmitter (struct rtems_termios_tty *tty)
wakeUpWriterTask = true; wakeUpWriterTask = true;
} }
(*tty->handler.write) (tty, NULL, 0); (*tty->handler.write) (ctx, NULL, 0);
nToSend = 0; nToSend = 0;
} else { } else {
len = tty->t_dqlen; len = tty->t_dqlen;
@@ -1734,7 +1771,7 @@ rtems_termios_refill_transmitter (struct rtems_termios_tty *tty)
* Buffer has become empty * Buffer has become empty
*/ */
tty->rawOutBufState = rob_idle; tty->rawOutBufState = rob_idle;
(*tty->handler.write) (tty, NULL, 0); (*tty->handler.write) (ctx, NULL, 0);
nToSend = 0; nToSend = 0;
/* /*
@@ -1751,7 +1788,7 @@ rtems_termios_refill_transmitter (struct rtems_termios_tty *tty)
} }
} }
rtems_termios_interrupt_lock_release (tty, &lock_context); rtems_termios_device_lock_release (ctx, &lock_context);
if (wakeUpWriterTask) { if (wakeUpWriterTask) {
rtems_semaphore_release (tty->rawOutBuf.Semaphore); rtems_semaphore_release (tty->rawOutBuf.Semaphore);
@@ -1854,6 +1891,7 @@ static rtems_task rtems_termios_txdaemon(rtems_task_argument argument)
static rtems_task rtems_termios_rxdaemon(rtems_task_argument argument) static rtems_task rtems_termios_rxdaemon(rtems_task_argument argument)
{ {
struct rtems_termios_tty *tty = (struct rtems_termios_tty *)argument; struct rtems_termios_tty *tty = (struct rtems_termios_tty *)argument;
rtems_termios_device_context *ctx = tty->device_context;
rtems_event_set the_event; rtems_event_set the_event;
int c; int c;
char c_buf; char c_buf;
@@ -1876,7 +1914,7 @@ static rtems_task rtems_termios_rxdaemon(rtems_task_argument argument)
/* /*
* do something * do something
*/ */
c = tty->handler.poll_read(tty); c = tty->handler.poll_read(ctx);
if (c != EOF) { if (c != EOF) {
/* /*
* poll_read did call enqueue on its own * poll_read did call enqueue on its own

View File

@@ -19,8 +19,8 @@
#include <rtems/termiostypes.h> #include <rtems/termiostypes.h>
void rtems_termios_set_best_baud( void rtems_termios_set_best_baud(
rtems_termios_tty *tty, struct termios *term,
uint32_t baud uint32_t baud
) )
{ {
const rtems_assoc_t *current = &rtems_termios_baud_table[ 0 ]; const rtems_assoc_t *current = &rtems_termios_baud_table[ 0 ];
@@ -41,5 +41,5 @@ void rtems_termios_set_best_baud(
cbaud = B460800; cbaud = B460800;
} }
tty->termios.c_cflag = (tty->termios.c_cflag & ~cbaud_mask) | cbaud; term->c_cflag = (term->c_cflag & ~cbaud_mask) | cbaud;
} }

View File

@@ -387,7 +387,7 @@ static rtems_task ppp_txdaemon(rtems_task_argument arg)
/* write out frame byte to start the transmission */ /* write out frame byte to start the transmission */
sc->sc_outchar = (u_char)PPP_FLAG; sc->sc_outchar = (u_char)PPP_FLAG;
(*tp->handler.write)(tp, (char *)&sc->sc_outchar, 1); (*tp->handler.write)(tp->device_context, (char *)&sc->sc_outchar, 1);
} }
/* check to see if we need to free some empty mbufs */ /* check to see if we need to free some empty mbufs */

View File

@@ -568,6 +568,7 @@ pppstart(struct rtems_termios_tty *tp)
u_long ioffset = (u_long )0; u_long ioffset = (u_long )0;
struct mbuf *m = (struct mbuf *)0; struct mbuf *m = (struct mbuf *)0;
struct ppp_softc *sc = tp->t_sc; struct ppp_softc *sc = tp->t_sc;
rtems_termios_device_context *ctx = rtems_termios_get_device_context(tp);
/* ensure input is valid and we are busy */ /* ensure input is valid and we are busy */
if (( sc != NULL ) && ( sc->sc_outflag & SC_TX_BUSY )) { if (( sc != NULL ) && ( sc->sc_outflag & SC_TX_BUSY )) {
@@ -606,7 +607,7 @@ pppstart(struct rtems_termios_tty *tp)
sc->sc_outflag |= SC_TX_LASTCHAR; sc->sc_outflag |= SC_TX_LASTCHAR;
sc->sc_outflag &=~(SC_TX_FCS); sc->sc_outflag &=~(SC_TX_FCS);
sc->sc_outchar = (u_char)PPP_FLAG; sc->sc_outchar = (u_char)PPP_FLAG;
(*tp->handler.write)(tp, (char *)&sc->sc_outchar, 1); (*tp->handler.write)(ctx, (char *)&sc->sc_outchar, 1);
return(0); return(0);
} }
} }
@@ -643,7 +644,7 @@ pppstart(struct rtems_termios_tty *tp)
} }
/* write out the character(s) and update the stats */ /* write out the character(s) and update the stats */
(*tp->handler.write)(tp, (char *)sendBegin, (ioffset > 0) ? ioffset : 1); (*tp->handler.write)(ctx, (char *)sendBegin, (ioffset > 0) ? ioffset : 1);
sc->sc_stats.ppp_obytes += (ioffset > 0) ? ioffset : 1; sc->sc_stats.ppp_obytes += (ioffset > 0) ? ioffset : 1;
sc->sc_outoff += ioffset; sc->sc_outoff += ioffset;
} }

View File

@@ -274,6 +274,7 @@ initialization example the device name is also present. Her is an example heade
/* Low-level driver specific data structure */ /* Low-level driver specific data structure */
typedef struct @{ typedef struct @{
rtems_termios_device_context base;
const char *device_name; const char *device_name;
volatile module_register_block *regs; volatile module_register_block *regs;
/* More stuff */ /* More stuff */
@@ -298,12 +299,12 @@ characters from @code{buf} to the serial device specified by @code{tty}.
@example @example
@group @group
static void my_driver_poll_write( static void my_driver_poll_write(
rtems_termios_tty *tty, rtems_termios_device_context *base,
const char *buf, const char *buf,
size_t n size_t n
) )
@{ @{
my_driver_context *ctx = rtems_termios_get_device_context(tty); my_driver_context *ctx = (my_driver_context *) base;
size_t i; size_t i;
/* Write */ /* Write */
@@ -320,9 +321,9 @@ available, then the routine should return minus one.
@example @example
@group @group
static int my_driver_poll_read(rtems_termios_tty *tty) static int my_driver_poll_read(rtems_termios_device_context *base)
@{ @{
my_driver_context *ctx = rtems_termios_get_device_context(tty); my_driver_context *ctx = (my_driver_context *) base;
/* Check if a character is available */ /* Check if a character is available */
if (my_driver_can_read_char(ctx)) @{ if (my_driver_can_read_char(ctx)) @{
@@ -409,12 +410,12 @@ character.
@example @example
@group @group
static void my_driver_interrupt_write( static void my_driver_interrupt_write(
rtems_termios_tty *tty, rtems_termios_device_context *base,
const char *buf, const char *buf,
size_t n size_t n
) )
@{ @{
my_driver_context *ctx = rtems_termios_get_device_context(tty); my_driver_context *ctx = (my_driver_context *) base;
/* /*
* Tell the device to transmit some characters from buf (less than * Tell the device to transmit some characters from buf (less than
@@ -518,10 +519,12 @@ During the first open of the device Termios will call the
@group @group
static bool my_driver_first_open( static bool my_driver_first_open(
rtems_termios_tty *tty, rtems_termios_tty *tty,
rtems_termios_device_context *base,
struct termios *term,
rtems_libio_open_close_args_t *args rtems_libio_open_close_args_t *args
) )
@{ @{
my_driver_context *ctx = rtems_termios_get_device_context(tty); my_driver_context *ctx = (my_driver_context *) base;
rtems_status_code sc; rtems_status_code sc;
bool ok; bool ok;
@@ -542,13 +545,13 @@ static bool my_driver_first_open(
/* /*
* Alternatively you can set the best baud. * Alternatively you can set the best baud.
*/ */
rtems_termios_set_best_baud(tty, MY_DRIVER_BAUD_RATE); rtems_termios_set_best_baud(term, MY_DRIVER_BAUD_RATE);
/* /*
* To propagate the initial Termios attributes to the device use * To propagate the initial Termios attributes to the device use
* this. * this.
*/ */
ok = my_driver_set_attributes(tty, rtems_termios_get_termios(tty)); ok = my_driver_set_attributes(base, term);
if (!ok) @{ if (!ok) @{
/* This is bad */ /* This is bad */
@} @}
@@ -574,10 +577,11 @@ happens on the device.
@group @group
static void my_driver_last_close( static void my_driver_last_close(
rtems_termios_tty *tty, rtems_termios_tty *tty,
rtems_termios_device_context *base,
rtems_libio_open_close_args_t *args rtems_libio_open_close_args_t *args
) )
@{ @{
my_driver_context *ctx = rtems_termios_get_device_context(tty); my_driver_context *ctx = (my_driver_context *) base;
/* /*
* The driver may do some cleanup here. * The driver may do some cleanup here.
@@ -618,11 +622,11 @@ handler.
@example @example
@group @group
static bool my_driver_set_attributes( static bool my_driver_set_attributes(
rtems_termios_tty *tty, rtems_termios_device_context *base,
const struct termios *term const struct termios *term
) )
@{ @{
my_driver_context *ctx = rtems_termios_get_device_context(tty); my_driver_context *ctx = (my_driver_context *) base;
/* /*
* Inspect the termios data structure and configure the device * Inspect the termios data structure and configure the device

View File

@@ -517,6 +517,11 @@ static void test_termios_cfmakeraw(void)
rtems_test_assert( term.c_cflag & CS8 ); rtems_test_assert( term.c_cflag & CS8 );
} }
typedef struct {
rtems_termios_device_context base;
bool done;
} device_context;
static rtems_status_code test_early_device_install_remove( static rtems_status_code test_early_device_install_remove(
rtems_device_major_number major, rtems_device_major_number major,
rtems_device_minor_number minor, rtems_device_minor_number minor,
@@ -528,7 +533,7 @@ static rtems_status_code test_early_device_install_remove(
rtems_resource_snapshot_take( &snapshot ); rtems_resource_snapshot_take( &snapshot );
sc = rtems_termios_device_install( "/", 0, 0, NULL, NULL ); sc = rtems_termios_device_install( "/", 0, 0, NULL, NULL, NULL );
rtems_test_assert( sc == RTEMS_INCORRECT_STATE ); rtems_test_assert( sc == RTEMS_INCORRECT_STATE );
sc = rtems_termios_device_remove( "/", 0, 0 ); sc = rtems_termios_device_remove( "/", 0, 0 );
@@ -630,14 +635,18 @@ static void test_device_install_remove(void)
static bool first_open_error( static bool first_open_error(
rtems_termios_tty *tty, rtems_termios_tty *tty,
rtems_termios_device_context *base,
struct termios *term,
rtems_libio_open_close_args_t *args rtems_libio_open_close_args_t *args
) )
{ {
bool *done = rtems_termios_get_device_context( tty ); device_context *ctx = (device_context *) base;
(void) tty;
(void) term;
(void) args; (void) args;
*done = true; ctx->done = true;
return false; return false;
} }
@@ -655,7 +664,10 @@ static void test_first_open_error(void)
rtems_status_code sc; rtems_status_code sc;
rtems_libio_t iop; rtems_libio_t iop;
rtems_libio_open_close_args_t args; rtems_libio_open_close_args_t args;
bool done = false; device_context ctx = {
.base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER( "abc" ),
.done = false
};
rtems_resource_snapshot_take( &snapshot ); rtems_resource_snapshot_take( &snapshot );
@@ -665,7 +677,7 @@ static void test_first_open_error(void)
minor, minor,
&handler, &handler,
NULL, NULL,
&done &ctx.base
); );
rtems_test_assert( sc == RTEMS_SUCCESSFUL ); rtems_test_assert( sc == RTEMS_SUCCESSFUL );
@@ -673,10 +685,10 @@ static void test_first_open_error(void)
memset( &args, 0, sizeof( args ) ); memset( &args, 0, sizeof( args ) );
args.iop = &iop; args.iop = &iop;
rtems_test_assert( !done ); rtems_test_assert( !ctx.done );
sc = rtems_termios_device_open( major, minor, &args ); sc = rtems_termios_device_open( major, minor, &args );
rtems_test_assert( sc == RTEMS_NO_MEMORY ); rtems_test_assert( sc == RTEMS_NO_MEMORY );
rtems_test_assert( done ); rtems_test_assert( ctx.done );
sc = rtems_termios_device_remove( &dev[0], major, minor ); sc = rtems_termios_device_remove( &dev[0], major, minor );
rtems_test_assert( sc == RTEMS_SUCCESSFUL ); rtems_test_assert( sc == RTEMS_SUCCESSFUL );
@@ -685,15 +697,15 @@ static void test_first_open_error(void)
} }
static bool set_attributes_error( static bool set_attributes_error(
rtems_termios_tty *tty, rtems_termios_device_context *base,
const struct termios *term const struct termios *term
) )
{ {
bool *done = rtems_termios_get_device_context( tty ); device_context *ctx = (device_context *) base;
(void) term; (void) term;
*done = true; ctx->done = true;
return false; return false;
} }
@@ -713,7 +725,10 @@ static void test_set_attributes_error(void)
rtems_libio_open_close_args_t oc_args; rtems_libio_open_close_args_t oc_args;
rtems_libio_ioctl_args_t io_args; rtems_libio_ioctl_args_t io_args;
struct termios term; struct termios term;
bool done = false; device_context ctx = {
.base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER( "abc" ),
.done = false
};
rtems_resource_snapshot_take( &snapshot ); rtems_resource_snapshot_take( &snapshot );
@@ -723,7 +738,7 @@ static void test_set_attributes_error(void)
minor, minor,
&handler, &handler,
NULL, NULL,
&done &ctx.base
); );
rtems_test_assert( sc == RTEMS_SUCCESSFUL ); rtems_test_assert( sc == RTEMS_SUCCESSFUL );
@@ -739,10 +754,10 @@ static void test_set_attributes_error(void)
io_args.command = RTEMS_IO_SET_ATTRIBUTES; io_args.command = RTEMS_IO_SET_ATTRIBUTES;
io_args.buffer = &term; io_args.buffer = &term;
rtems_test_assert( !done ); rtems_test_assert( !ctx.done );
sc = rtems_termios_ioctl( &io_args ); sc = rtems_termios_ioctl( &io_args );
rtems_test_assert( sc == RTEMS_IO_ERROR ); rtems_test_assert( sc == RTEMS_IO_ERROR );
rtems_test_assert( done ); rtems_test_assert( ctx.done );
sc = rtems_termios_device_close( &oc_args ); sc = rtems_termios_device_close( &oc_args );
rtems_test_assert( sc == RTEMS_SUCCESSFUL ); rtems_test_assert( sc == RTEMS_SUCCESSFUL );
@@ -790,15 +805,14 @@ static void test_set_best_baud(void)
size_t i; size_t i;
for ( i = 0; i < n; ++i ) { for ( i = 0; i < n; ++i ) {
rtems_termios_tty tty; struct termios term;
struct termios *term = rtems_termios_get_termios( &tty );
tcflag_t cbaud_mask = CBAUD; tcflag_t cbaud_mask = CBAUD;
memset( &tty, 0xff, sizeof( tty ) ); memset( &term, 0xff, sizeof( term ) );
rtems_termios_set_best_baud( &tty, baud_to_cflag_table[ i ].baud ); rtems_termios_set_best_baud( &term, baud_to_cflag_table[ i ].baud );
rtems_test_assert( rtems_test_assert(
(term->c_cflag & cbaud_mask) == baud_to_cflag_table[ i ].cflag (term.c_cflag & cbaud_mask) == baud_to_cflag_table[ i ].cflag
); );
} }
} }