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 static const cc_t c_cc_init[ NCCS ] = {
162 0x04, /* EOF == ^D */
164 0x08, /* ERASE = BS ; NB DEL=0x7f */
165 0x03, /* INTR = ^C */
166 0x15, /* KILL = ^U */
168 0x1c, /* QUIT = ^\ */
169 0x1a, /* SUSP = ^Z ; NB ignored in this impl - no job control */
171 #ifdef CYGOPT_IO_SERIAL_FLOW_CONTROL_SOFTWARE
172 CYGDAT_IO_SERIAL_FLOW_CONTROL_XON_CHAR,
173 CYGDAT_IO_SERIAL_FLOW_CONTROL_XOFF_CHAR,
180 // map eCos bitrates to POSIX bitrates.
181 static speed_t ecosbaud2posixbaud[] = {
182 0, B50, B75, B110, B134, B150, B200, B300, B600, B1200, B2400, B3600,
183 B4800, B7200, B9600, B14400, B19200, B38400, B57600, B115200, B230400 };
185 // map POSIX bitrates to eCos bitrates.
186 static cyg_serial_baud_rate_t posixbaud2ecosbaud[] = {
187 0, CYGNUM_SERIAL_BAUD_50, CYGNUM_SERIAL_BAUD_75, CYGNUM_SERIAL_BAUD_110,
188 CYGNUM_SERIAL_BAUD_134_5, CYGNUM_SERIAL_BAUD_150, CYGNUM_SERIAL_BAUD_200,
189 CYGNUM_SERIAL_BAUD_300, CYGNUM_SERIAL_BAUD_600, CYGNUM_SERIAL_BAUD_1200,
190 CYGNUM_SERIAL_BAUD_1800, CYGNUM_SERIAL_BAUD_2400, CYGNUM_SERIAL_BAUD_3600,
191 CYGNUM_SERIAL_BAUD_4800, CYGNUM_SERIAL_BAUD_7200, CYGNUM_SERIAL_BAUD_9600,
192 CYGNUM_SERIAL_BAUD_14400, CYGNUM_SERIAL_BAUD_19200,
193 CYGNUM_SERIAL_BAUD_38400, CYGNUM_SERIAL_BAUD_57600,
194 CYGNUM_SERIAL_BAUD_115200, CYGNUM_SERIAL_BAUD_230400 };
197 //==========================================================================
200 static __inline__ speed_t
201 map_ecosbaud_to_posixbaud( cyg_serial_baud_rate_t ebaud )
203 if ( ebaud > (sizeof(ecosbaud2posixbaud) / sizeof(speed_t)) )
205 return ecosbaud2posixbaud[ ebaud ];
208 static __inline__ cyg_serial_baud_rate_t
209 map_posixbaud_to_ecosbaud( speed_t pbaud )
211 if ( pbaud > (sizeof(posixbaud2ecosbaud)/sizeof(cyg_serial_baud_rate_t)) )
213 return posixbaud2ecosbaud[ pbaud ];
216 //==========================================================================
217 // real_termios_init is used to initialize the termios structure. This is
218 // called at lookup time, and not from termios_init() because it needs
219 // to query the serial device which may not be set up yet at that point
222 #ifdef CYGSEM_IO_SERIAL_TERMIOS_USE_SIGNALS
223 # define C_IFLAG_INIT (ICRNL|IGNBRK|BRKINT)
225 # define C_IFLAG_INIT (ICRNL|IGNBRK)
227 #define C_OFLAG_INIT (ONLCR)
228 #define C_CFLAG_INIT (CREAD)
229 #define C_LFLAG_INIT (ECHO|ECHOE|ECHOK|ICANON)
232 real_termios_init( struct termios_private_info *priv )
236 cyg_serial_info_t dev_conf;
237 cyg_serial_buf_info_t dev_buf_conf;
238 cyg_uint32 len = sizeof( dev_conf );
240 CYG_REPORT_FUNCTYPE("returning %d");
241 CYG_REPORT_FUNCARG1XV( priv );
242 CYG_CHECK_DATA_PTRC( priv );
246 // Get info from driver
247 res = cyg_io_get_config( priv->dev_handle, CYG_IO_GET_CONFIG_SERIAL_INFO,
249 if ( ENOERR == res ) {
250 len = sizeof( dev_buf_conf );
251 res = cyg_io_get_config( priv->dev_handle,
252 CYG_IO_GET_CONFIG_SERIAL_BUFFER_INFO,
253 &dev_buf_conf, &len );
256 if ( ENOERR != res ) {
257 CYG_REPORT_RETVAL( res );
261 // we only support symmetric baud rates
262 t->c_ispeed = t->c_ospeed = map_ecosbaud_to_posixbaud( dev_conf.baud );
263 t->c_iflag = C_IFLAG_INIT;
264 t->c_oflag = C_OFLAG_INIT;
265 t->c_cflag = C_CFLAG_INIT;
266 t->c_lflag = C_LFLAG_INIT;
267 memcpy( t->c_cc, c_cc_init, sizeof( t->c_cc ) );
269 switch ( dev_conf.parity ) {
270 case CYGNUM_SERIAL_PARITY_NONE:
271 t->c_iflag |= IGNPAR;
273 case CYGNUM_SERIAL_PARITY_ODD:
274 t->c_cflag |= PARODD;
276 case CYGNUM_SERIAL_PARITY_EVEN:
277 t->c_iflag |= PARENB;
280 CYG_FAIL( "Unsupported default parity" );
284 switch( dev_conf.word_length ) {
285 case CYGNUM_SERIAL_WORD_LENGTH_5:
288 case CYGNUM_SERIAL_WORD_LENGTH_6:
291 case CYGNUM_SERIAL_WORD_LENGTH_7:
294 case CYGNUM_SERIAL_WORD_LENGTH_8:
298 CYG_FAIL( "Unsupported word length" );
302 switch ( dev_conf.stop ) {
303 case CYGNUM_SERIAL_STOP_1:
304 // Don't need to do anything
306 case CYGNUM_SERIAL_STOP_2:
307 t->c_cflag |= CSTOPB;
310 CYG_FAIL( "Unsupported number of stop bits" );
314 switch ( dev_conf.flags ) {
315 case CYGNUM_SERIAL_FLOW_RTSCTS_RX:
316 t->c_cflag |= CRTSCTS;
318 case CYGNUM_SERIAL_FLOW_XONXOFF_RX:
321 case CYGNUM_SERIAL_FLOW_RTSCTS_TX:
322 t->c_cflag |= CRTSCTS;
324 case CYGNUM_SERIAL_FLOW_XONXOFF_TX:
328 // Ignore flags we don't grok
333 } // real_termios_init()
335 //==========================================================================
336 // set_attr() actually enacts the termios config. We come in here with
337 // the mutex in priv locked
339 // Possible deviation from standard: POSIX says we should enact which ever
340 // bits we can and only return EINVAL when none of them can be performed
341 // Rather than tracking whether *none* of them worked, instead we just
342 // always claim success. At the very least, setting c_cc is never to
343 // fail so I'm not sure if this is really non-standard or not!
346 set_attr( struct termios *t, struct termios_private_info *priv )
348 Cyg_ErrNo res = ENOERR;
349 cyg_serial_info_t dev_conf, new_dev_conf;
350 cyg_uint32 len = sizeof( dev_conf );
351 cc_t *tempcc = &priv->termios.c_cc[0];
352 struct termios *ptermios = &priv->termios;
354 // Get info from driver
355 res = cyg_io_get_config( priv->dev_handle, CYG_IO_GET_CONFIG_SERIAL_INFO,
361 // We need to set up each facet of config to change one by one because
362 // POSIX says we should try and change as much of the config as possible
363 // This is tedious and has to be done by steam :-(
365 if ( t->c_ospeed != ptermios->c_ospeed ) {
366 new_dev_conf = dev_conf;
367 new_dev_conf.baud = map_posixbaud_to_ecosbaud( t->c_ospeed );
368 if ( 0 != new_dev_conf.baud ) {
369 len = sizeof( new_dev_conf );
370 res = cyg_io_set_config( priv->dev_handle,
371 CYG_IO_SET_CONFIG_SERIAL_INFO,
372 &new_dev_conf, &len );
373 if ( ENOERR == res ) {
374 // It worked, so update dev_conf to reflect the new state
375 dev_conf.baud = new_dev_conf.baud;
377 ptermios->c_ispeed = t->c_ospeed;
378 ptermios->c_ospeed = t->c_ospeed;
383 if ( (t->c_cflag & CSTOPB) != (ptermios->c_cflag & CSTOPB) ) {
384 new_dev_conf = dev_conf;
385 if ( t->c_cflag & CSTOPB )
386 new_dev_conf.stop = CYGNUM_SERIAL_STOP_2;
388 new_dev_conf.stop = CYGNUM_SERIAL_STOP_1;
390 len = sizeof( new_dev_conf );
391 res = cyg_io_set_config( priv->dev_handle,
392 CYG_IO_SET_CONFIG_SERIAL_INFO,
393 &new_dev_conf, &len );
394 if ( ENOERR == res ) {
395 // It worked, so update dev_conf to reflect the new state
396 dev_conf.stop = new_dev_conf.stop;
398 ptermios->c_cflag &= ~CSTOPB;
399 ptermios->c_cflag |= t->c_cflag & CSTOPB;
403 if ( ((t->c_cflag & PARENB) != (ptermios->c_cflag & PARENB)) ||
404 ((t->c_cflag & PARODD) != (ptermios->c_cflag & PARODD)) ) {
405 new_dev_conf = dev_conf;
406 if ( t->c_cflag & PARENB )
407 if ( t->c_cflag & PARODD )
408 new_dev_conf.parity = CYGNUM_SERIAL_PARITY_ODD;
410 new_dev_conf.parity = CYGNUM_SERIAL_PARITY_EVEN;
412 new_dev_conf.parity = CYGNUM_SERIAL_PARITY_NONE;
414 len = sizeof( new_dev_conf );
415 res = cyg_io_set_config( priv->dev_handle,
416 CYG_IO_SET_CONFIG_SERIAL_INFO,
417 &new_dev_conf, &len );
418 if ( ENOERR == res ) {
419 // It worked, so update dev_conf to reflect the new state
420 dev_conf.parity = new_dev_conf.parity;
422 ptermios->c_cflag &= ~(PARENB|PARODD);
423 ptermios->c_cflag |= t->c_cflag & (PARENB|PARODD);
427 if ( (t->c_cflag & CSIZE) != (ptermios->c_cflag & CSIZE) ) {
428 new_dev_conf = dev_conf;
429 switch ( t->c_cflag & CSIZE ) {
431 new_dev_conf.word_length = CYGNUM_SERIAL_WORD_LENGTH_5;
434 new_dev_conf.word_length = CYGNUM_SERIAL_WORD_LENGTH_6;
437 new_dev_conf.word_length = CYGNUM_SERIAL_WORD_LENGTH_7;
440 new_dev_conf.word_length = CYGNUM_SERIAL_WORD_LENGTH_8;
444 len = sizeof( new_dev_conf );
445 res = cyg_io_set_config( priv->dev_handle,
446 CYG_IO_SET_CONFIG_SERIAL_INFO,
447 &new_dev_conf, &len );
448 if ( ENOERR == res ) {
449 // It worked, so update dev_conf to reflect the new state
450 dev_conf.word_length = new_dev_conf.word_length;
452 ptermios->c_cflag &= ~CSIZE;
453 ptermios->c_cflag |= t->c_cflag & CSIZE;
457 if ( (t->c_cflag & IXOFF) != (ptermios->c_cflag & IXOFF) ) {
458 new_dev_conf = dev_conf;
459 new_dev_conf.flags &=
460 ~(CYGNUM_SERIAL_FLOW_XONXOFF_RX|CYGNUM_SERIAL_FLOW_RTSCTS_RX);
461 if ( t->c_cflag & IXOFF )
462 if ( t->c_cflag & CRTSCTS)
463 new_dev_conf.flags |= CYGNUM_SERIAL_FLOW_RTSCTS_RX;
465 new_dev_conf.flags |= CYGNUM_SERIAL_FLOW_XONXOFF_RX;
467 new_dev_conf.flags |= CYGNUM_SERIAL_FLOW_NONE;
469 len = sizeof( new_dev_conf );
470 res = cyg_io_set_config( priv->dev_handle,
471 CYG_IO_SET_CONFIG_SERIAL_INFO,
472 &new_dev_conf, &len );
473 if ( ENOERR == res ) {
474 // It worked, so update dev_conf to reflect the new state
475 dev_conf.flags = new_dev_conf.flags;
477 ptermios->c_cflag &= ~(IXOFF|CRTSCTS);
478 ptermios->c_cflag |= t->c_cflag & (IXOFF|CRTSCTS);
482 if ( (t->c_cflag & IXON) != (ptermios->c_cflag & IXON) ) {
483 new_dev_conf = dev_conf;
484 new_dev_conf.flags &=
485 ~(CYGNUM_SERIAL_FLOW_XONXOFF_TX|CYGNUM_SERIAL_FLOW_RTSCTS_TX);
486 if ( t->c_cflag & IXON )
487 if ( t->c_cflag & CRTSCTS)
488 new_dev_conf.flags |= CYGNUM_SERIAL_FLOW_RTSCTS_TX;
490 new_dev_conf.flags |= CYGNUM_SERIAL_FLOW_XONXOFF_TX;
492 new_dev_conf.flags |= CYGNUM_SERIAL_FLOW_NONE;
494 len = sizeof( new_dev_conf );
495 res = cyg_io_set_config( priv->dev_handle,
496 CYG_IO_SET_CONFIG_SERIAL_INFO,
497 &new_dev_conf, &len );
498 if ( ENOERR == res ) {
499 // It worked, so update dev_conf to reflect the new state
500 dev_conf.flags = new_dev_conf.flags;
502 ptermios->c_cflag &= ~(IXON|CRTSCTS);
503 ptermios->c_cflag |= t->c_cflag & (IXON|CRTSCTS);
507 // Input/Output processing flags can just be set as we grok them all
508 // with few exceptions (see lflags below)
509 ptermios->c_iflag &= ~(BRKINT|ICRNL|IGNBRK|IGNCR|IGNPAR|INLCR|INPCK|
511 ptermios->c_iflag |= t->c_iflag & (
512 #ifdef CYGSEM_IO_SERIAL_TERMIOS_USE_SIGNALS
515 ICRNL|IGNBRK|IGNCR|IGNPAR|
516 INLCR|INPCK|ISTRIP|PARMRK );
518 ptermios->c_oflag &= ~(OPOST|ONLCR);
519 ptermios->c_oflag |= t->c_oflag & (OPOST|ONLCR);
521 ptermios->c_cflag &= ~(CLOCAL|CREAD|HUPCL);
522 ptermios->c_cflag |= t->c_cflag & (CLOCAL|CREAD|HUPCL);
524 ptermios->c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|ICANON|
525 IEXTEN|ISIG|NOFLSH|TOSTOP);
526 // Note we don't support IEXTEN nor TOSTOP so we don't set them
527 ptermios->c_lflag |= t->c_lflag & (ECHO|ECHOE|ECHOK|ECHONL|ICANON|
528 #ifdef CYGSEM_IO_SERIAL_TERMIOS_USE_SIGNALS
533 // control characters. We don't support changing of VSTART, VSTOP,
534 // VTIME or VSUSP though
535 tempcc[VEOF] = t->c_cc[VEOF];
536 tempcc[VEOL] = t->c_cc[VEOL];
537 tempcc[VERASE] = t->c_cc[VERASE];
538 tempcc[VINTR] = t->c_cc[VINTR];
539 tempcc[VKILL] = t->c_cc[VKILL];
540 tempcc[VMIN] = t->c_cc[VMIN];
541 tempcc[VQUIT] = t->c_cc[VQUIT];
546 //==========================================================================
549 termios_init(struct cyg_devtab_entry *tab)
551 // can't initialize the termios structure because we can't
552 // query the serial driver yet. Wait until lookup time.
557 //==========================================================================
560 termios_lookup(struct cyg_devtab_entry **tab,
561 struct cyg_devtab_entry *sub_tab,
564 cyg_io_handle_t chan = (cyg_io_handle_t)sub_tab;
565 struct termios_private_info *priv =
566 (struct termios_private_info *)(*tab)->priv;
567 Cyg_ErrNo err = ENOERR;
570 cyg_drv_mutex_lock( &priv->lock );
571 if ( !priv->init ) { // retest as we may have been pre-empted
572 priv->dev_handle = chan;
573 err = real_termios_init( priv );
575 cyg_drv_mutex_unlock( &priv->lock );
580 //==========================================================================
582 #define WRITE_BUFSIZE 100 // FIXME: ->CDL
583 // #define MAX_CANON 64 FIXME: relevance?
587 termios_write(cyg_io_handle_t handle, const void *_buf, cyg_uint32 *len)
589 cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle;
590 struct termios_private_info *priv = (struct termios_private_info *)t->priv;
591 cyg_io_handle_t chan = (cyg_io_handle_t)priv->dev_handle;
592 cyg_int32 xbufsize, input_bytes_read;
593 cyg_uint8 xbuf[WRITE_BUFSIZE];
594 cyg_uint8 *buf = (cyg_uint8 *)_buf;
597 xbufsize = input_bytes_read = 0;
598 while (input_bytes_read++ < *len) {
599 if ( (*buf == '\n') && (priv->termios.c_oflag & (OPOST|ONLCR)) ) {
600 xbuf[xbufsize++] = '\r';
602 xbuf[xbufsize++] = *buf;
603 if ((xbufsize >= (WRITE_BUFSIZE-1)) || (input_bytes_read == *len) ||
606 cyg_uint32 size = xbufsize;
607 res = cyg_io_write(chan, xbuf, &size);
609 *len = input_bytes_read - (xbufsize - size);
616 // Everything sent, so *len is correct.
621 //==========================================================================
624 termios_read(cyg_io_handle_t handle, void *_buf, cyg_uint32 *len)
626 cyg_devtab_entry_t *dt = (cyg_devtab_entry_t *)handle;
627 struct termios_private_info *priv = (struct termios_private_info *)dt->priv;
628 cyg_io_handle_t chan = (cyg_io_handle_t)priv->dev_handle;
629 struct termios *t = &priv->termios;
634 cyg_uint8 *buf = (cyg_uint8 *)_buf;
635 cyg_bool discardc; // should c be discarded (not read, not printed)
636 cyg_bool returnnow = false; // return back to user after this char
639 if (0 == (t->c_cflag & CREAD) ) {
645 if ( 0 == (t->c_lflag & ICANON) ) {
646 // In non-canonical mode we return the min of *len and the
647 // number of bytes available
648 // So we query the driver for how many bytes are available - this
649 // guarantees we won't block
650 cyg_serial_buf_info_t dev_buf_conf;
651 cyg_uint32 dbc_len = sizeof( dev_buf_conf );
652 res = cyg_io_get_config( chan,
653 CYG_IO_GET_CONFIG_SERIAL_BUFFER_INFO,
654 &dev_buf_conf, &dbc_len );
655 CYG_ASSERT( res == ENOERR, "Query buffer status failed!" );
656 if (dev_buf_conf.rx_count > 0) {
657 // Adjust length to be max characters currently available
658 *len = *len < dev_buf_conf.rx_count ? *len : dev_buf_conf.rx_count;
659 } else if (t->c_cc[VMIN] == 0) {
660 // No chars available - don't block
666 while (!returnnow && size < *len) {
669 res = cyg_io_read(chan, &c, &clen);
675 // lock to prevent termios getting corrupted while we read from it
676 cyg_drv_mutex_lock( &priv->lock );
678 if ( t->c_iflag & ISTRIP )
681 // canonical mode: erase, kill, and newline processing
682 if ( t->c_lflag & ICANON ) {
683 if ( t->c_cc[ VERASE ] == c ) {
686 if ( (t->c_lflag & ECHO) && (t->c_lflag & ECHOE) ) {
687 cyg_uint8 erasebuf[3];
688 erasebuf[0] = erasebuf[2] = t->c_cc[ VERASE ];
690 clen = sizeof(erasebuf);
691 // FIXME: what about error or non-blocking?
692 cyg_io_write(chan, erasebuf, &clen);
697 else if ( t->c_cc[ VKILL ] == c ) {
698 // kill line on display?
699 if ( (t->c_lflag & ECHO) && (t->c_lflag & ECHOK) ) {
701 // we could try and be more efficient here and
702 // output a stream of erases, and then a stream
703 // of spaces and then more erases. But this is poor
704 // because on a slow terminal the user will see characters
705 // delete from the middle forward in chunks!
706 // But at least we try and chunk up sets of writes
707 cyg_uint8 erasebuf[30];
708 cyg_uint8 erasechunks;
711 erasechunks = size < (sizeof(erasebuf)/3) ?
712 size : (sizeof(erasebuf)/3);
714 for (i=0; i<erasechunks; i++) {
715 erasebuf[i*3] = erasebuf[i*3+2] = t->c_cc[ VERASE ];
716 erasebuf[i*3+1] = ' ';
722 j = size < (sizeof(erasebuf)/3) ?
723 size : (sizeof(erasebuf)/3);
725 // FIXME: what about error or non-blocking?
726 cyg_io_write( chan, erasebuf, &clen );
734 else if ( '\r' == c ) {
735 if ( t->c_iflag & IGNCR )
737 else if ( t->c_iflag & ICRNL )
740 // newlines or similar.
741 // Note: not an else if to catch CRNL conversion
742 if ( (t->c_cc[ VEOF ] == c) || (t->c_cc[ VEOL ] == c) ||
744 if ( t->c_cc[ VEOF ] == c )
746 if ( t->c_lflag & ECHONL ) { // don't check ECHO in this case
748 // FIXME: what about error or non-blocking?
749 // FIXME: what if INLCR is set?
750 cyg_io_write( chan, "\n", &clen );
752 if ( t->c_iflag & INLCR )
754 returnnow = true; // FIXME: true even for INLCR?
758 #ifdef CYGSEM_IO_SERIAL_TERMIOS_USE_SIGNALS
759 if ( (t->c_lflag & ISIG) && (t->c_cc[ VINTR ] == c) ) {
761 if ( 0 == (t->c_lflag & NOFLSH) )
763 // raise could be a non-local jump - we should unlock mutex
764 cyg_drv_mutex_unlock( &priv->lock );
766 // FIXME: what if raise returns != 0?
768 cyg_drv_mutex_lock( &priv->lock );
771 if ( (t->c_lflag & ISIG) && (t->c_cc[ VQUIT ] == 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 );
785 if ( t->c_lflag & ECHO ) {
787 // FIXME: what about error or non-blocking?
788 termios_write( handle, &c, &clen );
792 if ( (t->c_lflag & ICANON) == 0 ) {
793 // Check to see if read has been satisfied
794 if ( t->c_cc[ VMIN ] && (size >= t->c_cc[ VMIN ]) )
797 cyg_drv_mutex_unlock( &priv->lock );
805 //==========================================================================
808 termios_select(cyg_io_handle_t handle, cyg_uint32 which, CYG_ADDRWORD info)
810 cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle;
811 struct termios_private_info *priv = (struct termios_private_info *)t->priv;
812 cyg_io_handle_t chan = (cyg_io_handle_t)priv->dev_handle;
814 // Just pass it on to next driver level
815 return cyg_io_select( chan, which, info );
819 //==========================================================================
822 termios_get_config(cyg_io_handle_t handle, cyg_uint32 key, void *buf,
825 cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle;
826 struct termios_private_info *priv = (struct termios_private_info *)t->priv;
827 cyg_io_handle_t chan = (cyg_io_handle_t)priv->dev_handle;
828 Cyg_ErrNo res = ENOERR;
831 case CYG_IO_GET_CONFIG_TERMIOS:
833 if ( *len < sizeof(struct termios) ) {
836 cyg_drv_mutex_lock( &priv->lock );
837 *(struct termios *)buf = priv->termios;
838 cyg_drv_mutex_unlock( &priv->lock );
839 *len = sizeof(struct termios);
842 default: // Assume this is a 'serial' driver control
843 res = cyg_io_get_config(chan, key, buf, len);
849 //==========================================================================
853 termios_set_config(cyg_io_handle_t handle, cyg_uint32 key, const void *buf, cyg_uint32 *len)
855 cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle;
856 struct termios_private_info *priv = (struct termios_private_info *)t->priv;
857 cyg_io_handle_t chan = (cyg_io_handle_t)priv->dev_handle;
858 Cyg_ErrNo res = ENOERR;
861 case CYG_IO_SET_CONFIG_TERMIOS:
863 setattr_struct *attr = (setattr_struct *)buf;
864 int optact = attr->optact;
866 if ( *len != sizeof( *attr ) ) {
870 CYG_ASSERT( (optact == TCSAFLUSH) || (optact == TCSADRAIN) ||
871 (optact == TCSANOW), "Invalid optact" );
873 cyg_drv_mutex_lock( &priv->lock );
875 if ( ( TCSAFLUSH == optact ) ||
876 ( TCSADRAIN == optact ) ) {
877 res = cyg_io_get_config( chan,
878 CYG_IO_GET_CONFIG_SERIAL_OUTPUT_DRAIN,
880 CYG_ASSERT( ENOERR == res, "Drain request failed" );
882 if ( TCSAFLUSH == optact ) {
883 res = cyg_io_get_config( chan,
884 CYG_IO_GET_CONFIG_SERIAL_INPUT_FLUSH,
886 CYG_ASSERT( ENOERR == res, "Flush request failed" );
889 res = set_attr( attr->termios_p, priv );
890 cyg_drv_mutex_unlock( &priv->lock );
893 default: // Pass on to serial driver
894 res = cyg_io_set_config(chan, key, buf, len);
900 //==========================================================================
902 #endif // ifdef CYGPKG_IO_SERIAL_TERMIOS