termios: PR1279: Use first open status

This commit is contained in:
Sebastian Huber
2014-07-09 12:07:49 +02:00
parent 32fc6a3490
commit a0fb29fb80
2 changed files with 132 additions and 73 deletions
+82 -73
View File
@@ -284,6 +284,82 @@ rtems_termios_callback_startRemoteTx (rtems_termios_tty *tty)
(*tty->device.startRemoteTx) (tty->minor);
}
/*
* Drain output queue
*/
static void
drainOutput (struct rtems_termios_tty *tty)
{
rtems_interrupt_lock_context lock_context;
rtems_status_code sc;
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;
rtems_termios_interrupt_lock_release (tty, &lock_context);
sc = rtems_semaphore_obtain(
tty->rawOutBuf.Semaphore, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
if (sc != RTEMS_SUCCESSFUL)
rtems_fatal_error_occurred (sc);
rtems_termios_interrupt_lock_acquire (tty, &lock_context);
}
rtems_termios_interrupt_lock_release (tty, &lock_context);
}
}
static void
rtems_termios_destroy_tty (rtems_termios_tty *tty, void *arg, bool last_close)
{
rtems_status_code sc;
if (rtems_termios_linesw[tty->t_line].l_close != NULL) {
/*
* call discipline-specific close
*/
sc = rtems_termios_linesw[tty->t_line].l_close(tty);
} else if (last_close) {
/*
* default: just flush output buffer
*/
sc = rtems_semaphore_obtain(tty->osem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
if (sc != RTEMS_SUCCESSFUL) {
rtems_fatal_error_occurred (sc);
}
drainOutput (tty);
rtems_semaphore_release (tty->osem);
}
if (tty->handler.mode == TERMIOS_TASK_DRIVEN) {
/*
* send "terminate" to I/O tasks
*/
sc = rtems_event_send( tty->rxTaskId, TERMIOS_RX_TERMINATE_EVENT );
if (sc != RTEMS_SUCCESSFUL)
rtems_fatal_error_occurred (sc);
sc = rtems_event_send( tty->txTaskId, TERMIOS_TX_TERMINATE_EVENT );
if (sc != RTEMS_SUCCESSFUL)
rtems_fatal_error_occurred (sc);
}
if (last_close && 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);
}
static rtems_termios_tty *
rtems_termios_open_tty(
rtems_device_major_number major,
@@ -486,8 +562,11 @@ rtems_termios_open_tty(
}
args->iop->data1 = tty;
if (!tty->refcount++) {
if (tty->handler.first_open)
(*tty->handler.first_open)(tty, args);
if (tty->handler.first_open &&
!(*tty->handler.first_open)(tty, args)) {
rtems_termios_destroy_tty(tty, args, false);
return NULL;
}
/*
* start I/O tasks, if needed
@@ -594,30 +673,6 @@ rtems_termios_open (
return RTEMS_SUCCESSFUL;
}
/*
* Drain output queue
*/
static void
drainOutput (struct rtems_termios_tty *tty)
{
rtems_interrupt_lock_context lock_context;
rtems_status_code sc;
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;
rtems_termios_interrupt_lock_release (tty, &lock_context);
sc = rtems_semaphore_obtain(
tty->rawOutBuf.Semaphore, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
if (sc != RTEMS_SUCCESSFUL)
rtems_fatal_error_occurred (sc);
rtems_termios_interrupt_lock_acquire (tty, &lock_context);
}
rtems_termios_interrupt_lock_release (tty, &lock_context);
}
}
static void
flushOutput (struct rtems_termios_tty *tty)
{
@@ -644,54 +699,8 @@ flushInput (struct rtems_termios_tty *tty)
static void
rtems_termios_close_tty (rtems_termios_tty *tty, void *arg)
{
rtems_status_code sc;
if (--tty->refcount == 0) {
if (rtems_termios_linesw[tty->t_line].l_close != NULL) {
/*
* call discipline-specific close
*/
sc = rtems_termios_linesw[tty->t_line].l_close(tty);
} else {
/*
* default: just flush output buffer
*/
sc = rtems_semaphore_obtain(tty->osem, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
if (sc != RTEMS_SUCCESSFUL) {
rtems_fatal_error_occurred (sc);
}
drainOutput (tty);
rtems_semaphore_release (tty->osem);
}
if (tty->handler.mode == TERMIOS_TASK_DRIVEN) {
/*
* send "terminate" to I/O tasks
*/
sc = rtems_event_send( tty->rxTaskId, TERMIOS_RX_TERMINATE_EVENT );
if (sc != RTEMS_SUCCESSFUL)
rtems_fatal_error_occurred (sc);
sc = rtems_event_send( tty->txTaskId, TERMIOS_TX_TERMINATE_EVENT );
if (sc != RTEMS_SUCCESSFUL)
rtems_fatal_error_occurred (sc);
}
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_termios_destroy_tty (tty, arg, true);
}
}
+50
View File
@@ -605,6 +605,55 @@ static void test_device_install_remove(void)
rtems_test_assert( rtems_resource_snapshot_check( &snapshot ) );
}
static bool first_open_error(
rtems_termios_tty *tty,
rtems_libio_open_close_args_t *args
)
{
bool *done = rtems_termios_get_device_context( tty );
(void) args;
*done = true;
return false;
}
static void test_first_open_error(void)
{
static const rtems_termios_device_handler handler = {
.first_open = first_open_error
};
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;
rtems_libio_t iop;
rtems_libio_open_close_args_t args;
bool done = false;
rtems_resource_snapshot_take( &snapshot );
sc = rtems_termios_device_install( &dev[0], major, minor, &handler, &done );
rtems_test_assert( sc == RTEMS_SUCCESSFUL );
memset( &iop, 0, sizeof( iop ) );
memset( &args, 0, sizeof( args ) );
args.iop = &iop;
rtems_test_assert( !done );
sc = rtems_termios_device_open( major, minor, &args );
rtems_test_assert( sc == RTEMS_NO_MEMORY );
rtems_test_assert( done );
sc = rtems_termios_device_remove( &dev[0], major, minor );
rtems_test_assert( sc == RTEMS_SUCCESSFUL );
rtems_test_assert( rtems_resource_snapshot_check( &snapshot ) );
}
static bool set_attributes_error(
rtems_termios_tty *tty,
const struct termios *term
@@ -821,6 +870,7 @@ static rtems_task Init(
puts( "" );
test_device_install_remove();
test_first_open_error();
test_set_attributes_error();
TEST_END();