1 //==========================================================================
5 // POSIX Termios compatible TTY I/O driver
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12 // Copyright (C) 2003 Jonathan Larmour
13 // Copyright (C) 2003 Gary Thomas
15 // eCos is free software; you can redistribute it and/or modify it under
16 // the terms of the GNU General Public License as published by the Free
17 // Software Foundation; either version 2 or (at your option) any later version.
19 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
20 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
21 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
24 // You should have received a copy of the GNU General Public License along
25 // with eCos; if not, write to the Free Software Foundation, Inc.,
26 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
28 // As a special exception, if other files instantiate templates or use macros
29 // or inline functions from this file, or you compile this file and link it
30 // with other works to produce a work based on this file, this file does not
31 // by itself cause the resulting work to be covered by the GNU General Public
32 // License. However the source code for this file must still be made available
33 // in accordance with section (3) of the GNU General Public License.
35 // This exception does not invalidate any other reasons why a work based on
36 // this file might be covered by the GNU General Public License.
38 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
39 // at http://sources.redhat.com/ecos/ecos-license/
40 // -------------------------------------------
41 //####ECOSGPLCOPYRIGHTEND####
42 //==========================================================================
43 //#####DESCRIPTIONBEGIN####
45 // Author(s): jlarmour
46 // Contributors: gthomas
48 // Purpose: Device driver for termios emulation tty I/O, layered on
50 // Description: TODO: Add OPOST support for 80x25 (configurable) windows
51 // TODO: Support _POSIX_VDISABLE
53 //####DESCRIPTIONEND####
55 //==========================================================================
59 #include <pkgconf/io_serial.h>
61 #ifdef CYGPKG_IO_SERIAL_TERMIOS
65 #include <cyg/infra/cyg_type.h> // Common types
66 #include <cyg/infra/cyg_ass.h> // Assertion support
67 #include <cyg/infra/cyg_trac.h> // Tracing support
68 #include <cyg/io/io.h>
69 #include <cyg/io/devtab.h>
70 #include <cyg/io/serialio.h> // public serial API
71 #include <termios.h> // Termios header
72 #include <cyg/hal/drv_api.h>
73 #include <stdlib.h> // malloc
75 #ifdef CYGSEM_IO_SERIAL_TERMIOS_USE_SIGNALS
79 //==========================================================================
80 // FUNCTION PROTOTYPES
83 termios_init(struct cyg_devtab_entry *tab);
86 termios_lookup(struct cyg_devtab_entry **tab,
87 struct cyg_devtab_entry *sub_tab,
90 termios_write(cyg_io_handle_t handle, const void *buf, cyg_uint32 *len);
92 termios_read(cyg_io_handle_t handle, void *buf, cyg_uint32 *len);
94 termios_select(cyg_io_handle_t handle, cyg_uint32 which, CYG_ADDRWORD info);
96 termios_get_config(cyg_io_handle_t handle, cyg_uint32 key, void *buf,
99 termios_set_config(cyg_io_handle_t handle, cyg_uint32 key, const void *buf,
102 //==========================================================================
105 struct termios_private_info {
106 struct termios termios;
107 cyg_io_handle_t dev_handle;
108 cyg_drv_mutex_t lock;
113 struct termios *termios_p;
118 //==========================================================================
121 static DEVIO_TABLE(termios_devio,
128 #ifdef CYGPKG_IO_SERIAL_TERMIOS_TERMIOS0
129 static struct termios_private_info termios_private_info0;
130 DEVTAB_ENTRY(termios_io0,
132 CYGDAT_IO_SERIAL_TERMIOS_TERMIOS0_DEV,
136 &termios_private_info0);
139 #ifdef CYGPKG_IO_SERIAL_TERMIOS_TERMIOS1
140 static struct termios_private_info termios_private_info1;
141 DEVTAB_ENTRY(termios_io1,
143 CYGDAT_IO_SERIAL_TERMIOS_TERMIOS1_DEV,
147 &termios_private_info1);
150 #ifdef CYGPKG_IO_SERIAL_TERMIOS_TERMIOS2
151 static struct termios_private_info termios_private_info2;
152 DEVTAB_ENTRY(termios_io2,
154 CYGDAT_IO_SERIAL_TERMIOS_TERMIOS2_DEV,
158 &termios_private_info2);
161 #ifdef CYGPKG_IO_SERIAL_TERMIOS_TERMIOS3
162 static struct termios_private_info termios_private_info3;
163 DEVTAB_ENTRY(termios_io3,
165 CYGDAT_IO_SERIAL_TERMIOS_TERMIOS3_DEV,
169 &termios_private_info3);
172 static const cc_t c_cc_init[ NCCS ] = {
173 0x04, /* EOF == ^D */
175 0x08, /* ERASE = BS ; NB DEL=0x7f */
176 0x03, /* INTR = ^C */
177 0x15, /* KILL = ^U */
179 0x1c, /* QUIT = ^\ */
180 0x1a, /* SUSP = ^Z ; NB ignored in this impl - no job control */
182 #ifdef CYGOPT_IO_SERIAL_FLOW_CONTROL_SOFTWARE
183 CYGDAT_IO_SERIAL_FLOW_CONTROL_XON_CHAR,
184 CYGDAT_IO_SERIAL_FLOW_CONTROL_XOFF_CHAR,
191 // map eCos bitrates to POSIX bitrates.
192 static speed_t ecosbaud2posixbaud[] = {
193 0, B50, B75, B110, B134, B150, B200, B300, B600, B1200, B1800, B2400, B3600,
194 B4800, B7200, B9600, B14400, B19200, B38400, B57600, B115200, B230400 };
196 // map POSIX bitrates to eCos bitrates.
197 static cyg_serial_baud_rate_t posixbaud2ecosbaud[] = {
198 0, CYGNUM_SERIAL_BAUD_50, CYGNUM_SERIAL_BAUD_75, CYGNUM_SERIAL_BAUD_110,
199 CYGNUM_SERIAL_BAUD_134_5, CYGNUM_SERIAL_BAUD_150, CYGNUM_SERIAL_BAUD_200,
200 CYGNUM_SERIAL_BAUD_300, CYGNUM_SERIAL_BAUD_600, CYGNUM_SERIAL_BAUD_1200,
201 CYGNUM_SERIAL_BAUD_1800, CYGNUM_SERIAL_BAUD_2400, CYGNUM_SERIAL_BAUD_3600,
202 CYGNUM_SERIAL_BAUD_4800, CYGNUM_SERIAL_BAUD_7200, CYGNUM_SERIAL_BAUD_9600,
203 CYGNUM_SERIAL_BAUD_14400, CYGNUM_SERIAL_BAUD_19200,
204 CYGNUM_SERIAL_BAUD_38400, CYGNUM_SERIAL_BAUD_57600,
205 CYGNUM_SERIAL_BAUD_115200, CYGNUM_SERIAL_BAUD_230400 };
208 //==========================================================================
211 static __inline__ speed_t
212 map_ecosbaud_to_posixbaud( cyg_serial_baud_rate_t ebaud )
214 if ( ebaud > (sizeof(ecosbaud2posixbaud) / sizeof(speed_t)) )
216 return ecosbaud2posixbaud[ ebaud ];
219 static __inline__ cyg_serial_baud_rate_t
220 map_posixbaud_to_ecosbaud( speed_t pbaud )
222 if ( pbaud > (sizeof(posixbaud2ecosbaud)/sizeof(cyg_serial_baud_rate_t)) )
224 return posixbaud2ecosbaud[ pbaud ];
227 //==========================================================================
228 // real_termios_init is used to initialize the termios structure. This is
229 // called at lookup time, and not from termios_init() because it needs
230 // to query the serial device which may not be set up yet at that point
233 #ifdef CYGSEM_IO_SERIAL_TERMIOS_USE_SIGNALS
234 # define C_IFLAG_INIT (ICRNL|IGNBRK|BRKINT)
236 # define C_IFLAG_INIT (ICRNL|IGNBRK)
238 #define C_OFLAG_INIT (ONLCR)
239 #define C_CFLAG_INIT (CREAD)
240 #define C_LFLAG_INIT (ECHO|ECHOE|ECHOK|ICANON)
243 real_termios_init( struct termios_private_info *priv )
247 cyg_serial_info_t dev_conf;
248 cyg_serial_buf_info_t dev_buf_conf;
249 cyg_uint32 len = sizeof( dev_conf );
251 CYG_REPORT_FUNCTYPE("returning %d");
252 CYG_REPORT_FUNCARG1XV( priv );
253 CYG_CHECK_DATA_PTRC( priv );
257 // Get info from driver
258 res = cyg_io_get_config( priv->dev_handle, CYG_IO_GET_CONFIG_SERIAL_INFO,
260 if ( ENOERR == res ) {
261 len = sizeof( dev_buf_conf );
262 res = cyg_io_get_config( priv->dev_handle,
263 CYG_IO_GET_CONFIG_SERIAL_BUFFER_INFO,
264 &dev_buf_conf, &len );
267 if ( ENOERR != res ) {
268 CYG_REPORT_RETVAL( res );
272 // we only support symmetric baud rates
273 t->c_ispeed = t->c_ospeed = map_ecosbaud_to_posixbaud( dev_conf.baud );
274 t->c_iflag = C_IFLAG_INIT;
275 t->c_oflag = C_OFLAG_INIT;
276 t->c_cflag = C_CFLAG_INIT;
277 t->c_lflag = C_LFLAG_INIT;
278 memcpy( t->c_cc, c_cc_init, sizeof( t->c_cc ) );
280 switch ( dev_conf.parity ) {
281 case CYGNUM_SERIAL_PARITY_NONE:
282 t->c_iflag |= IGNPAR;
284 case CYGNUM_SERIAL_PARITY_ODD:
285 t->c_cflag |= PARODD;
287 case CYGNUM_SERIAL_PARITY_EVEN:
288 t->c_iflag |= PARENB;
291 CYG_FAIL( "Unsupported default parity" );
295 switch( dev_conf.word_length ) {
296 case CYGNUM_SERIAL_WORD_LENGTH_5:
299 case CYGNUM_SERIAL_WORD_LENGTH_6:
302 case CYGNUM_SERIAL_WORD_LENGTH_7:
305 case CYGNUM_SERIAL_WORD_LENGTH_8:
309 CYG_FAIL( "Unsupported word length" );
313 switch ( dev_conf.stop ) {
314 case CYGNUM_SERIAL_STOP_1:
315 // Don't need to do anything
317 case CYGNUM_SERIAL_STOP_2:
318 t->c_cflag |= CSTOPB;
321 CYG_FAIL( "Unsupported number of stop bits" );
325 switch ( dev_conf.flags ) {
326 case CYGNUM_SERIAL_FLOW_RTSCTS_RX:
327 t->c_cflag |= CRTSCTS;
329 case CYGNUM_SERIAL_FLOW_XONXOFF_RX:
332 case CYGNUM_SERIAL_FLOW_RTSCTS_TX:
333 t->c_cflag |= CRTSCTS;
335 case CYGNUM_SERIAL_FLOW_XONXOFF_TX:
339 // Ignore flags we don't grok
344 } // real_termios_init()
346 //==========================================================================
347 // set_attr() actually enacts the termios config. We come in here with
348 // the mutex in priv locked
350 // Possible deviation from standard: POSIX says we should enact which ever
351 // bits we can and only return EINVAL when none of them can be performed
352 // Rather than tracking whether *none* of them worked, instead we just
353 // always claim success. At the very least, setting c_cc is never to
354 // fail so I'm not sure if this is really non-standard or not!
357 set_attr( struct termios *t, struct termios_private_info *priv )
359 Cyg_ErrNo res = ENOERR;
360 cyg_serial_info_t dev_conf, new_dev_conf;
361 cyg_uint32 len = sizeof( dev_conf );
362 cc_t *tempcc = &priv->termios.c_cc[0];
363 struct termios *ptermios = &priv->termios;
365 // Get info from driver
366 res = cyg_io_get_config( priv->dev_handle, CYG_IO_GET_CONFIG_SERIAL_INFO,
372 // We need to set up each facet of config to change one by one because
373 // POSIX says we should try and change as much of the config as possible
374 // This is tedious and has to be done by steam :-(
376 if ( t->c_ospeed != ptermios->c_ospeed ) {
377 new_dev_conf = dev_conf;
378 new_dev_conf.baud = map_posixbaud_to_ecosbaud( t->c_ospeed );
379 if ( 0 != new_dev_conf.baud ) {
380 len = sizeof( new_dev_conf );
381 res = cyg_io_set_config( priv->dev_handle,
382 CYG_IO_SET_CONFIG_SERIAL_INFO,
383 &new_dev_conf, &len );
384 if ( ENOERR == res ) {
385 // It worked, so update dev_conf to reflect the new state
386 dev_conf.baud = new_dev_conf.baud;
388 ptermios->c_ispeed = t->c_ospeed;
389 ptermios->c_ospeed = t->c_ospeed;
394 if ( (t->c_cflag & CSTOPB) != (ptermios->c_cflag & CSTOPB) ) {
395 new_dev_conf = dev_conf;
396 if ( t->c_cflag & CSTOPB )
397 new_dev_conf.stop = CYGNUM_SERIAL_STOP_2;
399 new_dev_conf.stop = CYGNUM_SERIAL_STOP_1;
401 len = sizeof( new_dev_conf );
402 res = cyg_io_set_config( priv->dev_handle,
403 CYG_IO_SET_CONFIG_SERIAL_INFO,
404 &new_dev_conf, &len );
405 if ( ENOERR == res ) {
406 // It worked, so update dev_conf to reflect the new state
407 dev_conf.stop = new_dev_conf.stop;
409 ptermios->c_cflag &= ~CSTOPB;
410 ptermios->c_cflag |= t->c_cflag & CSTOPB;
414 if ( ((t->c_cflag & PARENB) != (ptermios->c_cflag & PARENB)) ||
415 ((t->c_cflag & PARODD) != (ptermios->c_cflag & PARODD)) ) {
416 new_dev_conf = dev_conf;
417 if ( t->c_cflag & PARENB )
418 if ( t->c_cflag & PARODD )
419 new_dev_conf.parity = CYGNUM_SERIAL_PARITY_ODD;
421 new_dev_conf.parity = CYGNUM_SERIAL_PARITY_EVEN;
423 new_dev_conf.parity = CYGNUM_SERIAL_PARITY_NONE;
425 len = sizeof( new_dev_conf );
426 res = cyg_io_set_config( priv->dev_handle,
427 CYG_IO_SET_CONFIG_SERIAL_INFO,
428 &new_dev_conf, &len );
429 if ( ENOERR == res ) {
430 // It worked, so update dev_conf to reflect the new state
431 dev_conf.parity = new_dev_conf.parity;
433 ptermios->c_cflag &= ~(PARENB|PARODD);
434 ptermios->c_cflag |= t->c_cflag & (PARENB|PARODD);
438 if ( (t->c_cflag & CSIZE) != (ptermios->c_cflag & CSIZE) ) {
439 new_dev_conf = dev_conf;
440 switch ( t->c_cflag & CSIZE ) {
442 new_dev_conf.word_length = CYGNUM_SERIAL_WORD_LENGTH_5;
445 new_dev_conf.word_length = CYGNUM_SERIAL_WORD_LENGTH_6;
448 new_dev_conf.word_length = CYGNUM_SERIAL_WORD_LENGTH_7;
451 new_dev_conf.word_length = CYGNUM_SERIAL_WORD_LENGTH_8;
455 len = sizeof( new_dev_conf );
456 res = cyg_io_set_config( priv->dev_handle,
457 CYG_IO_SET_CONFIG_SERIAL_INFO,
458 &new_dev_conf, &len );
459 if ( ENOERR == res ) {
460 // It worked, so update dev_conf to reflect the new state
461 dev_conf.word_length = new_dev_conf.word_length;
463 ptermios->c_cflag &= ~CSIZE;
464 ptermios->c_cflag |= t->c_cflag & CSIZE;
468 if ( (t->c_cflag & IXOFF) != (ptermios->c_cflag & IXOFF) ) {
469 new_dev_conf = dev_conf;
470 new_dev_conf.flags &=
471 ~(CYGNUM_SERIAL_FLOW_XONXOFF_RX|CYGNUM_SERIAL_FLOW_RTSCTS_RX);
472 if ( t->c_cflag & IXOFF )
473 if ( t->c_cflag & CRTSCTS)
474 new_dev_conf.flags |= CYGNUM_SERIAL_FLOW_RTSCTS_RX;
476 new_dev_conf.flags |= CYGNUM_SERIAL_FLOW_XONXOFF_RX;
478 new_dev_conf.flags |= CYGNUM_SERIAL_FLOW_NONE;
480 len = sizeof( new_dev_conf );
481 res = cyg_io_set_config( priv->dev_handle,
482 CYG_IO_SET_CONFIG_SERIAL_INFO,
483 &new_dev_conf, &len );
484 if ( ENOERR == res ) {
485 // It worked, so update dev_conf to reflect the new state
486 dev_conf.flags = new_dev_conf.flags;
488 ptermios->c_cflag &= ~(IXOFF|CRTSCTS);
489 ptermios->c_cflag |= t->c_cflag & (IXOFF|CRTSCTS);
493 if ( (t->c_cflag & IXON) != (ptermios->c_cflag & IXON) ) {
494 new_dev_conf = dev_conf;
495 new_dev_conf.flags &=
496 ~(CYGNUM_SERIAL_FLOW_XONXOFF_TX|CYGNUM_SERIAL_FLOW_RTSCTS_TX);
497 if ( t->c_cflag & IXON )
498 if ( t->c_cflag & CRTSCTS)
499 new_dev_conf.flags |= CYGNUM_SERIAL_FLOW_RTSCTS_TX;
501 new_dev_conf.flags |= CYGNUM_SERIAL_FLOW_XONXOFF_TX;
503 new_dev_conf.flags |= CYGNUM_SERIAL_FLOW_NONE;
505 len = sizeof( new_dev_conf );
506 res = cyg_io_set_config( priv->dev_handle,
507 CYG_IO_SET_CONFIG_SERIAL_INFO,
508 &new_dev_conf, &len );
509 if ( ENOERR == res ) {
510 // It worked, so update dev_conf to reflect the new state
511 dev_conf.flags = new_dev_conf.flags;
513 ptermios->c_cflag &= ~(IXON|CRTSCTS);
514 ptermios->c_cflag |= t->c_cflag & (IXON|CRTSCTS);
518 // Input/Output processing flags can just be set as we grok them all
519 // with few exceptions (see lflags below)
520 ptermios->c_iflag &= ~(BRKINT|ICRNL|IGNBRK|IGNCR|IGNPAR|INLCR|INPCK|
522 ptermios->c_iflag |= t->c_iflag & (
523 #ifdef CYGSEM_IO_SERIAL_TERMIOS_USE_SIGNALS
526 ICRNL|IGNBRK|IGNCR|IGNPAR|
527 INLCR|INPCK|ISTRIP|PARMRK );
529 ptermios->c_oflag &= ~(OPOST|ONLCR);
530 ptermios->c_oflag |= t->c_oflag & (OPOST|ONLCR);
532 ptermios->c_cflag &= ~(CLOCAL|CREAD|HUPCL);
533 ptermios->c_cflag |= t->c_cflag & (CLOCAL|CREAD|HUPCL);
535 ptermios->c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|ICANON|
536 IEXTEN|ISIG|NOFLSH|TOSTOP);
537 // Note we don't support IEXTEN nor TOSTOP so we don't set them
538 ptermios->c_lflag |= t->c_lflag & (ECHO|ECHOE|ECHOK|ECHONL|ICANON|
539 #ifdef CYGSEM_IO_SERIAL_TERMIOS_USE_SIGNALS
544 // control characters. We don't support changing of VSTART, VSTOP,
545 // VTIME or VSUSP though
546 tempcc[VEOF] = t->c_cc[VEOF];
547 tempcc[VEOL] = t->c_cc[VEOL];
548 tempcc[VERASE] = t->c_cc[VERASE];
549 tempcc[VINTR] = t->c_cc[VINTR];
550 tempcc[VKILL] = t->c_cc[VKILL];
551 tempcc[VMIN] = t->c_cc[VMIN];
552 tempcc[VQUIT] = t->c_cc[VQUIT];
557 //==========================================================================
560 termios_init(struct cyg_devtab_entry *tab)
562 // can't initialize the termios structure because we can't
563 // query the serial driver yet. Wait until lookup time.
568 //==========================================================================
571 termios_lookup(struct cyg_devtab_entry **tab,
572 struct cyg_devtab_entry *sub_tab,
575 cyg_io_handle_t chan = (cyg_io_handle_t)sub_tab;
576 struct termios_private_info *priv =
577 (struct termios_private_info *)(*tab)->priv;
578 Cyg_ErrNo err = ENOERR;
581 cyg_drv_mutex_lock( &priv->lock );
582 if ( !priv->init ) { // retest as we may have been pre-empted
584 priv->dev_handle = chan;
585 err = real_termios_init( priv );
587 cyg_drv_mutex_unlock( &priv->lock );
592 //==========================================================================
594 #define WRITE_BUFSIZE 100 // FIXME: ->CDL
595 // #define MAX_CANON 64 FIXME: relevance?
599 termios_write(cyg_io_handle_t handle, const void *_buf, cyg_uint32 *len)
601 cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle;
602 struct termios_private_info *priv = (struct termios_private_info *)t->priv;
603 cyg_io_handle_t chan = (cyg_io_handle_t)priv->dev_handle;
604 cyg_int32 xbufsize, input_bytes_read;
605 cyg_uint8 xbuf[WRITE_BUFSIZE];
606 cyg_uint8 *buf = (cyg_uint8 *)_buf;
609 xbufsize = input_bytes_read = 0;
610 while (input_bytes_read++ < *len) {
611 if ( (*buf == '\n') && (priv->termios.c_oflag & (OPOST|ONLCR)) ) {
612 xbuf[xbufsize++] = '\r';
614 xbuf[xbufsize++] = *buf;
615 if ((xbufsize >= (WRITE_BUFSIZE-1)) || (input_bytes_read == *len) ||
618 cyg_uint32 size = xbufsize;
619 res = cyg_io_write(chan, xbuf, &size);
621 *len = input_bytes_read - (xbufsize - size);
628 // Everything sent, so *len is correct.
633 //==========================================================================
636 termios_read(cyg_io_handle_t handle, void *_buf, cyg_uint32 *len)
638 cyg_devtab_entry_t *dt = (cyg_devtab_entry_t *)handle;
639 struct termios_private_info *priv = (struct termios_private_info *)dt->priv;
640 cyg_io_handle_t chan = (cyg_io_handle_t)priv->dev_handle;
641 struct termios *t = &priv->termios;
646 cyg_uint8 *buf = (cyg_uint8 *)_buf;
647 cyg_bool discardc; // should c be discarded (not read, not printed)
648 cyg_bool returnnow = false; // return back to user after this char
651 if (0 == (t->c_cflag & CREAD) ) {
657 if ( 0 == (t->c_lflag & ICANON) ) {
658 // In non-canonical mode we return the min of *len and the
659 // number of bytes available
660 // So we query the driver for how many bytes are available - this
661 // guarantees we won't block
662 cyg_serial_buf_info_t dev_buf_conf;
663 cyg_uint32 dbc_len = sizeof( dev_buf_conf );
664 res = cyg_io_get_config( chan,
665 CYG_IO_GET_CONFIG_SERIAL_BUFFER_INFO,
666 &dev_buf_conf, &dbc_len );
667 CYG_ASSERT( res == ENOERR, "Query buffer status failed!" );
668 if (dev_buf_conf.rx_count > 0) {
669 // Adjust length to be max characters currently available
670 *len = *len < dev_buf_conf.rx_count ? *len : dev_buf_conf.rx_count;
671 } else if (t->c_cc[VMIN] == 0) {
672 // No chars available - don't block
678 while (!returnnow && size < *len) {
681 res = cyg_io_read(chan, &c, &clen);
687 // lock to prevent termios getting corrupted while we read from it
688 cyg_drv_mutex_lock( &priv->lock );
690 if ( t->c_iflag & ISTRIP )
693 // canonical mode: erase, kill, and newline processing
694 if ( t->c_lflag & ICANON ) {
695 if ( t->c_cc[ VERASE ] == c ) {
698 if ( (t->c_lflag & ECHO) && (t->c_lflag & ECHOE) ) {
699 cyg_uint8 erasebuf[3];
700 erasebuf[0] = erasebuf[2] = t->c_cc[ VERASE ];
702 clen = sizeof(erasebuf);
703 // FIXME: what about error or non-blocking?
704 cyg_io_write(chan, erasebuf, &clen);
709 else if ( t->c_cc[ VKILL ] == c ) {
710 // kill line on display?
711 if ( (t->c_lflag & ECHO) && (t->c_lflag & ECHOK) ) {
713 // we could try and be more efficient here and
714 // output a stream of erases, and then a stream
715 // of spaces and then more erases. But this is poor
716 // because on a slow terminal the user will see characters
717 // delete from the middle forward in chunks!
718 // But at least we try and chunk up sets of writes
719 cyg_uint8 erasebuf[30];
720 cyg_uint8 erasechunks;
723 erasechunks = size < (sizeof(erasebuf)/3) ?
724 size : (sizeof(erasebuf)/3);
726 for (i=0; i<erasechunks; i++) {
727 erasebuf[i*3] = erasebuf[i*3+2] = t->c_cc[ VERASE ];
728 erasebuf[i*3+1] = ' ';
734 j = size < (sizeof(erasebuf)/3) ?
735 size : (sizeof(erasebuf)/3);
737 // FIXME: what about error or non-blocking?
738 cyg_io_write( chan, erasebuf, &clen );
746 else if ( '\r' == c ) {
747 if ( t->c_iflag & IGNCR )
749 else if ( t->c_iflag & ICRNL )
752 // newlines or similar.
753 // Note: not an else if to catch CRNL conversion
754 if ( (t->c_cc[ VEOF ] == c) || (t->c_cc[ VEOL ] == c) ||
756 if ( t->c_cc[ VEOF ] == c )
758 if ( t->c_lflag & ECHONL ) { // don't check ECHO in this case
760 // FIXME: what about error or non-blocking?
761 // FIXME: what if INLCR is set?
762 cyg_io_write( chan, "\n", &clen );
764 if ( t->c_iflag & INLCR )
766 returnnow = true; // FIXME: true even for INLCR?
770 #ifdef CYGSEM_IO_SERIAL_TERMIOS_USE_SIGNALS
771 if ( (t->c_lflag & ISIG) && (t->c_cc[ VINTR ] == c) ) {
773 if ( 0 == (t->c_lflag & NOFLSH) )
775 // raise could be a non-local jump - we should unlock mutex
776 cyg_drv_mutex_unlock( &priv->lock );
778 // FIXME: what if raise returns != 0?
780 cyg_drv_mutex_lock( &priv->lock );
783 if ( (t->c_lflag & ISIG) && (t->c_cc[ VQUIT ] == c) ) {
785 if ( 0 == (t->c_lflag & NOFLSH) )
787 // raise could be a non-local jump - we should unlock mutex
788 cyg_drv_mutex_unlock( &priv->lock );
790 // FIXME: what if raise returns != 0?
792 cyg_drv_mutex_lock( &priv->lock );
797 if ( t->c_lflag & ECHO ) {
799 // FIXME: what about error or non-blocking?
800 termios_write( handle, &c, &clen );
804 if ( (t->c_lflag & ICANON) == 0 ) {
805 // Check to see if read has been satisfied
806 if ( t->c_cc[ VMIN ] && (size >= t->c_cc[ VMIN ]) )
809 cyg_drv_mutex_unlock( &priv->lock );
817 //==========================================================================
820 termios_select(cyg_io_handle_t handle, cyg_uint32 which, CYG_ADDRWORD info)
822 cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle;
823 struct termios_private_info *priv = (struct termios_private_info *)t->priv;
824 cyg_io_handle_t chan = (cyg_io_handle_t)priv->dev_handle;
826 // Just pass it on to next driver level
827 return cyg_io_select( chan, which, info );
831 //==========================================================================
834 termios_get_config(cyg_io_handle_t handle, cyg_uint32 key, void *buf,
837 cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle;
838 struct termios_private_info *priv = (struct termios_private_info *)t->priv;
839 cyg_io_handle_t chan = (cyg_io_handle_t)priv->dev_handle;
840 Cyg_ErrNo res = ENOERR;
843 case CYG_IO_GET_CONFIG_TERMIOS:
845 if ( *len < sizeof(struct termios) ) {
848 cyg_drv_mutex_lock( &priv->lock );
849 *(struct termios *)buf = priv->termios;
850 cyg_drv_mutex_unlock( &priv->lock );
851 *len = sizeof(struct termios);
854 default: // Assume this is a 'serial' driver control
855 res = cyg_io_get_config(chan, key, buf, len);
861 //==========================================================================
865 termios_set_config(cyg_io_handle_t handle, cyg_uint32 key, const void *buf, cyg_uint32 *len)
867 cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle;
868 struct termios_private_info *priv = (struct termios_private_info *)t->priv;
869 cyg_io_handle_t chan = (cyg_io_handle_t)priv->dev_handle;
870 Cyg_ErrNo res = ENOERR;
873 case CYG_IO_SET_CONFIG_TERMIOS:
875 setattr_struct *attr = (setattr_struct *)buf;
876 int optact = attr->optact;
878 if ( *len != sizeof( *attr ) ) {
882 CYG_ASSERT( (optact == TCSAFLUSH) || (optact == TCSADRAIN) ||
883 (optact == TCSANOW), "Invalid optact" );
885 cyg_drv_mutex_lock( &priv->lock );
887 if ( ( TCSAFLUSH == optact ) ||
888 ( TCSADRAIN == optact ) ) {
889 res = cyg_io_get_config( chan,
890 CYG_IO_GET_CONFIG_SERIAL_OUTPUT_DRAIN,
892 CYG_ASSERT( ENOERR == res, "Drain request failed" );
894 if ( TCSAFLUSH == optact ) {
895 res = cyg_io_get_config( chan,
896 CYG_IO_GET_CONFIG_SERIAL_INPUT_FLUSH,
898 CYG_ASSERT( ENOERR == res, "Flush request failed" );
901 res = set_attr( attr->termios_p, priv );
902 cyg_drv_mutex_unlock( &priv->lock );
905 default: // Pass on to serial driver
906 res = cyg_io_set_config(chan, key, buf, len);
912 //==========================================================================
914 #endif // ifdef CYGPKG_IO_SERIAL_TERMIOS