File indexing completed on 2025-05-11 08:24:15
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #ifdef HAVE_CONFIG_H
0015 #include "config.h"
0016 #endif
0017
0018 #include <rtems.h>
0019 #include <rtems/libio.h>
0020 #include <rtems/imfs.h>
0021 #include <rtems/score/assert.h>
0022 #include <ctype.h>
0023 #include <errno.h>
0024 #include <stdio.h>
0025 #include <stdlib.h>
0026 #include <string.h>
0027 #include <termios.h>
0028 #include <unistd.h>
0029 #include <sys/fcntl.h>
0030 #include <sys/filio.h>
0031 #include <sys/ttycom.h>
0032
0033 #include <rtems/termiostypes.h>
0034
0035
0036
0037
0038 #define CBUFSIZE (rtems_termios_cbufsize)
0039
0040
0041
0042
0043
0044
0045 #define RAW_INPUT_BUFFER_SIZE (rtems_termios_raw_input_size)
0046 #define RAW_OUTPUT_BUFFER_SIZE (rtems_termios_raw_output_size)
0047
0048
0049 #define FL_IREQXOF 1U
0050 #define FL_ISNTXOF 2U
0051 #define FL_IRTSOFF 4U
0052
0053 #define FL_ORCVXOF 0x10U
0054 #define FL_OSTOP 0x20U
0055
0056 #define FL_MDRTS 0x100U
0057 #define FL_MDXON 0x200U
0058 #define FL_MDXOF 0x400U
0059
0060 #define NODISC(n) \
0061 { NULL, NULL, NULL, NULL, \
0062 NULL, NULL, NULL, NULL }
0063
0064
0065
0066
0067 struct rtems_termios_linesw rtems_termios_linesw[MAXLDISC] =
0068 {
0069 NODISC(0),
0070 NODISC(1),
0071 NODISC(2),
0072 NODISC(3),
0073 NODISC(4),
0074 NODISC(5),
0075 NODISC(6),
0076 NODISC(7),
0077 };
0078
0079 int rtems_termios_nlinesw =
0080 sizeof (rtems_termios_linesw) / sizeof (rtems_termios_linesw[0]);
0081
0082 static size_t rtems_termios_cbufsize = 256;
0083 static size_t rtems_termios_raw_input_size = 256;
0084 static size_t rtems_termios_raw_output_size = 64;
0085
0086 static const IMFS_node_control rtems_termios_imfs_node_control;
0087
0088 static struct rtems_termios_tty *rtems_termios_ttyHead;
0089 static struct rtems_termios_tty *rtems_termios_ttyTail;
0090
0091 static RTEMS_CHAIN_DEFINE_EMPTY(rtems_termios_devices);
0092
0093 static rtems_task rtems_termios_rxdaemon(rtems_task_argument argument);
0094 static rtems_task rtems_termios_txdaemon(rtems_task_argument argument);
0095
0096
0097
0098 #define TERMIOS_TXTASK_PRIO 10
0099 #define TERMIOS_RXTASK_PRIO 9
0100 #define TERMIOS_TXTASK_STACKSIZE 1024
0101 #define TERMIOS_RXTASK_STACKSIZE 1024
0102
0103
0104
0105 #define TERMIOS_TX_START_EVENT RTEMS_EVENT_1
0106 #define TERMIOS_TX_TERMINATE_EVENT RTEMS_EVENT_0
0107
0108 #define TERMIOS_RX_PROC_EVENT RTEMS_EVENT_1
0109 #define TERMIOS_RX_TERMINATE_EVENT RTEMS_EVENT_0
0110
0111 static rtems_mutex rtems_termios_ttyMutex =
0112 RTEMS_MUTEX_INITIALIZER( "termios" );
0113
0114 static void
0115 rtems_termios_obtain (void)
0116 {
0117 rtems_mutex_lock (&rtems_termios_ttyMutex);
0118 }
0119
0120 static void
0121 rtems_termios_release (void)
0122 {
0123 rtems_mutex_unlock (&rtems_termios_ttyMutex);
0124 }
0125
0126 rtems_status_code rtems_termios_device_install(
0127 const char *device_file,
0128 const rtems_termios_device_handler *handler,
0129 const rtems_termios_device_flow *flow,
0130 rtems_termios_device_context *context
0131 )
0132 {
0133 rtems_termios_device_node *new_device_node;
0134 int rv;
0135
0136 new_device_node = calloc (1, sizeof(*new_device_node));
0137 if (new_device_node == NULL) {
0138 return RTEMS_NO_MEMORY;
0139 }
0140
0141 rtems_chain_initialize_node (&new_device_node->node);
0142 new_device_node->handler = handler;
0143 new_device_node->flow = flow;
0144 new_device_node->context = context;
0145 new_device_node->tty = NULL;
0146
0147 rv = IMFS_make_generic_node(
0148 device_file,
0149 S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO,
0150 &rtems_termios_imfs_node_control,
0151 new_device_node
0152 );
0153 if (rv != 0) {
0154 free (new_device_node);
0155 return RTEMS_UNSATISFIED;
0156 }
0157
0158 return RTEMS_SUCCESSFUL;
0159 }
0160
0161 static rtems_termios_tty *
0162 legacyContextToTTY (rtems_termios_device_context *ctx)
0163 {
0164 return RTEMS_CONTAINER_OF (ctx, rtems_termios_tty, legacy_device_context);
0165 }
0166
0167 static bool
0168 rtems_termios_callback_firstOpen(
0169 rtems_termios_tty *tty,
0170 rtems_termios_device_context *ctx,
0171 struct termios *term,
0172 rtems_libio_open_close_args_t *args
0173 )
0174 {
0175 (void) ctx;
0176 (void) term;
0177
0178 (*tty->device.firstOpen) (tty->major, tty->minor, args);
0179
0180 return true;
0181 }
0182
0183 static void
0184 rtems_termios_callback_lastClose(
0185 rtems_termios_tty *tty,
0186 rtems_termios_device_context *ctx,
0187 rtems_libio_open_close_args_t *args
0188 )
0189 {
0190 (void) ctx;
0191
0192 (*tty->device.lastClose) (tty->major, tty->minor, args);
0193 }
0194
0195 static int
0196 rtems_termios_callback_pollRead (rtems_termios_device_context *ctx)
0197 {
0198 rtems_termios_tty *tty = legacyContextToTTY (ctx);
0199
0200 return (*tty->device.pollRead) (tty->minor);
0201 }
0202
0203 static void
0204 rtems_termios_callback_write(
0205 rtems_termios_device_context *ctx,
0206 const char *buf,
0207 size_t len
0208 )
0209 {
0210 rtems_termios_tty *tty = legacyContextToTTY (ctx);
0211
0212 (*tty->device.write) (tty->minor, buf, len);
0213 }
0214
0215 static bool
0216 rtems_termios_callback_setAttributes(
0217 rtems_termios_device_context *ctx,
0218 const struct termios *term
0219 )
0220 {
0221 rtems_termios_tty *tty = legacyContextToTTY (ctx);
0222
0223 (*tty->device.setAttributes) (tty->minor, term);
0224
0225 return true;
0226 }
0227
0228 static void
0229 rtems_termios_callback_stopRemoteTx (rtems_termios_device_context *ctx)
0230 {
0231 rtems_termios_tty *tty = legacyContextToTTY (ctx);
0232
0233 (*tty->device.stopRemoteTx) (tty->minor);
0234 }
0235
0236 static void
0237 rtems_termios_callback_startRemoteTx (rtems_termios_device_context *ctx)
0238 {
0239 rtems_termios_tty *tty = legacyContextToTTY (ctx);
0240
0241 (*tty->device.startRemoteTx) (tty->minor);
0242 }
0243
0244
0245
0246
0247 static void
0248 drainOutput (struct rtems_termios_tty *tty)
0249 {
0250 rtems_termios_device_context *ctx = tty->device_context;
0251 rtems_interrupt_lock_context lock_context;
0252
0253 if (tty->handler.mode != TERMIOS_POLLED) {
0254 rtems_termios_device_lock_acquire (ctx, &lock_context);
0255 while (tty->rawOutBuf.Tail != tty->rawOutBuf.Head) {
0256 tty->rawOutBufState = rob_wait;
0257 rtems_termios_device_lock_release (ctx, &lock_context);
0258 rtems_binary_semaphore_wait (&tty->rawOutBuf.Semaphore);
0259 rtems_termios_device_lock_acquire (ctx, &lock_context);
0260 }
0261 rtems_termios_device_lock_release (ctx, &lock_context);
0262 }
0263 }
0264
0265 static bool
0266 needDeviceMutex (rtems_termios_tty *tty)
0267 {
0268 return tty->handler.mode == TERMIOS_IRQ_SERVER_DRIVEN
0269 || tty->handler.mode == TERMIOS_TASK_DRIVEN;
0270 }
0271
0272 static void
0273 rtems_termios_destroy_tty (rtems_termios_tty *tty, void *arg, bool last_close)
0274 {
0275 if (rtems_termios_linesw[tty->t_line].l_close != NULL) {
0276
0277
0278
0279 (void) rtems_termios_linesw[tty->t_line].l_close(tty);
0280 } else if (last_close) {
0281
0282
0283
0284 rtems_mutex_lock (&tty->osem);
0285 drainOutput (tty);
0286 rtems_mutex_unlock (&tty->osem);
0287 }
0288
0289 if (tty->handler.mode == TERMIOS_TASK_DRIVEN) {
0290 rtems_status_code sc;
0291
0292
0293
0294
0295 sc = rtems_event_send( tty->rxTaskId, TERMIOS_RX_TERMINATE_EVENT );
0296 if (sc != RTEMS_SUCCESSFUL)
0297 rtems_fatal_error_occurred (sc);
0298 sc = rtems_event_send( tty->txTaskId, TERMIOS_TX_TERMINATE_EVENT );
0299 if (sc != RTEMS_SUCCESSFUL)
0300 rtems_fatal_error_occurred (sc);
0301 }
0302 if (last_close && tty->handler.last_close)
0303 (*tty->handler.last_close)(tty, tty->device_context, arg);
0304
0305 if (tty->device_node != NULL)
0306 tty->device_node->tty = NULL;
0307
0308 rtems_mutex_destroy (&tty->isem);
0309 rtems_mutex_destroy (&tty->osem);
0310 rtems_binary_semaphore_destroy (&tty->rawOutBuf.Semaphore);
0311 if ((tty->handler.poll_read == NULL) ||
0312 (tty->handler.mode == TERMIOS_TASK_DRIVEN))
0313 rtems_binary_semaphore_destroy (&tty->rawInBuf.Semaphore);
0314
0315 if (needDeviceMutex (tty)) {
0316 rtems_mutex_destroy (&tty->device_context->lock.mutex);
0317 } else if (tty->device_context == &tty->legacy_device_context) {
0318 rtems_interrupt_lock_destroy (&tty->legacy_device_context.lock.interrupt);
0319 }
0320
0321 free (tty->rawInBuf.theBuf);
0322 free (tty->rawOutBuf.theBuf);
0323 free (tty->cbuf);
0324 free (tty);
0325 }
0326
0327 static void
0328 deviceAcquireMutex(
0329 rtems_termios_device_context *ctx,
0330 rtems_interrupt_lock_context *lock_context
0331 )
0332 {
0333 rtems_mutex_lock (&ctx->lock.mutex);
0334 }
0335
0336 static void
0337 deviceReleaseMutex(
0338 rtems_termios_device_context *ctx,
0339 rtems_interrupt_lock_context *lock_context
0340 )
0341 {
0342 rtems_mutex_unlock (&ctx->lock.mutex);
0343 }
0344
0345 static rtems_termios_tty *
0346 rtems_termios_open_tty(
0347 rtems_device_major_number major,
0348 rtems_device_minor_number minor,
0349 rtems_libio_open_close_args_t *args,
0350 rtems_termios_tty *tty,
0351 rtems_termios_device_node *device_node,
0352 const rtems_termios_callbacks *callbacks
0353 )
0354 {
0355 if (tty == NULL) {
0356 static char c = 'a';
0357 rtems_termios_device_context *ctx;
0358
0359
0360
0361
0362 tty = calloc (1, sizeof (struct rtems_termios_tty));
0363 if (tty == NULL) {
0364 return NULL;
0365 }
0366
0367
0368
0369 tty->rawInBuf.Size = RAW_INPUT_BUFFER_SIZE;
0370 tty->rawInBuf.theBuf = malloc (tty->rawInBuf.Size);
0371 if (tty->rawInBuf.theBuf == NULL) {
0372 free(tty);
0373 return NULL;
0374 }
0375
0376
0377
0378 tty->rawOutBuf.Size = RAW_OUTPUT_BUFFER_SIZE;
0379 tty->rawOutBuf.theBuf = malloc (tty->rawOutBuf.Size);
0380 if (tty->rawOutBuf.theBuf == NULL) {
0381 free((void *)(tty->rawInBuf.theBuf));
0382 free(tty);
0383 return NULL;
0384 }
0385
0386
0387
0388 tty->cbuf = malloc (CBUFSIZE);
0389 if (tty->cbuf == NULL) {
0390 free((void *)(tty->rawOutBuf.theBuf));
0391 free((void *)(tty->rawInBuf.theBuf));
0392 free(tty);
0393 return NULL;
0394 }
0395
0396
0397
0398 tty->tty_snd.sw_pfn = NULL;
0399 tty->tty_snd.sw_arg = NULL;
0400 tty->tty_rcv.sw_pfn = NULL;
0401 tty->tty_rcv.sw_arg = NULL;
0402 tty->tty_rcvwakeup = false;
0403
0404 tty->minor = minor;
0405 tty->major = major;
0406
0407
0408
0409
0410 rtems_mutex_init (&tty->isem, "termios input");
0411 rtems_mutex_init (&tty->osem, "termios output");
0412 rtems_binary_semaphore_init (&tty->rawOutBuf.Semaphore,
0413 "termios raw output");
0414 tty->rawOutBufState = rob_idle;
0415
0416
0417
0418
0419 if (device_node != NULL) {
0420 device_node->tty = tty;
0421 tty->handler = *device_node->handler;
0422
0423 if (device_node->flow != NULL) {
0424 tty->flow = *device_node->flow;
0425 }
0426
0427 tty->device_node = device_node;
0428 tty->device_context = device_node->context;
0429 memset(&tty->device, 0, sizeof(tty->device));
0430 } else {
0431 tty->handler.first_open = callbacks->firstOpen != NULL ?
0432 rtems_termios_callback_firstOpen : NULL;
0433 tty->handler.last_close = callbacks->lastClose != NULL ?
0434 rtems_termios_callback_lastClose : NULL;
0435 tty->handler.poll_read = callbacks->pollRead != NULL ?
0436 rtems_termios_callback_pollRead : NULL;
0437 tty->handler.write = callbacks->write != NULL ?
0438 rtems_termios_callback_write : NULL;
0439 tty->handler.set_attributes = callbacks->setAttributes != NULL ?
0440 rtems_termios_callback_setAttributes : NULL;
0441 tty->flow.stop_remote_tx = callbacks->stopRemoteTx != NULL ?
0442 rtems_termios_callback_stopRemoteTx : NULL;
0443 tty->flow.start_remote_tx = callbacks->startRemoteTx != NULL ?
0444 rtems_termios_callback_startRemoteTx : NULL;
0445 tty->handler.mode = callbacks->outputUsesInterrupts;
0446 tty->device_context = NULL;
0447 tty->device_node = NULL;
0448 tty->device = *callbacks;
0449 }
0450
0451 if (tty->device_context == NULL) {
0452 tty->device_context = &tty->legacy_device_context;
0453 rtems_termios_device_context_initialize (tty->device_context, "Termios");
0454 }
0455
0456 ctx = tty->device_context;
0457
0458 if (needDeviceMutex (tty)) {
0459 rtems_mutex_init (&ctx->lock.mutex, "termios device");
0460 ctx->lock_acquire = deviceAcquireMutex;
0461 ctx->lock_release = deviceReleaseMutex;
0462 } else {
0463 ctx->lock_acquire = rtems_termios_device_lock_acquire_default;
0464 ctx->lock_release = rtems_termios_device_lock_release_default;
0465 }
0466
0467
0468
0469
0470 if (tty->handler.mode == TERMIOS_TASK_DRIVEN) {
0471 rtems_status_code sc;
0472
0473 sc = rtems_task_create (
0474 rtems_build_name ('T', 'x', 'T', c),
0475 TERMIOS_TXTASK_PRIO,
0476 TERMIOS_TXTASK_STACKSIZE,
0477 RTEMS_NO_PREEMPT | RTEMS_NO_TIMESLICE |
0478 RTEMS_NO_ASR,
0479 RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL,
0480 &tty->txTaskId);
0481 if (sc != RTEMS_SUCCESSFUL)
0482 rtems_fatal_error_occurred (sc);
0483 sc = rtems_task_create (
0484 rtems_build_name ('R', 'x', 'T', c),
0485 TERMIOS_RXTASK_PRIO,
0486 TERMIOS_RXTASK_STACKSIZE,
0487 RTEMS_NO_PREEMPT | RTEMS_NO_TIMESLICE |
0488 RTEMS_NO_ASR,
0489 RTEMS_NO_FLOATING_POINT | RTEMS_LOCAL,
0490 &tty->rxTaskId);
0491 if (sc != RTEMS_SUCCESSFUL)
0492 rtems_fatal_error_occurred (sc);
0493
0494 }
0495 if ((tty->handler.poll_read == NULL) ||
0496 (tty->handler.mode == TERMIOS_TASK_DRIVEN)){
0497 rtems_binary_semaphore_init (&tty->rawInBuf.Semaphore,
0498 "termios raw input");
0499 }
0500
0501
0502
0503
0504 tty->termios.c_iflag = BRKINT | ICRNL | IXON | IMAXBEL;
0505 tty->termios.c_oflag = OPOST | ONLCR | OXTABS;
0506 tty->termios.c_cflag = CS8 | CREAD | CLOCAL;
0507 tty->termios.c_lflag =
0508 ISIG | ICANON | IEXTEN | ECHO | ECHOK | ECHOE | ECHOCTL;
0509
0510 tty->termios.c_ispeed = B9600;
0511 tty->termios.c_ospeed = B9600;
0512
0513 tty->termios.c_cc[VINTR] = '\003';
0514 tty->termios.c_cc[VQUIT] = '\034';
0515 tty->termios.c_cc[VERASE] = '\177';
0516 tty->termios.c_cc[VKILL] = '\025';
0517 tty->termios.c_cc[VEOF] = '\004';
0518 tty->termios.c_cc[VEOL] = '\000';
0519 tty->termios.c_cc[VEOL2] = '\000';
0520 tty->termios.c_cc[VSTART] = '\021';
0521 tty->termios.c_cc[VSTOP] = '\023';
0522 tty->termios.c_cc[VSUSP] = '\032';
0523 tty->termios.c_cc[VREPRINT] = '\022';
0524 tty->termios.c_cc[VDISCARD] = '\017';
0525 tty->termios.c_cc[VWERASE] = '\027';
0526 tty->termios.c_cc[VLNEXT] = '\026';
0527
0528
0529 tty->flow_ctrl = 0;
0530
0531
0532
0533 tty->lowwater = tty->rawInBuf.Size * 1/2;
0534 tty->highwater = tty->rawInBuf.Size * 3/4;
0535
0536
0537
0538 if (c++ == 'z')
0539 c = 'a';
0540
0541 }
0542 args->iop->data1 = tty;
0543 if (!tty->refcount++) {
0544 if (tty->handler.first_open && !(*tty->handler.first_open)(
0545 tty, tty->device_context, &tty->termios, args)) {
0546 rtems_termios_destroy_tty(tty, args, false);
0547 return NULL;
0548 }
0549
0550
0551
0552
0553 if (tty->handler.mode == TERMIOS_TASK_DRIVEN) {
0554 rtems_status_code sc;
0555
0556 sc = rtems_task_start(
0557 tty->rxTaskId, rtems_termios_rxdaemon, (rtems_task_argument)tty);
0558 if (sc != RTEMS_SUCCESSFUL)
0559 rtems_fatal_error_occurred (sc);
0560
0561 sc = rtems_task_start(
0562 tty->txTaskId, rtems_termios_txdaemon, (rtems_task_argument)tty);
0563 if (sc != RTEMS_SUCCESSFUL)
0564 rtems_fatal_error_occurred (sc);
0565 }
0566 }
0567
0568 return tty;
0569 }
0570
0571
0572
0573
0574 rtems_status_code
0575 rtems_termios_open (
0576 rtems_device_major_number major,
0577 rtems_device_minor_number minor,
0578 void *arg,
0579 const rtems_termios_callbacks *callbacks
0580 )
0581 {
0582 struct rtems_termios_tty *tty;
0583
0584
0585
0586
0587 rtems_termios_obtain ();
0588
0589 for (tty = rtems_termios_ttyHead ; tty != NULL ; tty = tty->forw) {
0590 if ((tty->major == major) && (tty->minor == minor))
0591 break;
0592 }
0593
0594 tty = rtems_termios_open_tty(
0595 major, minor, arg, tty, NULL, callbacks);
0596 if (tty == NULL) {
0597 rtems_termios_release ();
0598 return RTEMS_NO_MEMORY;
0599 }
0600
0601 if (tty->refcount == 1) {
0602
0603
0604
0605 tty->forw = rtems_termios_ttyHead;
0606 tty->back = NULL;
0607 if (rtems_termios_ttyHead != NULL)
0608 rtems_termios_ttyHead->back = tty;
0609 rtems_termios_ttyHead = tty;
0610 if (rtems_termios_ttyTail == NULL)
0611 rtems_termios_ttyTail = tty;
0612 }
0613
0614 rtems_termios_release ();
0615
0616 return RTEMS_SUCCESSFUL;
0617 }
0618
0619 static void
0620 flushOutput (struct rtems_termios_tty *tty)
0621 {
0622 rtems_termios_device_context *ctx = tty->device_context;
0623 rtems_interrupt_lock_context lock_context;
0624
0625 rtems_termios_device_lock_acquire (ctx, &lock_context);
0626 tty->rawOutBuf.Tail = 0;
0627 tty->rawOutBuf.Head = 0;
0628 tty->rawOutBufState = rob_idle;
0629 rtems_termios_device_lock_release (ctx, &lock_context);
0630 }
0631
0632 static void
0633 flushInput (struct rtems_termios_tty *tty)
0634 {
0635 rtems_termios_device_context *ctx = tty->device_context;
0636 rtems_interrupt_lock_context lock_context;
0637
0638 rtems_termios_device_lock_acquire (ctx, &lock_context);
0639 tty->rawInBuf.Tail = 0;
0640 tty->rawInBuf.Head = 0;
0641 rtems_termios_device_lock_release (ctx, &lock_context);
0642 }
0643
0644 static void
0645 rtems_termios_close_tty (rtems_termios_tty *tty, void *arg)
0646 {
0647 if (--tty->refcount == 0) {
0648 rtems_termios_destroy_tty (tty, arg, true);
0649 }
0650 }
0651
0652 rtems_status_code
0653 rtems_termios_close (void *arg)
0654 {
0655 rtems_libio_open_close_args_t *args = arg;
0656 struct rtems_termios_tty *tty = args->iop->data1;
0657
0658 rtems_termios_obtain ();
0659
0660 if (tty->refcount == 1) {
0661 if (tty->forw == NULL) {
0662 rtems_termios_ttyTail = tty->back;
0663 if ( rtems_termios_ttyTail != NULL ) {
0664 rtems_termios_ttyTail->forw = NULL;
0665 }
0666 } else {
0667 tty->forw->back = tty->back;
0668 }
0669
0670 if (tty->back == NULL) {
0671 rtems_termios_ttyHead = tty->forw;
0672 if ( rtems_termios_ttyHead != NULL ) {
0673 rtems_termios_ttyHead->back = NULL;
0674 }
0675 } else {
0676 tty->back->forw = tty->forw;
0677 }
0678 }
0679
0680 rtems_termios_close_tty (tty, arg);
0681
0682 rtems_termios_release ();
0683
0684 return RTEMS_SUCCESSFUL;
0685 }
0686
0687 rtems_status_code rtems_termios_bufsize (
0688 size_t cbufsize,
0689 size_t raw_input,
0690 size_t raw_output
0691 )
0692 {
0693 rtems_termios_cbufsize = cbufsize;
0694 rtems_termios_raw_input_size = raw_input;
0695 rtems_termios_raw_output_size = raw_output;
0696 return RTEMS_SUCCESSFUL;
0697 }
0698
0699 static void
0700 termios_set_flowctrl(struct rtems_termios_tty *tty)
0701 {
0702 rtems_termios_device_context *ctx = tty->device_context;
0703 rtems_interrupt_lock_context lock_context;
0704
0705
0706
0707
0708
0709 if (( tty->flow_ctrl & FL_MDXON) &&
0710 !(tty->termios.c_iflag & IXON)) {
0711
0712 tty->flow_ctrl &= ~(FL_MDXON | FL_ORCVXOF);
0713
0714
0715 if (tty->flow_ctrl & FL_OSTOP) {
0716
0717 rtems_termios_device_lock_acquire (ctx, &lock_context);
0718 tty->flow_ctrl &= ~FL_OSTOP;
0719
0720 if (tty->rawOutBufState != rob_idle) {
0721
0722 (*tty->handler.write)(
0723 ctx, &tty->rawOutBuf.theBuf[tty->rawOutBuf.Tail],1);
0724 }
0725
0726 rtems_termios_device_lock_release (ctx, &lock_context);
0727 }
0728 }
0729
0730 if (( tty->flow_ctrl & FL_MDXOF) && !(tty->termios.c_iflag & IXOFF)) {
0731
0732 tty->flow_ctrl &= ~(FL_MDXOF);
0733
0734 tty->flow_ctrl &= ~(FL_ISNTXOF);
0735 }
0736
0737
0738 if (( tty->flow_ctrl & FL_MDRTS) && !(tty->termios.c_cflag & CRTSCTS)) {
0739
0740 tty->flow_ctrl &= ~(FL_MDRTS);
0741
0742
0743 if ((tty->flow_ctrl & FL_IRTSOFF) &&
0744 (tty->flow.start_remote_tx != NULL)) {
0745 tty->flow.start_remote_tx(ctx);
0746 }
0747 tty->flow_ctrl &= ~(FL_IRTSOFF);
0748 }
0749
0750
0751
0752
0753
0754 if (tty->termios.c_cflag & CRTSCTS) {
0755 tty->flow_ctrl |= FL_MDRTS;
0756 }
0757
0758 if (tty->termios.c_iflag & IXOFF) {
0759 tty->flow_ctrl |= FL_MDXOF;
0760 }
0761
0762 if (tty->termios.c_iflag & IXON) {
0763 tty->flow_ctrl |= FL_MDXON;
0764 }
0765 }
0766
0767 rtems_status_code
0768 rtems_termios_ioctl (void *arg)
0769 {
0770 rtems_libio_ioctl_args_t *args = arg;
0771 struct rtems_termios_tty *tty = args->iop->data1;
0772 struct ttywakeup *wakeup = (struct ttywakeup *)args->buffer;
0773 rtems_status_code sc;
0774 int flags;
0775
0776 sc = RTEMS_SUCCESSFUL;
0777 args->ioctl_return = 0;
0778 rtems_mutex_lock (&tty->osem);
0779 switch (args->command) {
0780 default:
0781 if (rtems_termios_linesw[tty->t_line].l_ioctl != NULL) {
0782 sc = rtems_termios_linesw[tty->t_line].l_ioctl(tty,args);
0783 } else if (tty->handler.ioctl) {
0784 args->ioctl_return = (*tty->handler.ioctl) (tty->device_context,
0785 args->command, args->buffer);
0786 sc = RTEMS_SUCCESSFUL;
0787 } else {
0788 sc = RTEMS_INVALID_NUMBER;
0789 }
0790 break;
0791
0792 case TIOCGETA:
0793 *(struct termios *)args->buffer = tty->termios;
0794 break;
0795
0796 case TIOCSETA:
0797 case TIOCSETAW:
0798 case TIOCSETAF:
0799 tty->termios = *(struct termios *)args->buffer;
0800
0801 if (args->command == TIOCSETAW || args->command == TIOCSETAF) {
0802 drainOutput (tty);
0803 if (args->command == TIOCSETAF) {
0804 flushInput (tty);
0805 }
0806 }
0807
0808 termios_set_flowctrl(tty);
0809
0810 if (tty->termios.c_lflag & ICANON) {
0811 tty->rawInBufSemaphoreWait = true;
0812 tty->rawInBufSemaphoreTimeout = 0;
0813 tty->rawInBufSemaphoreFirstTimeout = 0;
0814 } else {
0815 tty->vtimeTicks = tty->termios.c_cc[VTIME] *
0816 rtems_clock_get_ticks_per_second() / 10;
0817 if (tty->termios.c_cc[VTIME]) {
0818 tty->rawInBufSemaphoreWait = true;
0819 tty->rawInBufSemaphoreTimeout = tty->vtimeTicks;
0820 if (tty->termios.c_cc[VMIN])
0821 tty->rawInBufSemaphoreFirstTimeout = 0;
0822 else
0823 tty->rawInBufSemaphoreFirstTimeout = tty->vtimeTicks;
0824 } else {
0825 if (tty->termios.c_cc[VMIN]) {
0826 tty->rawInBufSemaphoreWait = true;
0827 tty->rawInBufSemaphoreTimeout = 0;
0828 tty->rawInBufSemaphoreFirstTimeout = 0;
0829 } else {
0830 tty->rawInBufSemaphoreWait = false;
0831 }
0832 }
0833 }
0834 if (tty->handler.set_attributes) {
0835 sc = (*tty->handler.set_attributes)(tty->device_context, &tty->termios) ?
0836 RTEMS_SUCCESSFUL : RTEMS_IO_ERROR;
0837 }
0838 break;
0839
0840 case TIOCDRAIN:
0841 drainOutput (tty);
0842 break;
0843
0844 case TIOCFLUSH:
0845 flags = *((int *)args->buffer);
0846
0847 if (flags == 0) {
0848 flags = FREAD | FWRITE;
0849 } else {
0850 flags &= FREAD | FWRITE;
0851 }
0852 if (flags & FWRITE) {
0853 flushOutput (tty);
0854 }
0855 if (flags & FREAD) {
0856 flushInput (tty);
0857 }
0858 break;
0859
0860 case RTEMS_IO_SNDWAKEUP:
0861 tty->tty_snd = *wakeup;
0862 break;
0863
0864 case RTEMS_IO_RCVWAKEUP:
0865 tty->tty_rcv = *wakeup;
0866 break;
0867
0868
0869
0870
0871
0872 #if 1
0873 case TIOCSETD:
0874
0875
0876
0877 if (rtems_termios_linesw[tty->t_line].l_close != NULL) {
0878 sc = rtems_termios_linesw[tty->t_line].l_close(tty);
0879 }
0880 tty->t_line=*(int*)(args->buffer);
0881 tty->t_sc = NULL;
0882
0883
0884
0885 if (rtems_termios_linesw[tty->t_line].l_open != NULL) {
0886 sc = rtems_termios_linesw[tty->t_line].l_open(tty);
0887 }
0888 break;
0889 case TIOCGETD:
0890 *(int*)(args->buffer)=tty->t_line;
0891 break;
0892 #endif
0893 case FIONREAD: {
0894 int rawnc = tty->rawInBuf.Tail - tty->rawInBuf.Head;
0895 if ( rawnc < 0 )
0896 rawnc += tty->rawInBuf.Size;
0897
0898 *(int *)args->buffer = tty->ccount - tty->cindex + rawnc;
0899 }
0900 break;
0901 }
0902
0903 rtems_mutex_unlock (&tty->osem);
0904 return sc;
0905 }
0906
0907
0908
0909
0910
0911
0912 static unsigned int
0913 startXmit (
0914 struct rtems_termios_tty *tty,
0915 unsigned int newTail,
0916 bool transmitting
0917 )
0918 {
0919 unsigned int nToSend;
0920
0921 tty->rawOutBufState = rob_busy;
0922
0923
0924 if (tty->flow_ctrl & FL_ORCVXOF) {
0925
0926 tty->flow_ctrl |= FL_OSTOP;
0927 nToSend = 0;
0928
0929 if (transmitting) {
0930 (*tty->handler.write) (tty->device_context, NULL, 0);
0931 }
0932 } else {
0933
0934
0935
0936 if (tty->flow_ctrl & (FL_MDXON | FL_MDXOF))
0937 nToSend = 1;
0938 else if (newTail > tty->rawOutBuf.Head)
0939 nToSend = tty->rawOutBuf.Size - newTail;
0940 else
0941 nToSend = tty->rawOutBuf.Head - newTail;
0942
0943 (*tty->handler.write)(
0944 tty->device_context, &tty->rawOutBuf.theBuf[newTail], nToSend);
0945 }
0946
0947 return nToSend;
0948 }
0949
0950
0951
0952
0953 static size_t
0954 doTransmit (const char *buf, size_t len, rtems_termios_tty *tty,
0955 bool wait, bool nextWait)
0956 {
0957 unsigned int newHead;
0958 rtems_termios_device_context *ctx = tty->device_context;
0959 rtems_interrupt_lock_context lock_context;
0960 size_t todo;
0961
0962 if (tty->handler.mode == TERMIOS_POLLED) {
0963 (*tty->handler.write)(ctx, buf, len);
0964 return len;
0965 }
0966
0967 todo = len;
0968
0969 while (todo > 0) {
0970 size_t nToCopy;
0971 size_t nAvail;
0972
0973
0974 newHead = tty->rawOutBuf.Head + 1;
0975 if (newHead >= tty->rawOutBuf.Size)
0976 newHead -= tty->rawOutBuf.Size;
0977
0978 rtems_termios_device_lock_acquire (ctx, &lock_context);
0979 if (newHead == tty->rawOutBuf.Tail) {
0980 if (wait) {
0981 do {
0982 tty->rawOutBufState = rob_wait;
0983 rtems_termios_device_lock_release (ctx, &lock_context);
0984 rtems_binary_semaphore_wait (&tty->rawOutBuf.Semaphore);
0985 rtems_termios_device_lock_acquire (ctx, &lock_context);
0986 } while (newHead == tty->rawOutBuf.Tail);
0987 } else {
0988 rtems_termios_device_lock_release (ctx, &lock_context);
0989 return len - todo;
0990 }
0991 }
0992
0993
0994 nToCopy = todo;
0995 if (tty->rawOutBuf.Tail > tty->rawOutBuf.Head) {
0996
0997 nAvail = tty->rawOutBuf.Tail - tty->rawOutBuf.Head - 1;
0998 } else {
0999
1000
1001 nAvail = tty->rawOutBuf.Size - tty->rawOutBuf.Head;
1002
1003 if (tty->rawOutBuf.Tail == 0)
1004 nAvail--;
1005 }
1006 if (nToCopy > nAvail)
1007 nToCopy = nAvail;
1008
1009
1010
1011
1012 memcpy(&tty->rawOutBuf.theBuf[tty->rawOutBuf.Head], buf, nToCopy);
1013
1014 newHead = tty->rawOutBuf.Head + nToCopy;
1015 if (newHead >= tty->rawOutBuf.Size)
1016 newHead -= tty->rawOutBuf.Size;
1017 tty->rawOutBuf.Head = newHead;
1018
1019 if (tty->rawOutBufState == rob_idle) {
1020 startXmit (tty, tty->rawOutBuf.Tail, false);
1021 }
1022
1023 rtems_termios_device_lock_release (ctx, &lock_context);
1024
1025 buf += nToCopy;
1026 todo -= nToCopy;
1027 wait = nextWait;
1028 }
1029
1030 return len;
1031 }
1032
1033 void
1034 rtems_termios_puts (
1035 const void *_buf, size_t len, struct rtems_termios_tty *tty)
1036 {
1037 doTransmit (_buf, len, tty, true, true);
1038 }
1039
1040 static bool
1041 canTransmit (rtems_termios_tty *tty, bool wait, size_t len)
1042 {
1043 rtems_termios_device_context *ctx;
1044 rtems_interrupt_lock_context lock_context;
1045 unsigned int capacity;
1046
1047 if (wait || tty->handler.mode == TERMIOS_POLLED) {
1048 return true;
1049 }
1050
1051 ctx = tty->device_context;
1052 rtems_termios_device_lock_acquire (ctx, &lock_context);
1053 capacity = (tty->rawOutBuf.Tail - tty->rawOutBuf.Head - 1) %
1054 tty->rawOutBuf.Size;
1055 rtems_termios_device_lock_release (ctx, &lock_context);
1056 return capacity >= len;
1057 }
1058
1059
1060
1061
1062 static bool
1063 oproc (unsigned char c, rtems_termios_tty *tty, bool wait)
1064 {
1065 char buf[8];
1066 size_t len;
1067
1068 buf[0] = c;
1069 len = 1;
1070
1071 if (tty->termios.c_oflag & OPOST) {
1072 int oldColumn = tty->column;
1073 int columnAdj = 0;
1074
1075 switch (c) {
1076 case '\n':
1077 if (tty->termios.c_oflag & ONLRET)
1078 columnAdj = -oldColumn;
1079 if (tty->termios.c_oflag & ONLCR) {
1080 len = 2;
1081
1082 if (!canTransmit (tty, wait, len)) {
1083 return false;
1084 }
1085
1086 columnAdj = -oldColumn;
1087 buf[0] = '\r';
1088 buf[1] = c;
1089 }
1090 break;
1091
1092 case '\r':
1093 if ((tty->termios.c_oflag & ONOCR) && (oldColumn == 0))
1094 return true;
1095 if (tty->termios.c_oflag & OCRNL) {
1096 buf[0] = '\n';
1097 if (tty->termios.c_oflag & ONLRET)
1098 columnAdj = -oldColumn;
1099 } else {
1100 columnAdj = -oldColumn;
1101 }
1102 break;
1103
1104 case '\t':
1105 columnAdj = 8 - (oldColumn & 7);
1106 if ((tty->termios.c_oflag & TABDLY) == OXTABS) {
1107 int i;
1108
1109 len = (size_t) columnAdj;
1110
1111 if (!canTransmit (tty, wait, len)) {
1112 return false;
1113 }
1114
1115 for (i = 0; i < columnAdj; ++i) {
1116 buf[i] = ' ';
1117 }
1118 }
1119 break;
1120
1121 case '\b':
1122 if (oldColumn > 0)
1123 columnAdj = -1;
1124 break;
1125
1126 default:
1127 if (tty->termios.c_oflag & OLCUC) {
1128 c = toupper(c);
1129 buf[0] = c;
1130 }
1131 if (!iscntrl(c))
1132 columnAdj = 1;
1133 break;
1134 }
1135
1136 tty->column = oldColumn + columnAdj;
1137 }
1138
1139 return doTransmit (buf, len, tty, wait, true) > 0;
1140 }
1141
1142 static uint32_t
1143 rtems_termios_write_tty (rtems_libio_t *iop, rtems_termios_tty *tty,
1144 const char *buf, uint32_t len)
1145 {
1146 bool wait = !rtems_libio_iop_is_no_delay (iop);
1147
1148 if (tty->termios.c_oflag & OPOST) {
1149 uint32_t todo = len;
1150
1151 while (todo > 0) {
1152 if (!oproc (*buf, tty, wait)) {
1153 break;
1154 }
1155
1156 ++buf;
1157 --todo;
1158 wait = false;
1159 }
1160
1161 return len - todo;
1162 } else {
1163 return doTransmit (buf, len, tty, wait, false);
1164 }
1165 }
1166
1167 rtems_status_code
1168 rtems_termios_write (void *arg)
1169 {
1170 rtems_libio_rw_args_t *args = arg;
1171 struct rtems_termios_tty *tty = args->iop->data1;
1172
1173 rtems_mutex_lock (&tty->osem);
1174 if (rtems_termios_linesw[tty->t_line].l_write != NULL) {
1175 rtems_status_code sc;
1176
1177 sc = rtems_termios_linesw[tty->t_line].l_write(tty,args);
1178 rtems_mutex_unlock (&tty->osem);
1179 return sc;
1180 }
1181 args->bytes_moved = rtems_termios_write_tty (args->iop, tty,
1182 args->buffer, args->count);
1183 rtems_mutex_unlock (&tty->osem);
1184 return RTEMS_SUCCESSFUL;
1185 }
1186
1187
1188
1189
1190 static void
1191 echo (unsigned char c, struct rtems_termios_tty *tty)
1192 {
1193 if ((tty->termios.c_lflag & ECHOCTL) &&
1194 iscntrl(c) && (c != '\t') && (c != '\n')) {
1195 char echobuf[2];
1196
1197 echobuf[0] = '^';
1198 echobuf[1] = c ^ 0x40;
1199 doTransmit (echobuf, 2, tty, true, true);
1200 tty->column += 2;
1201 } else {
1202 oproc (c, tty, true);
1203 }
1204 }
1205
1206
1207
1208
1209
1210
1211 static void
1212 erase (struct rtems_termios_tty *tty, int lineFlag)
1213 {
1214 if (tty->ccount == 0)
1215 return;
1216 if (lineFlag) {
1217 if (!(tty->termios.c_lflag & ECHO)) {
1218 tty->ccount = 0;
1219 return;
1220 }
1221 if (!(tty->termios.c_lflag & ECHOE)) {
1222 tty->ccount = 0;
1223 echo (tty->termios.c_cc[VKILL], tty);
1224 if (tty->termios.c_lflag & ECHOK)
1225 echo ('\n', tty);
1226 return;
1227 }
1228 }
1229
1230 while (tty->ccount) {
1231 unsigned char c = tty->cbuf[--tty->ccount];
1232
1233 if (tty->termios.c_lflag & ECHO) {
1234 if (!lineFlag && !(tty->termios.c_lflag & ECHOE)) {
1235 echo (tty->termios.c_cc[VERASE], tty);
1236 } else if (c == '\t') {
1237 int col = tty->read_start_column;
1238 int i = 0;
1239
1240
1241
1242
1243 while (i != tty->ccount) {
1244 c = tty->cbuf[i++];
1245 if (c == '\t') {
1246 col = (col | 7) + 1;
1247 } else if (iscntrl (c)) {
1248 if (tty->termios.c_lflag & ECHOCTL)
1249 col += 2;
1250 } else {
1251 col++;
1252 }
1253 }
1254
1255
1256
1257
1258 while (tty->column > col) {
1259 doTransmit ("\b", 1, tty, true, true);
1260 tty->column--;
1261 }
1262 }
1263 else {
1264 if (iscntrl (c) && (tty->termios.c_lflag & ECHOCTL)) {
1265 doTransmit ("\b \b", 3, tty, true, true);
1266 if (tty->column)
1267 tty->column--;
1268 }
1269 if (!iscntrl (c) || (tty->termios.c_lflag & ECHOCTL)) {
1270 doTransmit ("\b \b", 3, tty, true, true);
1271 if (tty->column)
1272 tty->column--;
1273 }
1274 }
1275 }
1276 if (!lineFlag)
1277 break;
1278 }
1279 }
1280
1281 static unsigned char
1282 iprocEarly (unsigned char c, rtems_termios_tty *tty)
1283 {
1284 if (tty->termios.c_iflag & ISTRIP)
1285 c &= 0x7f;
1286
1287 if (tty->termios.c_iflag & IUCLC)
1288 c = tolower (c);
1289
1290 if (c == '\r') {
1291 if (tty->termios.c_iflag & ICRNL)
1292 c = '\n';
1293 } else if (c == '\n') {
1294 if (tty->termios.c_iflag & INLCR)
1295 c = '\r';
1296 }
1297
1298 return c;
1299 }
1300
1301
1302
1303
1304
1305 static rtems_termios_isig_handler termios_isig_handler =
1306 rtems_termios_default_isig_handler;
1307
1308
1309
1310
1311
1312 rtems_termios_iproc_status_code rtems_termios_default_isig_handler(
1313 unsigned char c,
1314 struct rtems_termios_tty *tty
1315 )
1316 {
1317 return RTEMS_TERMIOS_IPROC_CONTINUE;
1318 }
1319
1320
1321
1322
1323
1324 rtems_status_code rtems_termios_register_isig_handler(
1325 rtems_termios_isig_handler handler
1326 )
1327 {
1328 if (handler == NULL) {
1329 return RTEMS_INVALID_ADDRESS;
1330 }
1331
1332 termios_isig_handler = handler;
1333 return RTEMS_SUCCESSFUL;
1334 }
1335
1336
1337
1338
1339 static rtems_termios_iproc_status_code
1340 iproc (unsigned char c, struct rtems_termios_tty *tty)
1341 {
1342
1343
1344
1345
1346 if ((tty->termios.c_lflag & ISIG)) {
1347 if ((c == tty->termios.c_cc[VINTR]) || (c == tty->termios.c_cc[VQUIT])) {
1348 return (*termios_isig_handler)(c, tty);
1349 }
1350 }
1351
1352
1353
1354
1355 if ((c != '\0') && (tty->termios.c_lflag & ICANON)) {
1356 if (c == tty->termios.c_cc[VERASE]) {
1357 erase (tty, 0);
1358 return RTEMS_TERMIOS_IPROC_CONTINUE;
1359 }
1360 else if (c == tty->termios.c_cc[VKILL]) {
1361 erase (tty, 1);
1362 return RTEMS_TERMIOS_IPROC_CONTINUE;
1363 }
1364 else if (c == tty->termios.c_cc[VEOF]) {
1365 return RTEMS_TERMIOS_IPROC_DONE;
1366 } else if (c == '\n') {
1367 if (tty->termios.c_lflag & (ECHO | ECHONL))
1368 echo (c, tty);
1369 tty->cbuf[tty->ccount++] = c;
1370 return RTEMS_TERMIOS_IPROC_DONE;
1371 } else if ((c == tty->termios.c_cc[VEOL]) ||
1372 (c == tty->termios.c_cc[VEOL2])) {
1373 if (tty->termios.c_lflag & ECHO)
1374 echo (c, tty);
1375 tty->cbuf[tty->ccount++] = c;
1376 return RTEMS_TERMIOS_IPROC_DONE;
1377 }
1378 }
1379
1380
1381
1382
1383
1384
1385 if (tty->ccount < (CBUFSIZE-1)) {
1386 if (tty->termios.c_lflag & ECHO)
1387 echo (c, tty);
1388 tty->cbuf[tty->ccount++] = c;
1389 }
1390 return RTEMS_TERMIOS_IPROC_CONTINUE;
1391 }
1392
1393
1394
1395
1396 static rtems_termios_iproc_status_code
1397 siproc (unsigned char c, struct rtems_termios_tty *tty)
1398 {
1399 rtems_termios_iproc_status_code rc;
1400
1401
1402
1403
1404 if (tty->termios.c_lflag & (ECHO|ECHOE|ECHOK|ECHONL|ECHOPRT|ECHOCTL|ECHOKE)) {
1405 rtems_mutex_lock (&tty->osem);
1406 rc = iproc (c, tty);
1407 rtems_mutex_unlock (&tty->osem);
1408 }
1409 else {
1410 rc = iproc (c, tty);
1411 }
1412 return rc;
1413 }
1414
1415 static rtems_termios_iproc_status_code
1416 siprocPoll (unsigned char c, rtems_termios_tty *tty)
1417 {
1418 if (c == '\r' && (tty->termios.c_iflag & IGNCR) != 0) {
1419 return RTEMS_TERMIOS_IPROC_CONTINUE;
1420 }
1421
1422
1423
1424
1425
1426
1427 c = iprocEarly (c, tty);
1428 return siproc (c, tty);
1429 }
1430
1431
1432
1433
1434 static rtems_termios_iproc_status_code
1435 fillBufferPoll (struct rtems_termios_tty *tty)
1436 {
1437 int n;
1438 rtems_termios_iproc_status_code rc;
1439
1440 if (tty->termios.c_lflag & ICANON) {
1441 for (;;) {
1442 n = (*tty->handler.poll_read)(tty->device_context);
1443 if (n < 0) {
1444 rtems_task_wake_after (1);
1445 } else {
1446 rc = siprocPoll (n, tty);
1447 if (rc != RTEMS_TERMIOS_IPROC_CONTINUE) {
1448 return rc;
1449 }
1450 }
1451 }
1452 } else {
1453 rtems_interval then, now;
1454
1455 then = rtems_clock_get_ticks_since_boot();
1456 for (;;) {
1457 n = (*tty->handler.poll_read)(tty->device_context);
1458 if (n < 0) {
1459 if (tty->termios.c_cc[VMIN]) {
1460 if (tty->termios.c_cc[VTIME] && tty->ccount) {
1461 now = rtems_clock_get_ticks_since_boot();
1462 if ((now - then) > tty->vtimeTicks) {
1463 break;
1464 }
1465 }
1466 } else {
1467 if (!tty->termios.c_cc[VTIME])
1468 break;
1469 now = rtems_clock_get_ticks_since_boot();
1470 if ((now - then) > tty->vtimeTicks) {
1471 break;
1472 }
1473 }
1474 rtems_task_wake_after (1);
1475 } else {
1476 rc = siprocPoll (n, tty);
1477 if (rc != RTEMS_TERMIOS_IPROC_CONTINUE) {
1478 return rc;
1479 }
1480 if (tty->ccount >= tty->termios.c_cc[VMIN])
1481 break;
1482 if (tty->termios.c_cc[VMIN] && tty->termios.c_cc[VTIME])
1483 then = rtems_clock_get_ticks_since_boot();
1484 }
1485 }
1486 }
1487 return RTEMS_TERMIOS_IPROC_CONTINUE;
1488 }
1489
1490
1491
1492
1493 static rtems_termios_iproc_status_code
1494 fillBufferQueue (struct rtems_termios_tty *tty)
1495 {
1496 rtems_termios_device_context *ctx = tty->device_context;
1497 rtems_interval timeout = tty->rawInBufSemaphoreFirstTimeout;
1498 bool wait = true;
1499
1500 while ( wait ) {
1501 rtems_interrupt_lock_context lock_context;
1502
1503
1504
1505
1506
1507 rtems_termios_device_lock_acquire (ctx, &lock_context);
1508
1509 while ((tty->rawInBuf.Head != tty->rawInBuf.Tail) &&
1510 (tty->ccount < (CBUFSIZE-1))) {
1511 unsigned char c;
1512 unsigned int newHead;
1513 rtems_termios_iproc_status_code rc;
1514
1515 newHead = (tty->rawInBuf.Head + 1) % tty->rawInBuf.Size;
1516 c = tty->rawInBuf.theBuf[newHead];
1517 tty->rawInBuf.Head = newHead;
1518
1519 if(((tty->rawInBuf.Tail - newHead) % tty->rawInBuf.Size)
1520 < tty->lowwater) {
1521 tty->flow_ctrl &= ~FL_IREQXOF;
1522
1523 if (((tty->flow_ctrl & (FL_MDXON | FL_ISNTXOF))
1524 == (FL_MDXON | FL_ISNTXOF))
1525 && ((tty->rawOutBufState == rob_idle)
1526 || (tty->flow_ctrl & FL_OSTOP))) {
1527
1528 (*tty->handler.write)(
1529 tty->device_context, (void *)&(tty->termios.c_cc[VSTART]), 1);
1530 } else if (tty->flow_ctrl & FL_MDRTS) {
1531 tty->flow_ctrl &= ~FL_IRTSOFF;
1532
1533 if (tty->flow.start_remote_tx != NULL) {
1534 tty->flow.start_remote_tx(tty->device_context);
1535 }
1536 }
1537 }
1538
1539 rtems_termios_device_lock_release (ctx, &lock_context);
1540
1541
1542 if (tty->termios.c_lflag & ICANON) {
1543 rc = siproc (c, tty);
1544 if (rc != RTEMS_TERMIOS_IPROC_CONTINUE) {
1545 return rc;
1546 }
1547 } else {
1548 rc = siproc (c, tty);
1549
1550
1551 if (rc == RTEMS_TERMIOS_IPROC_INTERRUPT) {
1552 return rc;
1553 }
1554
1555 if (tty->ccount >= tty->termios.c_cc[VMIN])
1556 wait = false;
1557 }
1558 timeout = tty->rawInBufSemaphoreTimeout;
1559
1560 rtems_termios_device_lock_acquire (ctx, &lock_context);
1561 }
1562
1563 rtems_termios_device_lock_release (ctx, &lock_context);
1564
1565
1566
1567
1568 if (wait) {
1569 if (tty->ccount < CBUFSIZE - 1) {
1570 rtems_binary_semaphore *sem;
1571 int eno;
1572
1573 sem = &tty->rawInBuf.Semaphore;
1574
1575 if (tty->rawInBufSemaphoreWait) {
1576 eno = rtems_binary_semaphore_wait_timed_ticks (sem, timeout);
1577 } else {
1578 eno = rtems_binary_semaphore_try_wait (sem);
1579 }
1580
1581 if (eno != 0) {
1582 break;
1583 }
1584 } else {
1585 break;
1586 }
1587 }
1588 }
1589 return RTEMS_TERMIOS_IPROC_CONTINUE;
1590 }
1591
1592 static rtems_status_code
1593 rtems_termios_read_tty (
1594 struct rtems_termios_tty *tty,
1595 char *buffer,
1596 uint32_t initial_count,
1597 uint32_t *count_read
1598 )
1599 {
1600 uint32_t count;
1601 rtems_termios_iproc_status_code rc;
1602
1603 count = initial_count;
1604
1605 if (tty->cindex == tty->ccount) {
1606 tty->cindex = tty->ccount = 0;
1607 tty->read_start_column = tty->column;
1608 if (tty->handler.poll_read != NULL && tty->handler.mode == TERMIOS_POLLED)
1609 rc = fillBufferPoll (tty);
1610 else
1611 rc = fillBufferQueue (tty);
1612 } else {
1613 rc = RTEMS_TERMIOS_IPROC_CONTINUE;
1614 }
1615
1616
1617
1618
1619 while (count && (tty->cindex < tty->ccount)) {
1620 *buffer++ = tty->cbuf[tty->cindex++];
1621 count--;
1622 }
1623 tty->tty_rcvwakeup = false;
1624 *count_read = initial_count - count;
1625
1626
1627
1628
1629
1630
1631 if (rc == RTEMS_TERMIOS_IPROC_INTERRUPT) {
1632 return RTEMS_INTERRUPTED;
1633 }
1634
1635 return RTEMS_SUCCESSFUL;
1636 }
1637
1638 rtems_status_code
1639 rtems_termios_read (void *arg)
1640 {
1641 rtems_libio_rw_args_t *args = arg;
1642 struct rtems_termios_tty *tty = args->iop->data1;
1643 rtems_status_code sc;
1644
1645 rtems_mutex_lock (&tty->isem);
1646
1647 if (rtems_termios_linesw[tty->t_line].l_read != NULL) {
1648
1649 sc = rtems_termios_linesw[tty->t_line].l_read(tty,args);
1650 tty->tty_rcvwakeup = false;
1651 rtems_mutex_unlock (&tty->isem);
1652 return sc;
1653 }
1654
1655 sc = rtems_termios_read_tty(
1656 tty,
1657 args->buffer,
1658 args->count,
1659 &args->bytes_moved
1660 );
1661 rtems_mutex_unlock (&tty->isem);
1662 return sc;
1663 }
1664
1665
1666
1667
1668
1669
1670 void rtems_termios_rxirq_occured(struct rtems_termios_tty *tty)
1671 {
1672
1673
1674
1675 rtems_event_send(tty->rxTaskId,TERMIOS_RX_PROC_EVENT);
1676 }
1677
1678 static bool
1679 mustCallReceiveCallback (const rtems_termios_tty *tty, unsigned char c,
1680 unsigned int newTail, unsigned int head)
1681 {
1682 if ((tty->termios.c_lflag & ICANON) != 0) {
1683 return c == '\n' || c == tty->termios.c_cc[VEOF] ||
1684 c == tty->termios.c_cc[VEOL] || c == tty->termios.c_cc[VEOL2];
1685 } else {
1686 unsigned int rawContentSize = (newTail - head) % tty->rawInBuf.Size;
1687
1688 return rawContentSize >= tty->termios.c_cc[VMIN];
1689 }
1690 }
1691
1692
1693
1694
1695
1696
1697
1698 int
1699 rtems_termios_enqueue_raw_characters (void *ttyp, const char *buf, int len)
1700 {
1701 struct rtems_termios_tty *tty = ttyp;
1702 char c;
1703 int dropped = 0;
1704 bool flow_rcv = false;
1705 rtems_termios_device_context *ctx = tty->device_context;
1706 rtems_interrupt_lock_context lock_context;
1707
1708 if (rtems_termios_linesw[tty->t_line].l_rint != NULL) {
1709 while (len--) {
1710 c = *buf++;
1711 rtems_termios_linesw[tty->t_line].l_rint(c,tty);
1712 }
1713
1714
1715
1716
1717 if (tty->tty_rcv.sw_pfn != NULL && !tty->tty_rcvwakeup) {
1718 tty->tty_rcvwakeup = true;
1719 (*tty->tty_rcv.sw_pfn)(&tty->termios, tty->tty_rcv.sw_arg);
1720 }
1721 return 0;
1722 }
1723
1724 while (len--) {
1725 c = *buf++;
1726
1727
1728 if (tty->flow_ctrl & FL_MDXON) {
1729
1730 if (c == tty->termios.c_cc[VSTOP]) {
1731 if (c == tty->termios.c_cc[VSTART]) {
1732
1733
1734 tty->flow_ctrl = tty->flow_ctrl ^ FL_ORCVXOF;
1735 }
1736 else {
1737
1738
1739 tty->flow_ctrl |= FL_ORCVXOF;
1740 }
1741 flow_rcv = true;
1742 }
1743 else if (c == tty->termios.c_cc[VSTART]) {
1744
1745
1746 tty->flow_ctrl &= ~FL_ORCVXOF;
1747 flow_rcv = true;
1748 }
1749 }
1750 if (flow_rcv) {
1751
1752 if ((tty->flow_ctrl & (FL_ORCVXOF | FL_OSTOP)) == FL_OSTOP) {
1753
1754 rtems_termios_device_lock_acquire (ctx, &lock_context);
1755 tty->flow_ctrl &= ~FL_OSTOP;
1756
1757 if (tty->rawOutBufState != rob_idle) {
1758
1759 (*tty->handler.write)(
1760 ctx, &tty->rawOutBuf.theBuf[tty->rawOutBuf.Tail], 1);
1761 }
1762
1763 rtems_termios_device_lock_release (ctx, &lock_context);
1764 }
1765 } else {
1766 unsigned int head;
1767 unsigned int oldTail;
1768 unsigned int newTail;
1769 bool callReciveCallback;
1770
1771 if (c == '\r' && (tty->termios.c_iflag & IGNCR) != 0) {
1772 continue;
1773 }
1774
1775 c = iprocEarly (c, tty);
1776
1777 rtems_termios_device_lock_acquire (ctx, &lock_context);
1778
1779 head = tty->rawInBuf.Head;
1780 oldTail = tty->rawInBuf.Tail;
1781 newTail = (oldTail + 1) % tty->rawInBuf.Size;
1782
1783
1784 if ((tty->flow_ctrl & FL_IREQXOF) != 0 && (((newTail - head) %
1785 tty->rawInBuf.Size) > tty->highwater)) {
1786
1787 tty->flow_ctrl |= FL_IREQXOF;
1788 if ((tty->flow_ctrl & (FL_MDXOF | FL_ISNTXOF))
1789 == (FL_MDXOF ) ) {
1790 if ((tty->flow_ctrl & FL_OSTOP) ||
1791 (tty->rawOutBufState == rob_idle)) {
1792
1793
1794 tty->flow_ctrl |= FL_ISNTXOF;
1795 (*tty->handler.write)(ctx,
1796 (void *)&(tty->termios.c_cc[VSTOP]), 1);
1797 }
1798 } else if ((tty->flow_ctrl & (FL_MDRTS | FL_IRTSOFF)) == (FL_MDRTS) ) {
1799 tty->flow_ctrl |= FL_IRTSOFF;
1800
1801 if (tty->flow.stop_remote_tx != NULL) {
1802 tty->flow.stop_remote_tx(ctx);
1803 }
1804 }
1805 }
1806
1807 callReciveCallback = false;
1808
1809 if (newTail != head) {
1810 tty->rawInBuf.theBuf[newTail] = c;
1811 tty->rawInBuf.Tail = newTail;
1812
1813
1814
1815
1816 if (tty->tty_rcv.sw_pfn != NULL && !tty->tty_rcvwakeup) {
1817 if (mustCallReceiveCallback (tty, c, newTail, head)) {
1818 tty->tty_rcvwakeup = true;
1819 callReciveCallback = true;
1820 }
1821 }
1822 } else {
1823 ++dropped;
1824
1825 if (tty->tty_rcv.sw_pfn != NULL && !tty->tty_rcvwakeup) {
1826 tty->tty_rcvwakeup = true;
1827 callReciveCallback = true;
1828 }
1829 }
1830
1831 rtems_termios_device_lock_release (ctx, &lock_context);
1832
1833 if (callReciveCallback) {
1834 (*tty->tty_rcv.sw_pfn)(&tty->termios, tty->tty_rcv.sw_arg);
1835 }
1836 }
1837 }
1838
1839 tty->rawInBufDropped += dropped;
1840 rtems_binary_semaphore_post (&tty->rawInBuf.Semaphore);
1841 return dropped;
1842 }
1843
1844
1845
1846
1847
1848 static int
1849 rtems_termios_refill_transmitter (struct rtems_termios_tty *tty)
1850 {
1851 bool wakeUpWriterTask = false;
1852 unsigned int newTail;
1853 int nToSend;
1854 rtems_termios_device_context *ctx = tty->device_context;
1855 rtems_interrupt_lock_context lock_context;
1856 int len;
1857
1858 rtems_termios_device_lock_acquire (ctx, &lock_context);
1859
1860
1861 if ((tty->flow_ctrl & (FL_MDXOF | FL_IREQXOF | FL_ISNTXOF))
1862 == (FL_MDXOF | FL_IREQXOF)) {
1863
1864 (*tty->handler.write)(ctx, (void *)&(tty->termios.c_cc[VSTOP]), 1);
1865
1866 tty->t_dqlen--;
1867 tty->flow_ctrl |= FL_ISNTXOF;
1868
1869 nToSend = 1;
1870
1871 } else if ((tty->flow_ctrl & (FL_IREQXOF | FL_ISNTXOF)) == FL_ISNTXOF) {
1872
1873
1874
1875
1876
1877
1878
1879
1880 (*tty->handler.write)(ctx, (void *)&(tty->termios.c_cc[VSTART]), 1);
1881
1882 tty->t_dqlen--;
1883 tty->flow_ctrl &= ~FL_ISNTXOF;
1884
1885 nToSend = 1;
1886 } else if ( tty->rawOutBuf.Head == tty->rawOutBuf.Tail ) {
1887
1888
1889
1890 if (tty->rawOutBufState == rob_wait) {
1891
1892
1893
1894 wakeUpWriterTask = true;
1895 }
1896
1897 (*tty->handler.write) (ctx, NULL, 0);
1898 nToSend = 0;
1899 } else {
1900 len = tty->t_dqlen;
1901 tty->t_dqlen = 0;
1902
1903 newTail = (tty->rawOutBuf.Tail + len) % tty->rawOutBuf.Size;
1904 tty->rawOutBuf.Tail = newTail;
1905 if (tty->rawOutBufState == rob_wait) {
1906
1907
1908
1909 wakeUpWriterTask = true;
1910 }
1911
1912 if (newTail == tty->rawOutBuf.Head) {
1913
1914
1915
1916 tty->rawOutBufState = rob_idle;
1917 (*tty->handler.write) (ctx, NULL, 0);
1918 nToSend = 0;
1919
1920
1921
1922
1923 if ( tty->tty_snd.sw_pfn != NULL) {
1924 (*tty->tty_snd.sw_pfn)(&tty->termios, tty->tty_snd.sw_arg);
1925 }
1926 } else {
1927
1928
1929
1930 nToSend = startXmit (tty, newTail, true);
1931 }
1932 }
1933
1934 rtems_termios_device_lock_release (ctx, &lock_context);
1935
1936 if (wakeUpWriterTask) {
1937 rtems_binary_semaphore_post (&tty->rawOutBuf.Semaphore);
1938 }
1939
1940 return nToSend;
1941 }
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952 int
1953 rtems_termios_dequeue_characters (void *ttyp, int len)
1954 {
1955 struct rtems_termios_tty *tty = ttyp;
1956 rtems_status_code sc;
1957
1958
1959
1960
1961 tty->t_dqlen += len;
1962
1963 if (tty->handler.mode == TERMIOS_TASK_DRIVEN) {
1964
1965
1966
1967 tty->txTaskCharsDequeued = len;
1968 sc = rtems_event_send(tty->txTaskId, TERMIOS_TX_START_EVENT);
1969 if (sc != RTEMS_SUCCESSFUL)
1970 rtems_fatal_error_occurred (sc);
1971 return 0;
1972 }
1973
1974 if (tty->t_line == PPPDISC ) {
1975
1976
1977
1978 if (rtems_termios_linesw[tty->t_line].l_start != NULL) {
1979 rtems_termios_linesw[tty->t_line].l_start(tty, len);
1980 }
1981 return 0;
1982 }
1983
1984 return rtems_termios_refill_transmitter(tty);
1985 }
1986
1987
1988
1989
1990 static rtems_task rtems_termios_txdaemon(rtems_task_argument argument)
1991 {
1992 struct rtems_termios_tty *tty = (struct rtems_termios_tty *)argument;
1993 rtems_event_set the_event;
1994
1995 while (1) {
1996
1997
1998
1999 rtems_event_receive(
2000 (TERMIOS_TX_START_EVENT | TERMIOS_TX_TERMINATE_EVENT),
2001 RTEMS_EVENT_ANY | RTEMS_WAIT,
2002 RTEMS_NO_TIMEOUT,
2003 &the_event
2004 );
2005 if ((the_event & TERMIOS_TX_TERMINATE_EVENT) != 0) {
2006 tty->txTaskId = 0;
2007 rtems_task_exit();
2008 }
2009
2010
2011
2012
2013 if (rtems_termios_linesw[tty->t_line].l_start != NULL) {
2014 rtems_termios_linesw[tty->t_line].l_start(tty, tty->txTaskCharsDequeued);
2015
2016 if (tty->t_line == PPPDISC) {
2017
2018
2019
2020
2021 continue;
2022 }
2023 }
2024
2025
2026
2027
2028 rtems_termios_refill_transmitter(tty);
2029 }
2030 }
2031
2032
2033
2034
2035 static rtems_task rtems_termios_rxdaemon(rtems_task_argument argument)
2036 {
2037 struct rtems_termios_tty *tty = (struct rtems_termios_tty *)argument;
2038 rtems_termios_device_context *ctx = tty->device_context;
2039 rtems_event_set the_event;
2040 int c;
2041 char c_buf;
2042
2043 while (1) {
2044
2045
2046
2047 rtems_event_receive(
2048 (TERMIOS_RX_PROC_EVENT | TERMIOS_RX_TERMINATE_EVENT),
2049 RTEMS_EVENT_ANY | RTEMS_WAIT,
2050 RTEMS_NO_TIMEOUT,
2051 &the_event
2052 );
2053 if ((the_event & TERMIOS_RX_TERMINATE_EVENT) != 0) {
2054 tty->rxTaskId = 0;
2055 rtems_task_exit();
2056 }
2057
2058
2059
2060
2061 c = tty->handler.poll_read(ctx);
2062 if (c != EOF) {
2063
2064
2065
2066 c_buf = c;
2067 rtems_termios_enqueue_raw_characters ( tty,&c_buf,1);
2068 }
2069 }
2070 }
2071
2072 static int
2073 rtems_termios_imfs_open (rtems_libio_t *iop,
2074 const char *path, int oflag, mode_t mode)
2075 {
2076 rtems_termios_device_node *device_node;
2077 rtems_libio_open_close_args_t args;
2078 struct rtems_termios_tty *tty;
2079
2080 device_node = IMFS_generic_get_context_by_iop (iop);
2081
2082 memset (&args, 0, sizeof (args));
2083 args.iop = iop;
2084 args.flags = rtems_libio_iop_flags (iop);
2085 args.mode = mode;
2086
2087 rtems_termios_obtain ();
2088
2089 tty = rtems_termios_open_tty (device_node->major, device_node->minor, &args,
2090 device_node->tty, device_node, NULL);
2091 if (tty == NULL) {
2092 rtems_termios_release ();
2093 rtems_set_errno_and_return_minus_one (ENOMEM);
2094 }
2095
2096 rtems_termios_release ();
2097 return 0;
2098 }
2099
2100 static int
2101 rtems_termios_imfs_close (rtems_libio_t *iop)
2102 {
2103 rtems_libio_open_close_args_t args;
2104 struct rtems_termios_tty *tty;
2105
2106 memset (&args, 0, sizeof (args));
2107 args.iop = iop;
2108
2109 tty = iop->data1;
2110
2111 rtems_termios_obtain ();
2112 rtems_termios_close_tty (tty, &args);
2113 rtems_termios_release ();
2114 return 0;
2115 }
2116
2117 static ssize_t
2118 rtems_termios_imfs_read (rtems_libio_t *iop, void *buffer, size_t count)
2119 {
2120 struct rtems_termios_tty *tty;
2121 uint32_t bytes_moved;
2122 rtems_status_code sc;
2123
2124 tty = iop->data1;
2125
2126 rtems_mutex_lock (&tty->isem);
2127
2128 if (rtems_termios_linesw[tty->t_line].l_read != NULL) {
2129 rtems_libio_rw_args_t args;
2130 rtems_status_code sc;
2131
2132 memset (&args, 0, sizeof (args));
2133 args.iop = iop;
2134 args.buffer = buffer;
2135 args.count = count;
2136 args.flags = rtems_libio_iop_flags (iop);
2137
2138 sc = rtems_termios_linesw[tty->t_line].l_read (tty, &args);
2139 tty->tty_rcvwakeup = false;
2140 rtems_mutex_unlock (&tty->isem);
2141
2142 if (sc != RTEMS_SUCCESSFUL) {
2143 return rtems_status_code_to_errno (sc);
2144 }
2145
2146 return (ssize_t) args.bytes_moved;
2147 }
2148
2149 sc = rtems_termios_read_tty(tty, buffer, count, &bytes_moved);
2150 rtems_mutex_unlock (&tty->isem);
2151 if (sc != RTEMS_SUCCESSFUL) {
2152 return rtems_status_code_to_errno (sc);
2153 }
2154 return (ssize_t) bytes_moved;
2155
2156 }
2157
2158 static ssize_t
2159 rtems_termios_imfs_write (rtems_libio_t *iop, const void *buffer, size_t count)
2160 {
2161 struct rtems_termios_tty *tty;
2162 uint32_t bytes_moved;
2163
2164 tty = iop->data1;
2165
2166 rtems_mutex_lock (&tty->osem);
2167
2168 if (rtems_termios_linesw[tty->t_line].l_write != NULL) {
2169 rtems_libio_rw_args_t args;
2170 rtems_status_code sc;
2171
2172 memset (&args, 0, sizeof (args));
2173 args.iop = iop;
2174 args.buffer = RTEMS_DECONST (void *, buffer);
2175 args.count = count;
2176 args.flags = rtems_libio_iop_flags (iop);
2177
2178 sc = rtems_termios_linesw[tty->t_line].l_write (tty, &args);
2179 rtems_mutex_unlock (&tty->osem);
2180
2181 if (sc != RTEMS_SUCCESSFUL) {
2182 return rtems_status_code_to_errno (sc);
2183 }
2184
2185 return (ssize_t) args.bytes_moved;
2186 }
2187
2188 bytes_moved = rtems_termios_write_tty (iop, tty, buffer, count);
2189 rtems_mutex_unlock (&tty->osem);
2190 return (ssize_t) bytes_moved;
2191 }
2192
2193 static int
2194 rtems_termios_imfs_ioctl (rtems_libio_t *iop, ioctl_command_t request,
2195 void *buffer)
2196 {
2197 rtems_status_code sc;
2198 rtems_libio_ioctl_args_t args;
2199
2200 memset (&args, 0, sizeof (args));
2201 args.iop = iop;
2202 args.command = request;
2203 args.buffer = buffer;
2204
2205 sc = rtems_termios_ioctl (&args);
2206 if ( sc == RTEMS_SUCCESSFUL ) {
2207 return args.ioctl_return;
2208 } else {
2209 return rtems_status_code_to_errno (sc);
2210 }
2211 }
2212
2213 static const rtems_filesystem_file_handlers_r rtems_termios_imfs_handler = {
2214 .open_h = rtems_termios_imfs_open,
2215 .close_h = rtems_termios_imfs_close,
2216 .read_h = rtems_termios_imfs_read,
2217 .write_h = rtems_termios_imfs_write,
2218 .ioctl_h = rtems_termios_imfs_ioctl,
2219 .lseek_h = rtems_filesystem_default_lseek,
2220 .fstat_h = IMFS_stat,
2221 .ftruncate_h = rtems_filesystem_default_ftruncate,
2222 .fsync_h = rtems_filesystem_default_fsync_or_fdatasync,
2223 .fdatasync_h = rtems_filesystem_default_fsync_or_fdatasync,
2224 .fcntl_h = rtems_filesystem_default_fcntl,
2225 .kqfilter_h = rtems_termios_kqfilter,
2226 .mmap_h = rtems_termios_mmap,
2227 .poll_h = rtems_termios_poll,
2228 .readv_h = rtems_filesystem_default_readv,
2229 .writev_h = rtems_filesystem_default_writev
2230 };
2231
2232 static IMFS_jnode_t *
2233 rtems_termios_imfs_node_initialize (IMFS_jnode_t *node, void *arg)
2234 {
2235 rtems_termios_device_node *device_node;
2236 dev_t dev;
2237
2238 node = IMFS_node_initialize_generic (node, arg);
2239 device_node = IMFS_generic_get_context_by_node (node);
2240 dev = IMFS_generic_get_device_identifier_by_node (node);
2241 device_node->major = rtems_filesystem_dev_major_t (dev);
2242 device_node->minor = rtems_filesystem_dev_minor_t (dev);
2243
2244 return node;
2245 }
2246
2247 static void
2248 rtems_termios_imfs_node_destroy (IMFS_jnode_t *node)
2249 {
2250 rtems_termios_device_node *device_node;
2251
2252 device_node = IMFS_generic_get_context_by_node (node);
2253 free (device_node);
2254 IMFS_node_destroy_default (node);
2255 }
2256
2257 static const IMFS_node_control rtems_termios_imfs_node_control =
2258 IMFS_GENERIC_INITIALIZER(
2259 &rtems_termios_imfs_handler,
2260 rtems_termios_imfs_node_initialize,
2261 rtems_termios_imfs_node_destroy
2262 );