summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2014-07-09 11:52:56 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2014-07-09 12:07:49 +0200
commita0fb29fb800bb6954ac0f012df996b2adeeb208d (patch)
tree2caeabbceafac2c7317b035c62a6929cbe2927d5
parenttermios: PR1279: Use set attributes status (diff)
downloadrtems-a0fb29fb800bb6954ac0f012df996b2adeeb208d.tar.bz2
termios: PR1279: Use first open status
-rw-r--r--cpukit/libcsupport/src/termios.c155
-rw-r--r--testsuites/libtests/termios01/init.c50
2 files changed, 132 insertions, 73 deletions
diff --git a/cpukit/libcsupport/src/termios.c b/cpukit/libcsupport/src/termios.c
index b70060dd85..2448ea1068 100644
--- a/cpukit/libcsupport/src/termios.c
+++ b/cpukit/libcsupport/src/termios.c
@@ -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);
}
}
diff --git a/testsuites/libtests/termios01/init.c b/testsuites/libtests/termios01/init.c
index 5010c38a05..896867895d 100644
--- a/testsuites/libtests/termios01/init.c
+++ b/testsuites/libtests/termios01/init.c
@@ -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();