forked from Imagelibrary/rtems
termios: PR2153: New low-level device API
Add a new low-level device API to Termios that passes the TTY structure to the low-level device functions. This greatly simplifies the low-level device drivers since they are no longer forced to derive their private data from the minor number. It makes it possible to use the TTY low-level lock in the device driver low-level functions which is necessary for proper SMP support. For example to set the attributes it is often necessary to perform a read-modify-write operation on a control register used also by interrupt routines. A compatibility layer is provided to support device drivers using the old callback functions so it is not necessary to modify existing device drivers.
This commit is contained in:
@@ -19,6 +19,7 @@
|
||||
#include <rtems.h>
|
||||
#include <rtems/libio.h>
|
||||
#include <rtems/assoc.h>
|
||||
#include <rtems/chain.h>
|
||||
#include <stdint.h>
|
||||
#include <termios.h>
|
||||
|
||||
@@ -52,11 +53,138 @@ struct rtems_termios_rawbuf {
|
||||
volatile unsigned int Size;
|
||||
rtems_id Semaphore;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
TERMIOS_POLLED,
|
||||
TERMIOS_IRQ_DRIVEN,
|
||||
TERMIOS_TASK_DRIVEN
|
||||
} rtems_termios_device_mode;
|
||||
|
||||
struct rtems_termios_tty;
|
||||
|
||||
/**
|
||||
* @brief Termios device handler.
|
||||
*
|
||||
* @see rtems_termios_device_install().
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief First open of this device.
|
||||
*
|
||||
* @param[in] tty The Termios control.
|
||||
* @param[in] args The open/close arguments. This is parameter provided to
|
||||
* support legacy drivers. It must not be used by new drivers.
|
||||
*
|
||||
* @retval true Successful operation.
|
||||
* @retval false Cannot open device.
|
||||
*
|
||||
* @see rtems_termios_get_device_context().
|
||||
*/
|
||||
bool (*first_open)(
|
||||
struct rtems_termios_tty *tty,
|
||||
rtems_libio_open_close_args_t *args
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Last close of this device.
|
||||
*
|
||||
* @param[in] tty The Termios control.
|
||||
* @param[in] args The open/close arguments. This is parameter provided to
|
||||
* support legacy drivers. It must not be used by new drivers.
|
||||
*
|
||||
* @see rtems_termios_get_device_context().
|
||||
*/
|
||||
void (*last_close)(
|
||||
struct rtems_termios_tty *tty,
|
||||
rtems_libio_open_close_args_t *args
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Polled read.
|
||||
*
|
||||
* In case mode is TERMIOS_IRQ_DRIVEN or TERMIOS_TASK_DRIVEN, then data is
|
||||
* received via rtems_termios_enqueue_raw_characters().
|
||||
*
|
||||
* @param[in] tty The Termios control.
|
||||
*
|
||||
* @retval char The received data encoded as unsigned char.
|
||||
* @retval -1 No data currently available.
|
||||
*
|
||||
* @see rtems_termios_get_device_context().
|
||||
*/
|
||||
int (*poll_read)(struct rtems_termios_tty *tty);
|
||||
|
||||
/**
|
||||
* @brief Polled write in case mode is TERMIOS_POLLED or write support
|
||||
* otherwise.
|
||||
*
|
||||
* @param[in] tty The Termios control.
|
||||
* @param[in] buf The output buffer.
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* @brief Set attributes after a Termios settings change.
|
||||
*
|
||||
* @param[in] tty The Termios control.
|
||||
* @param[in] term The new Termios attributes.
|
||||
*
|
||||
* @retval true Successful operation.
|
||||
* @retval false Invalid attributes.
|
||||
*
|
||||
* @see rtems_termios_get_device_context().
|
||||
*/
|
||||
bool (*set_attributes)(
|
||||
struct rtems_termios_tty *tty,
|
||||
const struct termios *term
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Indicate to stop remote transmitter.
|
||||
*
|
||||
* @param[in] tty The Termios control.
|
||||
*
|
||||
* @see rtems_termios_get_device_context().
|
||||
*/
|
||||
void (*stop_remote_tx)(struct rtems_termios_tty *tty);
|
||||
|
||||
/**
|
||||
* @brief Indicate to start remote transmitter.
|
||||
*
|
||||
* @param[in] tty The Termios control.
|
||||
*
|
||||
* @see rtems_termios_get_device_context().
|
||||
*/
|
||||
void (*start_remote_tx)(struct rtems_termios_tty *tty);
|
||||
|
||||
/**
|
||||
* @brief Termios device mode.
|
||||
*/
|
||||
rtems_termios_device_mode mode;
|
||||
} rtems_termios_device_handler;
|
||||
|
||||
/**
|
||||
* @brief Termios device node for installed devices.
|
||||
*
|
||||
* @see rtems_termios_device_install().
|
||||
*/
|
||||
typedef struct rtems_termios_device_node {
|
||||
rtems_chain_node node;
|
||||
rtems_device_major_number major;
|
||||
rtems_device_minor_number minor;
|
||||
const rtems_termios_device_handler *handler;
|
||||
void *context;
|
||||
struct rtems_termios_tty *tty;
|
||||
} rtems_termios_device_node;
|
||||
|
||||
/*
|
||||
* Variables associated with each termios instance.
|
||||
* One structure for each hardware I/O device.
|
||||
*/
|
||||
struct rtems_termios_tty {
|
||||
typedef struct rtems_termios_tty {
|
||||
/*
|
||||
* Linked-list of active TERMIOS devices
|
||||
*/
|
||||
@@ -119,6 +247,12 @@ struct rtems_termios_tty {
|
||||
* Callbacks to device-specific routines
|
||||
*/
|
||||
rtems_termios_callbacks device;
|
||||
|
||||
/**
|
||||
* @brief The device handler.
|
||||
*/
|
||||
rtems_termios_device_handler handler;
|
||||
|
||||
volatile unsigned int flow_ctrl;
|
||||
unsigned int lowwater,highwater;
|
||||
|
||||
@@ -142,7 +276,101 @@ struct rtems_termios_tty {
|
||||
int tty_rcvwakeup;
|
||||
|
||||
rtems_interrupt_lock interrupt_lock;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Corresponding device node.
|
||||
*/
|
||||
rtems_termios_device_node *device_node;
|
||||
|
||||
/**
|
||||
* @brief Context for device driver.
|
||||
*
|
||||
* @see rtems_termios_get_device_context().
|
||||
*/
|
||||
void *device_context;
|
||||
} rtems_termios_tty;
|
||||
|
||||
/**
|
||||
* @brief Installes a Termios device.
|
||||
*
|
||||
* @param[in] device_file If not @c NULL, then a device file for the specified
|
||||
* major and minor number will be created.
|
||||
* @param[in] major The device major number of the corresponding device driver.
|
||||
* @param[in] minor The device minor number of the corresponding device driver.
|
||||
* @param[in] handler The device handler. It must be persistent throughout the
|
||||
* installed time of the device.
|
||||
* @param[in] context The device context. It must be persistent throughout the
|
||||
* installed time of the device.
|
||||
*
|
||||
* @retval RTEMS_SUCCESSFUL Successful operation.
|
||||
* @retval RTEMS_NO_MEMORY Not enough memory to create a device node.
|
||||
* @retval RTEMS_UNSATISFIED Creation of the device file failed.
|
||||
* @retval RTEMS_RESOURCE_IN_USE There exists a device node for this major and
|
||||
* minor number pair.
|
||||
* @retval RTEMS_INCORRECT_STATE Termios is not initialized.
|
||||
*
|
||||
* @see rtems_termios_device_remove(), rtems_termios_device_open(),
|
||||
* rtems_termios_device_close() and rtems_termios_get_device_context().
|
||||
*/
|
||||
rtems_status_code rtems_termios_device_install(
|
||||
const char *device_file,
|
||||
rtems_device_major_number major,
|
||||
rtems_device_minor_number minor,
|
||||
const rtems_termios_device_handler *handler,
|
||||
void *context
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Removes a Termios device.
|
||||
*
|
||||
* @param[in] device_file If not @c NULL, then the device file to remove.
|
||||
* @param[in] major The device major number of the corresponding device driver.
|
||||
* @param[in] minor The device minor number of the corresponding device driver.
|
||||
*
|
||||
* @retval RTEMS_SUCCESSFUL Successful operation.
|
||||
* @retval RTEMS_INVALID_ID There is no device installed with this major and
|
||||
* minor number pair.
|
||||
* @retval RTEMS_RESOURCE_IN_USE This device is currently in use.
|
||||
* @retval RTEMS_UNSATISFIED Removal of the device file failed.
|
||||
* @retval RTEMS_INCORRECT_STATE Termios is not initialized.
|
||||
*
|
||||
* @see rtems_termios_device_install().
|
||||
*/
|
||||
rtems_status_code rtems_termios_device_remove(
|
||||
const char *device_file,
|
||||
rtems_device_major_number major,
|
||||
rtems_device_minor_number minor
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Opens an installed Termios device.
|
||||
*
|
||||
* @see rtems_termios_device_install().
|
||||
*/
|
||||
rtems_status_code rtems_termios_device_open(
|
||||
rtems_device_major_number major,
|
||||
rtems_device_minor_number minor,
|
||||
void *arg
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Closes an installed Termios device.
|
||||
*
|
||||
* @retval RTEMS_SUCCESSFUL Successful operation.
|
||||
*
|
||||
* @see rtems_termios_device_install().
|
||||
*/
|
||||
rtems_status_code rtems_termios_device_close(void *arg);
|
||||
|
||||
/**
|
||||
* @brief Returns the device context of an installed Termios device.
|
||||
*/
|
||||
RTEMS_INLINE_ROUTINE void *rtems_termios_get_device_context(
|
||||
const rtems_termios_tty *tty
|
||||
)
|
||||
{
|
||||
return tty->device_context;
|
||||
}
|
||||
|
||||
struct rtems_termios_linesw {
|
||||
int (*l_open) (struct rtems_termios_tty *tp);
|
||||
@@ -155,14 +383,6 @@ struct rtems_termios_linesw {
|
||||
int (*l_modem)(struct rtems_termios_tty *tp,int flags);
|
||||
};
|
||||
|
||||
/*
|
||||
* FIXME: this should move to libio.h!
|
||||
* values for rtems_termios_callbacks.outputUsesInterrupts
|
||||
*/
|
||||
#define TERMIOS_POLLED 0
|
||||
#define TERMIOS_IRQ_DRIVEN 1
|
||||
#define TERMIOS_TASK_DRIVEN 2
|
||||
|
||||
/*
|
||||
* FIXME: this should move to termios.h!
|
||||
*/
|
||||
|
||||
@@ -85,6 +85,8 @@ static size_t rtems_termios_raw_output_size = 64;
|
||||
static struct rtems_termios_tty *rtems_termios_ttyHead;
|
||||
static struct rtems_termios_tty *rtems_termios_ttyTail;
|
||||
|
||||
static RTEMS_CHAIN_DEFINE_EMPTY(rtems_termios_devices);
|
||||
|
||||
static rtems_task rtems_termios_rxdaemon(rtems_task_argument argument);
|
||||
static rtems_task rtems_termios_txdaemon(rtems_task_argument argument);
|
||||
/*
|
||||
@@ -103,33 +105,196 @@ static rtems_task rtems_termios_txdaemon(rtems_task_argument argument);
|
||||
#define TERMIOS_RX_PROC_EVENT RTEMS_EVENT_1
|
||||
#define TERMIOS_RX_TERMINATE_EVENT RTEMS_EVENT_0
|
||||
|
||||
/*
|
||||
* Open a termios device
|
||||
*/
|
||||
rtems_status_code
|
||||
rtems_termios_open (
|
||||
static rtems_termios_device_node *
|
||||
rtems_termios_find_device_node(
|
||||
rtems_device_major_number major,
|
||||
rtems_device_minor_number minor
|
||||
)
|
||||
{
|
||||
rtems_chain_node *tail = rtems_chain_tail(&rtems_termios_devices);
|
||||
rtems_chain_node *current = rtems_chain_first(&rtems_termios_devices);
|
||||
|
||||
while (current != tail) {
|
||||
rtems_termios_device_node *device_node =
|
||||
(rtems_termios_device_node *) current;
|
||||
|
||||
if (device_node->major == major && device_node->minor == minor) {
|
||||
return device_node;
|
||||
}
|
||||
|
||||
current = rtems_chain_next(current);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rtems_status_code rtems_termios_device_install(
|
||||
const char *device_file,
|
||||
rtems_device_major_number major,
|
||||
rtems_device_minor_number minor,
|
||||
const rtems_termios_device_handler *handler,
|
||||
void *context
|
||||
)
|
||||
{
|
||||
rtems_status_code sc;
|
||||
rtems_termios_device_node *new_device_node;
|
||||
rtems_termios_device_node *existing_device_node;
|
||||
|
||||
new_device_node = malloc(sizeof(*new_device_node));
|
||||
if (new_device_node == NULL) {
|
||||
return RTEMS_NO_MEMORY;
|
||||
}
|
||||
|
||||
new_device_node->major = major;
|
||||
new_device_node->minor = minor;
|
||||
new_device_node->handler = handler;
|
||||
new_device_node->context = context;
|
||||
new_device_node->tty = NULL;
|
||||
|
||||
sc = rtems_semaphore_obtain(
|
||||
rtems_termios_ttyMutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
|
||||
if (sc != RTEMS_SUCCESSFUL) {
|
||||
free(new_device_node);
|
||||
return RTEMS_INCORRECT_STATE;
|
||||
}
|
||||
|
||||
existing_device_node = rtems_termios_find_device_node (major, minor);
|
||||
if (existing_device_node != NULL) {
|
||||
free(new_device_node);
|
||||
rtems_semaphore_release (rtems_termios_ttyMutex);
|
||||
return RTEMS_RESOURCE_IN_USE;
|
||||
}
|
||||
|
||||
if (device_file != NULL) {
|
||||
sc = rtems_io_register_name (device_file, major, minor);
|
||||
if (sc != RTEMS_SUCCESSFUL) {
|
||||
free(new_device_node);
|
||||
rtems_semaphore_release (rtems_termios_ttyMutex);
|
||||
return RTEMS_UNSATISFIED;
|
||||
}
|
||||
}
|
||||
|
||||
rtems_chain_append_unprotected(
|
||||
&rtems_termios_devices, &new_device_node->node);
|
||||
|
||||
rtems_semaphore_release (rtems_termios_ttyMutex);
|
||||
|
||||
return RTEMS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
rtems_status_code rtems_termios_device_remove(
|
||||
const char *device_file,
|
||||
rtems_device_major_number major,
|
||||
rtems_device_minor_number minor
|
||||
)
|
||||
{
|
||||
rtems_status_code sc;
|
||||
rtems_termios_device_node *device_node;
|
||||
|
||||
sc = rtems_semaphore_obtain(
|
||||
rtems_termios_ttyMutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
|
||||
if (sc != RTEMS_SUCCESSFUL) {
|
||||
return RTEMS_INCORRECT_STATE;
|
||||
}
|
||||
|
||||
device_node = rtems_termios_find_device_node (major, minor);
|
||||
if (device_node == NULL) {
|
||||
rtems_semaphore_release (rtems_termios_ttyMutex);
|
||||
return RTEMS_INVALID_ID;
|
||||
}
|
||||
|
||||
if (device_node->tty != NULL) {
|
||||
rtems_semaphore_release (rtems_termios_ttyMutex);
|
||||
return RTEMS_RESOURCE_IN_USE;
|
||||
}
|
||||
|
||||
if (device_file != NULL) {
|
||||
int rv = unlink (device_file);
|
||||
|
||||
if (rv != 0) {
|
||||
rtems_semaphore_release (rtems_termios_ttyMutex);
|
||||
return RTEMS_UNSATISFIED;
|
||||
}
|
||||
}
|
||||
|
||||
rtems_chain_extract_unprotected (&device_node->node);
|
||||
free (device_node);
|
||||
|
||||
rtems_semaphore_release (rtems_termios_ttyMutex);
|
||||
|
||||
return RTEMS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
static bool
|
||||
rtems_termios_callback_firstOpen(
|
||||
rtems_termios_tty *tty,
|
||||
rtems_libio_open_close_args_t *args
|
||||
)
|
||||
{
|
||||
(*tty->device.firstOpen) (tty->major, tty->minor, args);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
rtems_termios_callback_lastClose(
|
||||
rtems_termios_tty *tty,
|
||||
rtems_libio_open_close_args_t *args
|
||||
)
|
||||
{
|
||||
(*tty->device.lastClose) (tty->major, tty->minor, args);
|
||||
}
|
||||
|
||||
static int
|
||||
rtems_termios_callback_pollRead (struct rtems_termios_tty *tty)
|
||||
{
|
||||
return (*tty->device.pollRead) (tty->minor);
|
||||
}
|
||||
|
||||
static void
|
||||
rtems_termios_callback_write(
|
||||
rtems_termios_tty *tty,
|
||||
const char *buf,
|
||||
size_t len
|
||||
)
|
||||
{
|
||||
(*tty->device.write) (tty->minor, buf, len);
|
||||
}
|
||||
|
||||
static bool
|
||||
rtems_termios_callback_setAttributes(
|
||||
rtems_termios_tty *tty,
|
||||
const struct termios *term
|
||||
)
|
||||
{
|
||||
(*tty->device.setAttributes) (tty->minor, term);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
rtems_termios_callback_stopRemoteTx (rtems_termios_tty *tty)
|
||||
{
|
||||
(*tty->device.stopRemoteTx) (tty->minor);
|
||||
}
|
||||
|
||||
static void
|
||||
rtems_termios_callback_startRemoteTx (rtems_termios_tty *tty)
|
||||
{
|
||||
(*tty->device.startRemoteTx) (tty->minor);
|
||||
}
|
||||
|
||||
static rtems_termios_tty *
|
||||
rtems_termios_open_tty(
|
||||
rtems_device_major_number major,
|
||||
rtems_device_minor_number minor,
|
||||
void *arg,
|
||||
rtems_libio_open_close_args_t *args,
|
||||
rtems_termios_tty *tty,
|
||||
rtems_termios_device_node *device_node,
|
||||
const rtems_termios_callbacks *callbacks
|
||||
)
|
||||
{
|
||||
rtems_status_code sc;
|
||||
rtems_libio_open_close_args_t *args = arg;
|
||||
struct rtems_termios_tty *tty;
|
||||
|
||||
/*
|
||||
* See if the device has already been opened
|
||||
*/
|
||||
sc = rtems_semaphore_obtain(
|
||||
rtems_termios_ttyMutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
|
||||
if (sc != RTEMS_SUCCESSFUL)
|
||||
return sc;
|
||||
|
||||
for (tty = rtems_termios_ttyHead ; tty != NULL ; tty = tty->forw) {
|
||||
if ((tty->major == major) && (tty->minor == minor))
|
||||
break;
|
||||
}
|
||||
|
||||
if (tty == NULL) {
|
||||
static char c = 'a';
|
||||
@@ -139,8 +304,7 @@ rtems_termios_open (
|
||||
*/
|
||||
tty = calloc (1, sizeof (struct rtems_termios_tty));
|
||||
if (tty == NULL) {
|
||||
rtems_semaphore_release (rtems_termios_ttyMutex);
|
||||
return RTEMS_NO_MEMORY;
|
||||
return NULL;
|
||||
}
|
||||
/*
|
||||
* allocate raw input buffer
|
||||
@@ -149,8 +313,7 @@ rtems_termios_open (
|
||||
tty->rawInBuf.theBuf = malloc (tty->rawInBuf.Size);
|
||||
if (tty->rawInBuf.theBuf == NULL) {
|
||||
free(tty);
|
||||
rtems_semaphore_release (rtems_termios_ttyMutex);
|
||||
return RTEMS_NO_MEMORY;
|
||||
return NULL;
|
||||
}
|
||||
/*
|
||||
* allocate raw output buffer
|
||||
@@ -160,8 +323,7 @@ rtems_termios_open (
|
||||
if (tty->rawOutBuf.theBuf == NULL) {
|
||||
free((void *)(tty->rawInBuf.theBuf));
|
||||
free(tty);
|
||||
rtems_semaphore_release (rtems_termios_ttyMutex);
|
||||
return RTEMS_NO_MEMORY;
|
||||
return NULL;
|
||||
}
|
||||
/*
|
||||
* allocate cooked buffer
|
||||
@@ -171,8 +333,7 @@ rtems_termios_open (
|
||||
free((void *)(tty->rawOutBuf.theBuf));
|
||||
free((void *)(tty->rawInBuf.theBuf));
|
||||
free(tty);
|
||||
rtems_semaphore_release (rtems_termios_ttyMutex);
|
||||
return RTEMS_NO_MEMORY;
|
||||
return NULL;
|
||||
}
|
||||
/*
|
||||
* Initialize wakeup callbacks
|
||||
@@ -183,17 +344,6 @@ rtems_termios_open (
|
||||
tty->tty_rcv.sw_arg = NULL;
|
||||
tty->tty_rcvwakeup = 0;
|
||||
|
||||
/*
|
||||
* link tty
|
||||
*/
|
||||
tty->forw = rtems_termios_ttyHead;
|
||||
tty->back = NULL;
|
||||
if (rtems_termios_ttyHead != NULL)
|
||||
rtems_termios_ttyHead->back = tty;
|
||||
rtems_termios_ttyHead = tty;
|
||||
if (rtems_termios_ttyTail == NULL)
|
||||
rtems_termios_ttyTail = tty;
|
||||
|
||||
tty->minor = minor;
|
||||
tty->major = major;
|
||||
|
||||
@@ -229,14 +379,39 @@ rtems_termios_open (
|
||||
/*
|
||||
* Set callbacks
|
||||
*/
|
||||
tty->device = *callbacks;
|
||||
if (device_node != NULL) {
|
||||
device_node->tty = tty;
|
||||
tty->handler = *device_node->handler;
|
||||
tty->device_node = device_node;
|
||||
tty->device_context = device_node->context;
|
||||
memset(&tty->device, 0, sizeof(tty->device));
|
||||
} else {
|
||||
tty->handler.first_open = callbacks->firstOpen != NULL ?
|
||||
rtems_termios_callback_firstOpen : NULL;
|
||||
tty->handler.last_close = callbacks->lastClose != NULL ?
|
||||
rtems_termios_callback_lastClose : NULL;
|
||||
tty->handler.poll_read = callbacks->pollRead != NULL ?
|
||||
rtems_termios_callback_pollRead : NULL;
|
||||
tty->handler.write = callbacks->write != NULL ?
|
||||
rtems_termios_callback_write : NULL;
|
||||
tty->handler.set_attributes = callbacks->setAttributes != NULL ?
|
||||
rtems_termios_callback_setAttributes : NULL;
|
||||
tty->handler.stop_remote_tx = callbacks->stopRemoteTx != NULL ?
|
||||
rtems_termios_callback_stopRemoteTx : NULL;
|
||||
tty->handler.start_remote_tx = callbacks->startRemoteTx != NULL ?
|
||||
rtems_termios_callback_startRemoteTx : NULL;
|
||||
tty->handler.mode = callbacks->outputUsesInterrupts;
|
||||
tty->device_context = NULL;
|
||||
tty->device_node = NULL;
|
||||
tty->device = *callbacks;
|
||||
}
|
||||
|
||||
rtems_interrupt_lock_initialize (&tty->interrupt_lock, "Termios");
|
||||
|
||||
/*
|
||||
* Create I/O tasks
|
||||
*/
|
||||
if (tty->device.outputUsesInterrupts == TERMIOS_TASK_DRIVEN) {
|
||||
if (tty->handler.mode == TERMIOS_TASK_DRIVEN) {
|
||||
sc = rtems_task_create (
|
||||
rtems_build_name ('T', 'x', 'T', c),
|
||||
TERMIOS_TXTASK_PRIO,
|
||||
@@ -259,8 +434,8 @@ rtems_termios_open (
|
||||
rtems_fatal_error_occurred (sc);
|
||||
|
||||
}
|
||||
if ((tty->device.pollRead == NULL) ||
|
||||
(tty->device.outputUsesInterrupts == TERMIOS_TASK_DRIVEN)){
|
||||
if ((tty->handler.poll_read == NULL) ||
|
||||
(tty->handler.mode == TERMIOS_TASK_DRIVEN)){
|
||||
sc = rtems_semaphore_create (
|
||||
rtems_build_name ('T', 'R', 'r', c),
|
||||
0,
|
||||
@@ -311,13 +486,13 @@ rtems_termios_open (
|
||||
}
|
||||
args->iop->data1 = tty;
|
||||
if (!tty->refcount++) {
|
||||
if (tty->device.firstOpen)
|
||||
(*tty->device.firstOpen)(major, minor, arg);
|
||||
if (tty->handler.first_open)
|
||||
(*tty->handler.first_open)(tty, args);
|
||||
|
||||
/*
|
||||
* start I/O tasks, if needed
|
||||
*/
|
||||
if (tty->device.outputUsesInterrupts == TERMIOS_TASK_DRIVEN) {
|
||||
if (tty->handler.mode == TERMIOS_TASK_DRIVEN) {
|
||||
sc = rtems_task_start(
|
||||
tty->rxTaskId, rtems_termios_rxdaemon, (rtems_task_argument)tty);
|
||||
if (sc != RTEMS_SUCCESSFUL)
|
||||
@@ -329,7 +504,93 @@ rtems_termios_open (
|
||||
rtems_fatal_error_occurred (sc);
|
||||
}
|
||||
}
|
||||
|
||||
return tty;
|
||||
}
|
||||
|
||||
rtems_status_code
|
||||
rtems_termios_device_open(
|
||||
rtems_device_major_number major,
|
||||
rtems_device_minor_number minor,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
rtems_status_code sc;
|
||||
rtems_termios_device_node *device_node;
|
||||
struct rtems_termios_tty *tty;
|
||||
|
||||
sc = rtems_semaphore_obtain(
|
||||
rtems_termios_ttyMutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
|
||||
if (sc != RTEMS_SUCCESSFUL)
|
||||
return sc;
|
||||
|
||||
device_node = rtems_termios_find_device_node (major, minor);
|
||||
if (device_node == NULL) {
|
||||
rtems_semaphore_release (rtems_termios_ttyMutex);
|
||||
return RTEMS_INVALID_ID;
|
||||
}
|
||||
|
||||
tty = rtems_termios_open_tty(
|
||||
major, minor, arg, device_node->tty, device_node, NULL);
|
||||
if (tty == NULL) {
|
||||
rtems_semaphore_release (rtems_termios_ttyMutex);
|
||||
return RTEMS_NO_MEMORY;
|
||||
}
|
||||
|
||||
rtems_semaphore_release (rtems_termios_ttyMutex);
|
||||
|
||||
return RTEMS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Open a termios device
|
||||
*/
|
||||
rtems_status_code
|
||||
rtems_termios_open (
|
||||
rtems_device_major_number major,
|
||||
rtems_device_minor_number minor,
|
||||
void *arg,
|
||||
const rtems_termios_callbacks *callbacks
|
||||
)
|
||||
{
|
||||
rtems_status_code sc;
|
||||
struct rtems_termios_tty *tty;
|
||||
|
||||
/*
|
||||
* See if the device has already been opened
|
||||
*/
|
||||
sc = rtems_semaphore_obtain(
|
||||
rtems_termios_ttyMutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
|
||||
if (sc != RTEMS_SUCCESSFUL)
|
||||
return sc;
|
||||
|
||||
for (tty = rtems_termios_ttyHead ; tty != NULL ; tty = tty->forw) {
|
||||
if ((tty->major == major) && (tty->minor == minor))
|
||||
break;
|
||||
}
|
||||
|
||||
tty = rtems_termios_open_tty(
|
||||
major, minor, arg, tty, NULL, callbacks);
|
||||
if (tty == NULL) {
|
||||
rtems_semaphore_release (rtems_termios_ttyMutex);
|
||||
return RTEMS_NO_MEMORY;
|
||||
}
|
||||
|
||||
if (tty->refcount == 1) {
|
||||
/*
|
||||
* link tty
|
||||
*/
|
||||
tty->forw = rtems_termios_ttyHead;
|
||||
tty->back = NULL;
|
||||
if (rtems_termios_ttyHead != NULL)
|
||||
rtems_termios_ttyHead->back = tty;
|
||||
rtems_termios_ttyHead = tty;
|
||||
if (rtems_termios_ttyTail == NULL)
|
||||
rtems_termios_ttyTail = tty;
|
||||
}
|
||||
|
||||
rtems_semaphore_release (rtems_termios_ttyMutex);
|
||||
|
||||
return RTEMS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
@@ -342,7 +603,7 @@ drainOutput (struct rtems_termios_tty *tty)
|
||||
rtems_interrupt_lock_context lock_context;
|
||||
rtems_status_code sc;
|
||||
|
||||
if (tty->device.outputUsesInterrupts != TERMIOS_POLLED) {
|
||||
if (tty->handler.mode != TERMIOS_POLLED) {
|
||||
rtems_termios_interrupt_lock_acquire (tty, &lock_context);
|
||||
while (tty->rawOutBuf.Tail != tty->rawOutBuf.Head) {
|
||||
tty->rawOutBufState = rob_wait;
|
||||
@@ -380,17 +641,11 @@ flushInput (struct rtems_termios_tty *tty)
|
||||
rtems_termios_interrupt_lock_release (tty, &lock_context);
|
||||
}
|
||||
|
||||
rtems_status_code
|
||||
rtems_termios_close (void *arg)
|
||||
static void
|
||||
rtems_termios_close_tty (rtems_termios_tty *tty, void *arg)
|
||||
{
|
||||
rtems_libio_open_close_args_t *args = arg;
|
||||
struct rtems_termios_tty *tty = args->iop->data1;
|
||||
rtems_status_code sc;
|
||||
|
||||
sc = rtems_semaphore_obtain(
|
||||
rtems_termios_ttyMutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
|
||||
if (sc != RTEMS_SUCCESSFUL)
|
||||
rtems_fatal_error_occurred (sc);
|
||||
if (--tty->refcount == 0) {
|
||||
if (rtems_termios_linesw[tty->t_line].l_close != NULL) {
|
||||
/*
|
||||
@@ -409,7 +664,7 @@ rtems_termios_close (void *arg)
|
||||
rtems_semaphore_release (tty->osem);
|
||||
}
|
||||
|
||||
if (tty->device.outputUsesInterrupts == TERMIOS_TASK_DRIVEN) {
|
||||
if (tty->handler.mode == TERMIOS_TASK_DRIVEN) {
|
||||
/*
|
||||
* send "terminate" to I/O tasks
|
||||
*/
|
||||
@@ -420,8 +675,39 @@ rtems_termios_close (void *arg)
|
||||
if (sc != RTEMS_SUCCESSFUL)
|
||||
rtems_fatal_error_occurred (sc);
|
||||
}
|
||||
if (tty->device.lastClose)
|
||||
(*tty->device.lastClose)(tty->major, tty->minor, arg);
|
||||
if (tty->handler.last_close)
|
||||
(*tty->handler.last_close)(tty, arg);
|
||||
|
||||
if (tty->device_node != NULL)
|
||||
tty->device_node->tty = NULL;
|
||||
|
||||
rtems_semaphore_delete (tty->isem);
|
||||
rtems_semaphore_delete (tty->osem);
|
||||
rtems_semaphore_delete (tty->rawOutBuf.Semaphore);
|
||||
if ((tty->handler.poll_read == NULL) ||
|
||||
(tty->handler.mode == TERMIOS_TASK_DRIVEN))
|
||||
rtems_semaphore_delete (tty->rawInBuf.Semaphore);
|
||||
rtems_interrupt_lock_destroy (&tty->interrupt_lock);
|
||||
free (tty->rawInBuf.theBuf);
|
||||
free (tty->rawOutBuf.theBuf);
|
||||
free (tty->cbuf);
|
||||
free (tty);
|
||||
}
|
||||
}
|
||||
|
||||
rtems_status_code
|
||||
rtems_termios_close (void *arg)
|
||||
{
|
||||
rtems_status_code sc;
|
||||
rtems_libio_open_close_args_t *args = arg;
|
||||
struct rtems_termios_tty *tty = args->iop->data1;
|
||||
|
||||
sc = rtems_semaphore_obtain(
|
||||
rtems_termios_ttyMutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
|
||||
if (sc != RTEMS_SUCCESSFUL)
|
||||
rtems_fatal_error_occurred (sc);
|
||||
|
||||
if (tty->refcount == 1) {
|
||||
if (tty->forw == NULL) {
|
||||
rtems_termios_ttyTail = tty->back;
|
||||
if ( rtems_termios_ttyTail != NULL ) {
|
||||
@@ -439,20 +725,31 @@ rtems_termios_close (void *arg)
|
||||
} else {
|
||||
tty->back->forw = tty->forw;
|
||||
}
|
||||
|
||||
rtems_semaphore_delete (tty->isem);
|
||||
rtems_semaphore_delete (tty->osem);
|
||||
rtems_semaphore_delete (tty->rawOutBuf.Semaphore);
|
||||
if ((tty->device.pollRead == NULL) ||
|
||||
(tty->device.outputUsesInterrupts == TERMIOS_TASK_DRIVEN))
|
||||
rtems_semaphore_delete (tty->rawInBuf.Semaphore);
|
||||
rtems_interrupt_lock_destroy (&tty->interrupt_lock);
|
||||
free (tty->rawInBuf.theBuf);
|
||||
free (tty->rawOutBuf.theBuf);
|
||||
free (tty->cbuf);
|
||||
free (tty);
|
||||
}
|
||||
|
||||
rtems_termios_close_tty (tty, arg);
|
||||
|
||||
rtems_semaphore_release (rtems_termios_ttyMutex);
|
||||
|
||||
return RTEMS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
rtems_status_code
|
||||
rtems_termios_device_close (void *arg)
|
||||
{
|
||||
rtems_status_code sc;
|
||||
rtems_libio_open_close_args_t *args = arg;
|
||||
struct rtems_termios_tty *tty = args->iop->data1;
|
||||
|
||||
sc = rtems_semaphore_obtain(
|
||||
rtems_termios_ttyMutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
|
||||
if (sc != RTEMS_SUCCESSFUL)
|
||||
rtems_fatal_error_occurred (sc);
|
||||
|
||||
rtems_termios_close_tty (tty, arg);
|
||||
|
||||
rtems_semaphore_release (rtems_termios_ttyMutex);
|
||||
|
||||
return RTEMS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
@@ -490,8 +787,8 @@ termios_set_flowctrl(struct rtems_termios_tty *tty)
|
||||
/* check for chars in output buffer (or rob_state?) */
|
||||
if (tty->rawOutBufState != rob_idle) {
|
||||
/* if chars available, call write function... */
|
||||
(*tty->device.write)(
|
||||
tty->minor, &tty->rawOutBuf.theBuf[tty->rawOutBuf.Tail],1);
|
||||
(*tty->handler.write)(
|
||||
tty, &tty->rawOutBuf.theBuf[tty->rawOutBuf.Tail],1);
|
||||
}
|
||||
/* reenable interrupts */
|
||||
rtems_termios_interrupt_lock_release (tty, &lock_context);
|
||||
@@ -511,8 +808,9 @@ termios_set_flowctrl(struct rtems_termios_tty *tty)
|
||||
tty->flow_ctrl &= ~(FL_MDRTS);
|
||||
|
||||
/* restart remote Tx, if it was stopped */
|
||||
if ((tty->flow_ctrl & FL_IRTSOFF) && (tty->device.startRemoteTx != NULL)) {
|
||||
tty->device.startRemoteTx(tty->minor);
|
||||
if ((tty->flow_ctrl & FL_IRTSOFF) &&
|
||||
(tty->handler.start_remote_tx != NULL)) {
|
||||
tty->handler.start_remote_tx(tty);
|
||||
}
|
||||
tty->flow_ctrl &= ~(FL_IRTSOFF);
|
||||
}
|
||||
@@ -591,8 +889,8 @@ rtems_termios_ioctl (void *arg)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (tty->device.setAttributes)
|
||||
(*tty->device.setAttributes)(tty->minor, &tty->termios);
|
||||
if (tty->handler.set_attributes)
|
||||
(*tty->handler.set_attributes)(tty, &tty->termios);
|
||||
break;
|
||||
|
||||
case RTEMS_IO_TCDRAIN:
|
||||
@@ -676,8 +974,8 @@ rtems_termios_puts (
|
||||
rtems_interrupt_lock_context lock_context;
|
||||
rtems_status_code sc;
|
||||
|
||||
if (tty->device.outputUsesInterrupts == TERMIOS_POLLED) {
|
||||
(*tty->device.write)(tty->minor, buf, len);
|
||||
if (tty->handler.mode == TERMIOS_POLLED) {
|
||||
(*tty->handler.write)(tty, buf, len);
|
||||
return;
|
||||
}
|
||||
newHead = tty->rawOutBuf.Head;
|
||||
@@ -710,8 +1008,8 @@ rtems_termios_puts (
|
||||
if (tty->rawOutBufState == rob_idle) {
|
||||
/* check, whether XOFF has been received */
|
||||
if (!(tty->flow_ctrl & FL_ORCVXOF)) {
|
||||
(*tty->device.write)(
|
||||
tty->minor, &tty->rawOutBuf.theBuf[tty->rawOutBuf.Tail],1);
|
||||
(*tty->handler.write)(
|
||||
tty, &tty->rawOutBuf.theBuf[tty->rawOutBuf.Tail],1);
|
||||
} else {
|
||||
/* remember that output has been stopped due to flow ctrl*/
|
||||
tty->flow_ctrl |= FL_OSTOP;
|
||||
@@ -997,7 +1295,7 @@ fillBufferPoll (struct rtems_termios_tty *tty)
|
||||
|
||||
if (tty->termios.c_lflag & ICANON) {
|
||||
for (;;) {
|
||||
n = (*tty->device.pollRead)(tty->minor);
|
||||
n = (*tty->handler.poll_read)(tty);
|
||||
if (n < 0) {
|
||||
rtems_task_wake_after (1);
|
||||
} else {
|
||||
@@ -1010,7 +1308,7 @@ fillBufferPoll (struct rtems_termios_tty *tty)
|
||||
|
||||
then = rtems_clock_get_ticks_since_boot();
|
||||
for (;;) {
|
||||
n = (*tty->device.pollRead)(tty->minor);
|
||||
n = (*tty->handler.poll_read)(tty);
|
||||
if (n < 0) {
|
||||
if (tty->termios.c_cc[VMIN]) {
|
||||
if (tty->termios.c_cc[VTIME] && tty->ccount) {
|
||||
@@ -1072,13 +1370,13 @@ fillBufferQueue (struct rtems_termios_tty *tty)
|
||||
&& ((tty->rawOutBufState == rob_idle)
|
||||
|| (tty->flow_ctrl & FL_OSTOP))) {
|
||||
/* XON should be sent now... */
|
||||
(*tty->device.write)(
|
||||
tty->minor, (void *)&(tty->termios.c_cc[VSTART]), 1);
|
||||
(*tty->handler.write)(
|
||||
tty, (void *)&(tty->termios.c_cc[VSTART]), 1);
|
||||
} else if (tty->flow_ctrl & FL_MDRTS) {
|
||||
tty->flow_ctrl &= ~FL_IRTSOFF;
|
||||
/* activate RTS line */
|
||||
if (tty->device.startRemoteTx != NULL) {
|
||||
tty->device.startRemoteTx(tty->minor);
|
||||
if (tty->handler.start_remote_tx != NULL) {
|
||||
tty->handler.start_remote_tx(tty);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1131,8 +1429,7 @@ rtems_termios_read (void *arg)
|
||||
if (tty->cindex == tty->ccount) {
|
||||
tty->cindex = tty->ccount = 0;
|
||||
tty->read_start_column = tty->column;
|
||||
if (tty->device.pollRead != NULL &&
|
||||
tty->device.outputUsesInterrupts == TERMIOS_POLLED)
|
||||
if (tty->handler.poll_read != NULL && tty->handler.mode == TERMIOS_POLLED)
|
||||
sc = fillBufferPoll (tty);
|
||||
else
|
||||
sc = fillBufferQueue (tty);
|
||||
@@ -1230,8 +1527,8 @@ rtems_termios_enqueue_raw_characters (void *ttyp, const char *buf, int len)
|
||||
/* check for chars in output buffer (or rob_state?) */
|
||||
if (tty->rawOutBufState != rob_idle) {
|
||||
/* if chars available, call write function... */
|
||||
(*tty->device.write)(
|
||||
tty->minor, &tty->rawOutBuf.theBuf[tty->rawOutBuf.Tail], 1);
|
||||
(*tty->handler.write)(
|
||||
tty, &tty->rawOutBuf.theBuf[tty->rawOutBuf.Tail], 1);
|
||||
}
|
||||
/* reenable interrupts */
|
||||
rtems_termios_interrupt_lock_release (tty, &lock_context);
|
||||
@@ -1252,14 +1549,14 @@ rtems_termios_enqueue_raw_characters (void *ttyp, const char *buf, int len)
|
||||
/* if tx is stopped due to XOFF or out of data */
|
||||
/* call write function here */
|
||||
tty->flow_ctrl |= FL_ISNTXOF;
|
||||
(*tty->device.write)(tty->minor,
|
||||
(*tty->handler.write)(tty,
|
||||
(void *)&(tty->termios.c_cc[VSTOP]), 1);
|
||||
}
|
||||
} else if ((tty->flow_ctrl & (FL_MDRTS | FL_IRTSOFF)) == (FL_MDRTS) ) {
|
||||
tty->flow_ctrl |= FL_IRTSOFF;
|
||||
/* deactivate RTS line */
|
||||
if (tty->device.stopRemoteTx != NULL) {
|
||||
tty->device.stopRemoteTx(tty->minor);
|
||||
if (tty->handler.stop_remote_tx != NULL) {
|
||||
tty->handler.stop_remote_tx(tty);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1308,7 +1605,7 @@ rtems_termios_refill_transmitter (struct rtems_termios_tty *tty)
|
||||
if ((tty->flow_ctrl & (FL_MDXOF | FL_IREQXOF | FL_ISNTXOF))
|
||||
== (FL_MDXOF | FL_IREQXOF)) {
|
||||
/* XOFF should be sent now... */
|
||||
(*tty->device.write)(tty->minor, (void *)&(tty->termios.c_cc[VSTOP]), 1);
|
||||
(*tty->handler.write)(tty, (void *)&(tty->termios.c_cc[VSTOP]), 1);
|
||||
|
||||
tty->t_dqlen--;
|
||||
tty->flow_ctrl |= FL_ISNTXOF;
|
||||
@@ -1324,7 +1621,7 @@ rtems_termios_refill_transmitter (struct rtems_termios_tty *tty)
|
||||
* buffer, although the corresponding data is not yet out!
|
||||
* Therefore the dequeue "length" should be reduced by 1
|
||||
*/
|
||||
(*tty->device.write)(tty->minor, (void *)&(tty->termios.c_cc[VSTART]), 1);
|
||||
(*tty->handler.write)(tty, (void *)&(tty->termios.c_cc[VSTART]), 1);
|
||||
|
||||
tty->t_dqlen--;
|
||||
tty->flow_ctrl &= ~FL_ISNTXOF;
|
||||
@@ -1341,7 +1638,7 @@ rtems_termios_refill_transmitter (struct rtems_termios_tty *tty)
|
||||
wakeUpWriterTask = true;
|
||||
}
|
||||
|
||||
(*tty->device.write) (tty->minor, NULL, 0);
|
||||
(*tty->handler.write) (tty, NULL, 0);
|
||||
nToSend = 0;
|
||||
} else {
|
||||
len = tty->t_dqlen;
|
||||
@@ -1361,7 +1658,7 @@ rtems_termios_refill_transmitter (struct rtems_termios_tty *tty)
|
||||
* Buffer has become empty
|
||||
*/
|
||||
tty->rawOutBufState = rob_idle;
|
||||
(*tty->device.write) (tty->minor, NULL, 0);
|
||||
(*tty->handler.write) (tty, NULL, 0);
|
||||
nToSend = 0;
|
||||
|
||||
/*
|
||||
@@ -1378,7 +1675,7 @@ rtems_termios_refill_transmitter (struct rtems_termios_tty *tty)
|
||||
/* set flag, that output has been stopped */
|
||||
tty->flow_ctrl |= FL_OSTOP;
|
||||
tty->rawOutBufState = rob_busy; /*apm*/
|
||||
(*tty->device.write) (tty->minor, NULL, 0);
|
||||
(*tty->handler.write) (tty, NULL, 0);
|
||||
nToSend = 0;
|
||||
} else {
|
||||
/*
|
||||
@@ -1395,8 +1692,8 @@ rtems_termios_refill_transmitter (struct rtems_termios_tty *tty)
|
||||
nToSend = 1;
|
||||
}
|
||||
tty->rawOutBufState = rob_busy; /*apm*/
|
||||
(*tty->device.write)(
|
||||
tty->minor, &tty->rawOutBuf.theBuf[newTail], nToSend);
|
||||
(*tty->handler.write)(
|
||||
tty, &tty->rawOutBuf.theBuf[newTail], nToSend);
|
||||
}
|
||||
tty->rawOutBuf.Tail = newTail; /*apm*/
|
||||
}
|
||||
@@ -1430,7 +1727,7 @@ rtems_termios_dequeue_characters (void *ttyp, int len)
|
||||
*/
|
||||
tty->t_dqlen += len;
|
||||
|
||||
if (tty->device.outputUsesInterrupts == TERMIOS_TASK_DRIVEN) {
|
||||
if (tty->handler.mode == TERMIOS_TASK_DRIVEN) {
|
||||
/*
|
||||
* send wake up to transmitter task
|
||||
*/
|
||||
@@ -1518,10 +1815,10 @@ static rtems_task rtems_termios_rxdaemon(rtems_task_argument argument)
|
||||
/*
|
||||
* do something
|
||||
*/
|
||||
c = tty->device.pollRead(tty->minor);
|
||||
c = tty->handler.poll_read(tty);
|
||||
if (c != EOF) {
|
||||
/*
|
||||
* pollRead did call enqueue on its own
|
||||
* poll_read did call enqueue on its own
|
||||
*/
|
||||
c_buf = c;
|
||||
rtems_termios_enqueue_raw_characters ( tty,&c_buf,1);
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
|
||||
#include "tmacros.h"
|
||||
#include <termios.h>
|
||||
#include <rtems/libcsupport.h>
|
||||
#include <rtems/malloc.h>
|
||||
#include <rtems/termiostypes.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
@@ -515,6 +517,94 @@ static void test_termios_cfmakeraw(void)
|
||||
rtems_test_assert( term.c_cflag & CS8 );
|
||||
}
|
||||
|
||||
static void test_early_device_install_remove(
|
||||
rtems_device_major_number major,
|
||||
rtems_device_minor_number minor,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
rtems_resource_snapshot snapshot;
|
||||
rtems_status_code sc;
|
||||
|
||||
rtems_resource_snapshot_take( &snapshot );
|
||||
|
||||
sc = rtems_termios_device_install( "/", 0, 0, NULL, NULL );
|
||||
rtems_test_assert( sc == RTEMS_INCORRECT_STATE );
|
||||
|
||||
sc = rtems_termios_device_remove( "/", 0, 0 );
|
||||
rtems_test_assert( sc == RTEMS_INCORRECT_STATE );
|
||||
|
||||
rtems_test_assert( rtems_resource_snapshot_check( &snapshot ) );
|
||||
}
|
||||
|
||||
static void test_device_install_remove(void)
|
||||
{
|
||||
static const rtems_termios_device_handler handler;
|
||||
static const rtems_device_major_number major = 123456789;
|
||||
static const rtems_device_minor_number minor = 0xdeadbeef;
|
||||
static const char dev[] = "/foobar";
|
||||
|
||||
rtems_resource_snapshot snapshot;
|
||||
rtems_status_code sc;
|
||||
void *greedy;
|
||||
rtems_libio_t iop;
|
||||
rtems_libio_open_close_args_t args;
|
||||
|
||||
memset( &iop, 0, sizeof( iop ) );
|
||||
memset( &args, 0, sizeof( args ) );
|
||||
args.iop = &iop;
|
||||
|
||||
rtems_resource_snapshot_take( &snapshot );
|
||||
|
||||
greedy = rtems_heap_greedy_allocate( NULL, 0 );
|
||||
|
||||
sc = rtems_termios_device_install( "/", major, minor, &handler, NULL );
|
||||
rtems_test_assert( sc == RTEMS_NO_MEMORY );
|
||||
|
||||
rtems_heap_greedy_free( greedy );
|
||||
|
||||
rtems_test_assert( rtems_resource_snapshot_check( &snapshot ) );
|
||||
|
||||
sc = rtems_termios_device_install( NULL, major, minor, &handler, NULL );
|
||||
rtems_test_assert( sc == RTEMS_SUCCESSFUL );
|
||||
|
||||
sc = rtems_termios_device_install( NULL, major, minor, &handler, NULL );
|
||||
rtems_test_assert( sc == RTEMS_RESOURCE_IN_USE );
|
||||
|
||||
sc = rtems_termios_device_remove( NULL, major, minor );
|
||||
rtems_test_assert( sc == RTEMS_SUCCESSFUL );
|
||||
|
||||
rtems_test_assert( rtems_resource_snapshot_check( &snapshot ) );
|
||||
|
||||
sc = rtems_termios_device_install( "/", major, minor, &handler, NULL );
|
||||
rtems_test_assert( sc == RTEMS_UNSATISFIED );
|
||||
|
||||
rtems_test_assert( rtems_resource_snapshot_check( &snapshot ) );
|
||||
|
||||
sc = rtems_termios_device_remove( NULL, major, minor );
|
||||
rtems_test_assert( sc == RTEMS_INVALID_ID );
|
||||
|
||||
sc = rtems_termios_device_install( &dev[0], major, minor, &handler, NULL );
|
||||
rtems_test_assert( sc == RTEMS_SUCCESSFUL );
|
||||
|
||||
sc = rtems_termios_device_remove( "/barfoo", major, minor );
|
||||
rtems_test_assert( sc == RTEMS_UNSATISFIED );
|
||||
|
||||
sc = rtems_termios_device_open( major, minor, &args );
|
||||
rtems_test_assert( sc == RTEMS_SUCCESSFUL );
|
||||
|
||||
sc = rtems_termios_device_remove( &dev[0], major, minor );
|
||||
rtems_test_assert( sc == RTEMS_RESOURCE_IN_USE );
|
||||
|
||||
sc = rtems_termios_device_close( &args );
|
||||
rtems_test_assert( sc == RTEMS_SUCCESSFUL );
|
||||
|
||||
sc = rtems_termios_device_remove( &dev[0], major, minor );
|
||||
rtems_test_assert( sc == RTEMS_SUCCESSFUL );
|
||||
|
||||
rtems_test_assert( rtems_resource_snapshot_check( &snapshot ) );
|
||||
}
|
||||
|
||||
static rtems_task Init(
|
||||
rtems_task_argument ignored
|
||||
)
|
||||
@@ -668,17 +758,22 @@ static rtems_task Init(
|
||||
}
|
||||
puts( "" );
|
||||
|
||||
test_device_install_remove();
|
||||
|
||||
TEST_END();
|
||||
rtems_test_exit(0);
|
||||
}
|
||||
|
||||
/* configuration information */
|
||||
|
||||
#define CONFIGURE_APPLICATION_PREREQUISITE_DRIVERS \
|
||||
{ .initialization_entry = test_early_device_install_remove }
|
||||
|
||||
#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
|
||||
#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
|
||||
|
||||
/* include an extra slot for registering the termios one dynamically */
|
||||
#define CONFIGURE_MAXIMUM_DRIVERS 3
|
||||
#define CONFIGURE_MAXIMUM_DRIVERS 4
|
||||
|
||||
/* one for the console and one for the test port */
|
||||
#define CONFIGURE_NUMBER_OF_TERMIOS_PORTS 3
|
||||
|
||||
@@ -24,8 +24,13 @@ directives:
|
||||
cfsetspeed
|
||||
cfsetispeed
|
||||
cfsetospeed
|
||||
rtems_termios_device_install
|
||||
rtems_termios_device_remove
|
||||
rtems_termios_device_open
|
||||
rtems_termios_device_close
|
||||
|
||||
concepts:
|
||||
|
||||
+ Exercise termios ioctl for all baud, character size, parity and
|
||||
bits per character options.
|
||||
+ Ensure that Termios device install/remove works.
|
||||
|
||||
Reference in New Issue
Block a user