OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [io/] [serial/] [v2_0/] [src/] [common/] [termiostty.c] - Blame information for rev 27

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 27 unneback
//==========================================================================
2
//
3
//      termiostty.c
4
//
5
//      POSIX Termios compatible TTY I/O driver
6
//
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
//
14
// eCos is free software; you can redistribute it and/or modify it under
15
// the terms of the GNU General Public License as published by the Free
16
// Software Foundation; either version 2 or (at your option) any later version.
17
//
18
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
19
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
20
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
21
// for more details.
22
//
23
// You should have received a copy of the GNU General Public License along
24
// with eCos; if not, write to the Free Software Foundation, Inc.,
25
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26
//
27
// As a special exception, if other files instantiate templates or use macros
28
// or inline functions from this file, or you compile this file and link it
29
// with other works to produce a work based on this file, this file does not
30
// by itself cause the resulting work to be covered by the GNU General Public
31
// License. However the source code for this file must still be made available
32
// in accordance with section (3) of the GNU General Public License.
33
//
34
// This exception does not invalidate any other reasons why a work based on
35
// this file might be covered by the GNU General Public License.
36
//
37
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
38
// at http://sources.redhat.com/ecos/ecos-license/
39
// -------------------------------------------
40
//####ECOSGPLCOPYRIGHTEND####
41
//==========================================================================
42
//#####DESCRIPTIONBEGIN####
43
//
44
// Author(s):    jlarmour
45
// Contributors: gthomas
46
// Date:         2000-07-22
47
// Purpose:      Device driver for termios emulation tty I/O, layered on
48
//               top of serial I/O
49
// Description:  TODO: Add OPOST support for 80x25 (configurable) windows
50
//               TODO: Support _POSIX_VDISABLE
51
//
52
//####DESCRIPTIONEND####
53
//
54
//==========================================================================
55
 
56
// CONFIGURATION
57
 
58
#include <pkgconf/io_serial.h>
59
 
60
#ifdef CYGPKG_IO_SERIAL_TERMIOS
61
 
62
// INCLUDES
63
 
64
#include <cyg/infra/cyg_type.h>    // Common types 
65
#include <cyg/infra/cyg_ass.h>     // Assertion support
66
#include <cyg/infra/cyg_trac.h>    // Tracing support
67
#include <cyg/io/io.h>
68
#include <cyg/io/devtab.h>
69
#include <cyg/io/serialio.h>       // public serial API
70
#include <termios.h>               // Termios header
71
#include <cyg/hal/drv_api.h>
72
#include <stdlib.h>                // malloc
73
#include <string.h>
74
#ifdef CYGSEM_IO_SERIAL_TERMIOS_USE_SIGNALS
75
# include <signal.h>
76
#endif
77
 
78
//==========================================================================
79
// FUNCTION PROTOTYPES
80
 
81
static bool
82
termios_init(struct cyg_devtab_entry *tab);
83
 
84
static Cyg_ErrNo
85
termios_lookup(struct cyg_devtab_entry **tab,
86
               struct cyg_devtab_entry *sub_tab,
87
               const char *name);
88
static Cyg_ErrNo
89
termios_write(cyg_io_handle_t handle, const void *buf, cyg_uint32 *len);
90
static Cyg_ErrNo
91
termios_read(cyg_io_handle_t handle, void *buf, cyg_uint32 *len);
92
static Cyg_ErrNo
93
termios_select(cyg_io_handle_t handle, cyg_uint32 which, CYG_ADDRWORD info);
94
static Cyg_ErrNo
95
termios_get_config(cyg_io_handle_t handle, cyg_uint32 key, void *buf,
96
                   cyg_uint32 *len);
97
static Cyg_ErrNo
98
termios_set_config(cyg_io_handle_t handle, cyg_uint32 key, const void *buf,
99
                   cyg_uint32 *len);
100
 
101
//==========================================================================
102
// TYPE DEFINITIONS
103
 
104
struct termios_private_info {
105
    struct termios  termios;
106
    cyg_io_handle_t dev_handle;
107
    cyg_drv_mutex_t lock;
108
    cyg_bool        init;
109
    cyg_uint8      *errbuf;
110
    cyg_uint8      *errbufpos;
111
    cyg_uint32      errbufsize;
112
};
113
 
114
typedef struct {
115
    struct termios *termios_p;
116
    int optact;
117
} setattr_struct;
118
 
119
 
120
//==========================================================================
121
// STATIC OBJECTS
122
 
123
static DEVIO_TABLE(termios_devio,
124
                   termios_write,
125
                   termios_read,
126
                   termios_select,
127
                   termios_get_config,
128
                   termios_set_config);
129
 
130
#ifdef CYGPKG_IO_SERIAL_TERMIOS_TERMIOS0
131
static struct termios_private_info termios_private_info0;
132
DEVTAB_ENTRY(termios_io0,
133
             "/dev/termios0",
134
             CYGDAT_IO_SERIAL_TERMIOS_TERMIOS0_DEV,
135
             &termios_devio,
136
             termios_init,
137
             termios_lookup,
138
             &termios_private_info0);
139
#endif
140
 
141
#ifdef CYGPKG_IO_SERIAL_TERMIOS_TERMIOS1
142
static struct termios_private_info termios_private_info1;
143
DEVTAB_ENTRY(termios_io1,
144
             "/dev/termios1",
145
             CYGDAT_IO_SERIAL_TERMIOS_TERMIOS1_DEV,
146
             &termios_devio,
147
             termios_init,
148
             termios_lookup,
149
             &termios_private_info1);
150
#endif
151
 
152
#ifdef CYGPKG_IO_SERIAL_TERMIOS_TERMIOS2
153
static struct termios_private_info termios_private_info2;
154
DEVTAB_ENTRY(termios_io2,
155
             "/dev/termios2",
156
             CYGDAT_IO_SERIAL_TERMIOS_TERMIOS2_DEV,
157
             &termios_devio,
158
             termios_init,
159
             termios_lookup,
160
             &termios_private_info2);
161
#endif
162
 
163
static const cc_t c_cc_init[ NCCS ] = {
164
    0x04,     /* EOF == ^D */
165
    0,        /* EOL */
166
    0x08,     /* ERASE = BS ; NB DEL=0x7f */
167
    0x03,     /* INTR = ^C */
168
    0x15,     /* KILL = ^U */
169
    0,        /* MIN = 0 */
170
    0x1c,     /* QUIT = ^\ */
171
    0x1a,     /* SUSP = ^Z ; NB ignored in this impl - no job control */
172
    0,        /* TIME = 0 */
173
#ifdef CYGOPT_IO_SERIAL_FLOW_CONTROL_SOFTWARE
174
    CYGDAT_IO_SERIAL_FLOW_CONTROL_XON_CHAR,
175
    CYGDAT_IO_SERIAL_FLOW_CONTROL_XOFF_CHAR,
176
#else
177
    17,
178
    19,
179
#endif
180
};
181
 
182
// map eCos bitrates to POSIX bitrates.
183
static speed_t ecosbaud2posixbaud[] = {
184
    0, B50, B75, B110, B134, B150, B200, B300, B600, B1200, B2400, B3600,
185
    B4800, B7200, B9600, B14400, B19200, B38400, B57600, B115200, B230400 };
186
 
187
// map POSIX bitrates to eCos bitrates.
188
static cyg_serial_baud_rate_t posixbaud2ecosbaud[] = {
189
    0, CYGNUM_SERIAL_BAUD_50, CYGNUM_SERIAL_BAUD_75, CYGNUM_SERIAL_BAUD_110,
190
    CYGNUM_SERIAL_BAUD_134_5, CYGNUM_SERIAL_BAUD_150, CYGNUM_SERIAL_BAUD_200,
191
    CYGNUM_SERIAL_BAUD_300, CYGNUM_SERIAL_BAUD_600, CYGNUM_SERIAL_BAUD_1200,
192
    CYGNUM_SERIAL_BAUD_1800, CYGNUM_SERIAL_BAUD_2400, CYGNUM_SERIAL_BAUD_3600,
193
    CYGNUM_SERIAL_BAUD_4800, CYGNUM_SERIAL_BAUD_7200, CYGNUM_SERIAL_BAUD_9600,
194
    CYGNUM_SERIAL_BAUD_14400, CYGNUM_SERIAL_BAUD_19200,
195
    CYGNUM_SERIAL_BAUD_38400, CYGNUM_SERIAL_BAUD_57600,
196
    CYGNUM_SERIAL_BAUD_115200, CYGNUM_SERIAL_BAUD_230400 };
197
 
198
 
199
//==========================================================================
200
// FUNCTIONS
201
 
202
static __inline__ speed_t
203
map_ecosbaud_to_posixbaud( cyg_serial_baud_rate_t ebaud )
204
{
205
    if ( ebaud > (sizeof(ecosbaud2posixbaud) / sizeof(speed_t)) )
206
        return 0;
207
    return ecosbaud2posixbaud[ ebaud ];
208
}
209
 
210
static __inline__ cyg_serial_baud_rate_t
211
map_posixbaud_to_ecosbaud( speed_t pbaud )
212
{
213
    if ( pbaud > (sizeof(posixbaud2ecosbaud)/sizeof(cyg_serial_baud_rate_t)) )
214
        return 0;
215
    return posixbaud2ecosbaud[ pbaud ];
216
}
217
 
218
//==========================================================================
219
// real_termios_init is used to initialize the termios structure. This is
220
// called at lookup time, and not from termios_init() because it needs
221
// to query the serial device which may not be set up yet at that point
222
// in termios_init()
223
 
224
#ifdef CYGSEM_IO_SERIAL_TERMIOS_USE_SIGNALS
225
# define C_IFLAG_INIT (ICRNL|IGNBRK|BRKINT)
226
#else
227
# define C_IFLAG_INIT (ICRNL|IGNBRK)
228
#endif
229
#define C_OFLAG_INIT (ONLCR)
230
#define C_CFLAG_INIT (CREAD)
231
#define C_LFLAG_INIT (ECHO|ECHOE|ECHOK|ICANON)
232
 
233
static Cyg_ErrNo
234
real_termios_init( struct termios_private_info *priv )
235
{
236
    Cyg_ErrNo res;
237
    struct termios *t;
238
    cyg_serial_info_t dev_conf;
239
    cyg_serial_buf_info_t dev_buf_conf;
240
    cyg_uint32 len = sizeof( dev_conf );
241
 
242
    CYG_REPORT_FUNCTYPE("returning %d");
243
    CYG_REPORT_FUNCARG1XV( priv );
244
    CYG_CHECK_DATA_PTRC( priv );
245
 
246
    t = &priv->termios;
247
 
248
    // Get info from driver
249
    res = cyg_io_get_config( priv->dev_handle, CYG_IO_GET_CONFIG_SERIAL_INFO,
250
                             &dev_conf, &len );
251
    if ( ENOERR == res ) {
252
        len = sizeof( dev_buf_conf );
253
        res = cyg_io_get_config( priv->dev_handle,
254
                                 CYG_IO_GET_CONFIG_SERIAL_BUFFER_INFO,
255
                                 &dev_buf_conf, &len );
256
    }
257
 
258
    priv->errbuf = (cyg_uint8 *)malloc( dev_buf_conf.rx_bufsize );
259
    if ( NULL == priv->errbuf )
260
        res = ENOMEM;   // FIXME: Are we allowed to do this?
261
    priv->errbufpos = priv->errbuf;
262
    priv->errbufsize = dev_buf_conf.rx_bufsize;
263
 
264
    if ( ENOERR != res ) {
265
        CYG_REPORT_RETVAL( res );
266
        return res;
267
    }
268
 
269
    // we only support symmetric baud rates
270
    t->c_ispeed = t->c_ospeed = map_ecosbaud_to_posixbaud( dev_conf.baud );
271
    t->c_iflag = C_IFLAG_INIT;
272
    t->c_oflag = C_OFLAG_INIT;
273
    t->c_cflag = C_CFLAG_INIT;
274
    t->c_lflag = C_LFLAG_INIT;
275
    memcpy( t->c_cc, c_cc_init, sizeof( t->c_cc ) );
276
 
277
    switch ( dev_conf.parity ) {
278
    case CYGNUM_SERIAL_PARITY_NONE:
279
        t->c_iflag |= IGNPAR;
280
        break;
281
    case CYGNUM_SERIAL_PARITY_ODD:
282
        t->c_cflag |= PARODD;
283
        // DROPTHROUGH
284
    case CYGNUM_SERIAL_PARITY_EVEN:
285
        t->c_iflag |= PARENB;
286
        break;
287
    default:
288
        CYG_FAIL( "Unsupported default parity" );
289
        break;
290
    }
291
 
292
    switch( dev_conf.word_length ) {
293
    case CYGNUM_SERIAL_WORD_LENGTH_5:
294
        t->c_cflag |= CS5;
295
        break;
296
    case CYGNUM_SERIAL_WORD_LENGTH_6:
297
        t->c_cflag |= CS6;
298
        break;
299
    case CYGNUM_SERIAL_WORD_LENGTH_7:
300
        t->c_cflag |= CS7;
301
        break;
302
    case CYGNUM_SERIAL_WORD_LENGTH_8:
303
        t->c_cflag |= CS8;
304
        break;
305
    default:
306
        CYG_FAIL( "Unsupported word length" );
307
        break;
308
    }
309
 
310
    switch ( dev_conf.stop ) {
311
    case CYGNUM_SERIAL_STOP_1:
312
        // Don't need to do anything
313
        break;
314
    case CYGNUM_SERIAL_STOP_2:
315
        t->c_cflag |= CSTOPB;
316
        break;
317
    default:
318
        CYG_FAIL( "Unsupported number of stop bits" );
319
        break;
320
    }
321
 
322
    switch ( dev_conf.flags ) {
323
    case CYGNUM_SERIAL_FLOW_RTSCTS_RX:
324
        t->c_cflag |= CRTSCTS;
325
        // drop through
326
    case CYGNUM_SERIAL_FLOW_XONXOFF_RX:
327
        t->c_iflag |= IXOFF;
328
        break;
329
    case CYGNUM_SERIAL_FLOW_RTSCTS_TX:
330
        t->c_cflag |= CRTSCTS;
331
        // drop through
332
    case CYGNUM_SERIAL_FLOW_XONXOFF_TX:
333
        t->c_iflag |= IXON;
334
        break;
335
    default:
336
        // Ignore flags we don't grok
337
        break;
338
    }
339
 
340
    return ENOERR;
341
} // real_termios_init()
342
 
343
//==========================================================================
344
// set_attr() actually enacts the termios config. We come in here with
345
// the mutex in priv locked
346
//
347
// Possible deviation from standard: POSIX says we should enact which ever
348
// bits we can and only return EINVAL when none of them can be performed
349
// Rather than tracking whether *none* of them worked, instead we just
350
// always claim success. At the very least, setting c_cc is never to
351
// fail so I'm not sure if this is really non-standard or not!
352
 
353
static Cyg_ErrNo
354
set_attr( struct termios *t, struct termios_private_info *priv )
355
{
356
    Cyg_ErrNo res = ENOERR;
357
    cyg_serial_info_t dev_conf, new_dev_conf;
358
    cyg_uint32 len = sizeof( dev_conf );
359
    cc_t *tempcc = &priv->termios.c_cc[0];
360
    struct termios *ptermios = &priv->termios;
361
 
362
    // Get info from driver
363
    res = cyg_io_get_config( priv->dev_handle, CYG_IO_GET_CONFIG_SERIAL_INFO,
364
                             &dev_conf, &len );
365
 
366
    if ( ENOERR != res )
367
        return res;
368
 
369
    // We need to set up each facet of config to change one by one because
370
    // POSIX says we should try and change as much of the config as possible
371
    // This is tedious and has to be done by steam :-(
372
 
373
    if ( t->c_ospeed != ptermios->c_ospeed ) {
374
        new_dev_conf = dev_conf;
375
        new_dev_conf.baud = map_posixbaud_to_ecosbaud( t->c_ospeed );
376
        if ( 0 != new_dev_conf.baud ) {
377
            len = sizeof( new_dev_conf );
378
            res = cyg_io_set_config( priv->dev_handle,
379
                                     CYG_IO_SET_CONFIG_SERIAL_INFO,
380
                                     &new_dev_conf, &len );
381
            if ( ENOERR == res ) {
382
                // It worked, so update dev_conf to reflect the new state
383
                dev_conf.baud = new_dev_conf.baud;
384
                // and termios
385
                ptermios->c_ispeed = t->c_ospeed;
386
                ptermios->c_ospeed = t->c_ospeed;
387
            }
388
        }
389
    }
390
 
391
    if ( (t->c_cflag & CSTOPB) != (ptermios->c_cflag & CSTOPB) ) {
392
        new_dev_conf = dev_conf;
393
        if ( t->c_cflag & CSTOPB )
394
            new_dev_conf.stop = CYGNUM_SERIAL_STOP_2;
395
        else
396
            new_dev_conf.stop = CYGNUM_SERIAL_STOP_1;
397
 
398
        len = sizeof( new_dev_conf );
399
        res = cyg_io_set_config( priv->dev_handle,
400
                                 CYG_IO_SET_CONFIG_SERIAL_INFO,
401
                                 &new_dev_conf, &len );
402
        if ( ENOERR == res ) {
403
            // It worked, so update dev_conf to reflect the new state
404
            dev_conf.stop = new_dev_conf.stop;
405
            // and termios
406
            ptermios->c_cflag &= ~CSTOPB;
407
            ptermios->c_cflag |= t->c_cflag & CSTOPB;
408
        }
409
    }
410
 
411
    if ( ((t->c_cflag & PARENB) != (ptermios->c_cflag & PARENB)) ||
412
         ((t->c_cflag & PARODD) != (ptermios->c_cflag & PARODD)) ) {
413
        new_dev_conf = dev_conf;
414
        if ( t->c_cflag & PARENB )
415
            if ( t->c_cflag & PARODD )
416
                new_dev_conf.parity = CYGNUM_SERIAL_PARITY_ODD;
417
            else
418
                new_dev_conf.parity = CYGNUM_SERIAL_PARITY_EVEN;
419
        else
420
            new_dev_conf.parity = CYGNUM_SERIAL_PARITY_NONE;
421
 
422
        len = sizeof( new_dev_conf );
423
        res = cyg_io_set_config( priv->dev_handle,
424
                                 CYG_IO_SET_CONFIG_SERIAL_INFO,
425
                                 &new_dev_conf, &len );
426
        if ( ENOERR == res ) {
427
            // It worked, so update dev_conf to reflect the new state
428
            dev_conf.parity = new_dev_conf.parity;
429
            // and termios
430
            ptermios->c_cflag &= ~(PARENB|PARODD);
431
            ptermios->c_cflag |= t->c_cflag & (PARENB|PARODD);
432
        }
433
    }
434
 
435
    if ( (t->c_cflag & CSIZE) != (ptermios->c_cflag & CSIZE) ) {
436
        new_dev_conf = dev_conf;
437
        switch ( t->c_cflag & CSIZE ) {
438
        case CS5:
439
            new_dev_conf.word_length = CYGNUM_SERIAL_WORD_LENGTH_5;
440
            break;
441
        case CS6:
442
            new_dev_conf.word_length = CYGNUM_SERIAL_WORD_LENGTH_6;
443
            break;
444
        case CS7:
445
            new_dev_conf.word_length = CYGNUM_SERIAL_WORD_LENGTH_7;
446
            break;
447
        case CS8:
448
            new_dev_conf.word_length = CYGNUM_SERIAL_WORD_LENGTH_8;
449
            break;
450
        }
451
 
452
        len = sizeof( new_dev_conf );
453
        res = cyg_io_set_config( priv->dev_handle,
454
                                 CYG_IO_SET_CONFIG_SERIAL_INFO,
455
                                 &new_dev_conf, &len );
456
        if ( ENOERR == res ) {
457
            // It worked, so update dev_conf to reflect the new state
458
            dev_conf.word_length = new_dev_conf.word_length;
459
            // and termios
460
            ptermios->c_cflag &= ~CSIZE;
461
            ptermios->c_cflag |= t->c_cflag & CSIZE;
462
        }
463
    }
464
 
465
    if ( (t->c_cflag & IXOFF) != (ptermios->c_cflag & IXOFF) ) {
466
        new_dev_conf = dev_conf;
467
        new_dev_conf.flags &=
468
            ~(CYGNUM_SERIAL_FLOW_XONXOFF_RX|CYGNUM_SERIAL_FLOW_RTSCTS_RX);
469
        if ( t->c_cflag & IXOFF )
470
            if ( t->c_cflag & CRTSCTS)
471
                new_dev_conf.flags |= CYGNUM_SERIAL_FLOW_RTSCTS_RX;
472
            else
473
                new_dev_conf.flags |= CYGNUM_SERIAL_FLOW_XONXOFF_RX;
474
        else
475
            new_dev_conf.flags |= CYGNUM_SERIAL_FLOW_NONE;
476
 
477
        len = sizeof( new_dev_conf );
478
        res = cyg_io_set_config( priv->dev_handle,
479
                                 CYG_IO_SET_CONFIG_SERIAL_INFO,
480
                                 &new_dev_conf, &len );
481
        if ( ENOERR == res ) {
482
            // It worked, so update dev_conf to reflect the new state
483
            dev_conf.flags = new_dev_conf.flags;
484
            // and termios
485
            ptermios->c_cflag &= ~(IXOFF|CRTSCTS);
486
            ptermios->c_cflag |= t->c_cflag & (IXOFF|CRTSCTS);
487
        }
488
    }
489
 
490
    if ( (t->c_cflag & IXON) != (ptermios->c_cflag & IXON) ) {
491
        new_dev_conf = dev_conf;
492
        new_dev_conf.flags &=
493
            ~(CYGNUM_SERIAL_FLOW_XONXOFF_TX|CYGNUM_SERIAL_FLOW_RTSCTS_TX);
494
        if ( t->c_cflag & IXON )
495
            if ( t->c_cflag & CRTSCTS)
496
                new_dev_conf.flags |= CYGNUM_SERIAL_FLOW_RTSCTS_TX;
497
            else
498
                new_dev_conf.flags |= CYGNUM_SERIAL_FLOW_XONXOFF_TX;
499
        else
500
            new_dev_conf.flags |= CYGNUM_SERIAL_FLOW_NONE;
501
 
502
        len = sizeof( new_dev_conf );
503
        res = cyg_io_set_config( priv->dev_handle,
504
                                 CYG_IO_SET_CONFIG_SERIAL_INFO,
505
                                 &new_dev_conf, &len );
506
        if ( ENOERR == res ) {
507
            // It worked, so update dev_conf to reflect the new state
508
            dev_conf.flags = new_dev_conf.flags;
509
            // and termios
510
            ptermios->c_cflag &= ~(IXON|CRTSCTS);
511
            ptermios->c_cflag |= t->c_cflag & (IXON|CRTSCTS);
512
        }
513
    }
514
 
515
    // Input/Output processing flags can just be set as we grok them all
516
    // with few exceptions (see lflags below)
517
    ptermios->c_iflag &= ~(BRKINT|ICRNL|IGNBRK|IGNCR|IGNPAR|INLCR|INPCK|
518
                           ISTRIP|PARMRK);
519
    ptermios->c_iflag |= t->c_iflag & (
520
#ifdef CYGSEM_IO_SERIAL_TERMIOS_USE_SIGNALS
521
                                       BRKINT|
522
#endif
523
                                       ICRNL|IGNBRK|IGNCR|IGNPAR|
524
                                       INLCR|INPCK|ISTRIP|PARMRK );
525
 
526
    ptermios->c_oflag &= ~(OPOST|ONLCR);
527
    ptermios->c_oflag |= t->c_oflag & (OPOST|ONLCR);
528
 
529
    ptermios->c_cflag &= ~(CLOCAL|CREAD|HUPCL);
530
    ptermios->c_cflag |= t->c_cflag & (CLOCAL|CREAD|HUPCL);
531
 
532
    ptermios->c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|ICANON|
533
                                 IEXTEN|ISIG|NOFLSH|TOSTOP);
534
    // Note we don't support IEXTEN nor TOSTOP so we don't set them
535
    ptermios->c_lflag |= t->c_lflag & (ECHO|ECHOE|ECHOK|ECHONL|ICANON|
536
#ifdef CYGSEM_IO_SERIAL_TERMIOS_USE_SIGNALS
537
                                       ISIG|
538
#endif
539
                                       NOFLSH);
540
 
541
    // control characters. We don't support changing of VSTART, VSTOP,
542
    // VTIME or VSUSP though
543
    tempcc[VEOF]   = t->c_cc[VEOF];
544
    tempcc[VEOL]   = t->c_cc[VEOL];
545
    tempcc[VERASE] = t->c_cc[VERASE];
546
    tempcc[VINTR]  = t->c_cc[VINTR];
547
    tempcc[VKILL]  = t->c_cc[VKILL];
548
    tempcc[VMIN]   = t->c_cc[VMIN];
549
    tempcc[VQUIT]  = t->c_cc[VQUIT];
550
 
551
    return res;
552
}
553
 
554
//==========================================================================
555
 
556
static bool
557
termios_init(struct cyg_devtab_entry *tab)
558
{
559
    // can't initialize the termios structure because we can't
560
    // query the serial driver yet. Wait until lookup time.
561
 
562
    return true;
563
} // termios_init()
564
 
565
//==========================================================================
566
 
567
static Cyg_ErrNo
568
termios_lookup(struct cyg_devtab_entry **tab,
569
           struct cyg_devtab_entry *sub_tab,
570
           const char *name)
571
{
572
    cyg_io_handle_t chan = (cyg_io_handle_t)sub_tab;
573
    struct termios_private_info *priv =
574
        (struct termios_private_info *)(*tab)->priv;
575
    Cyg_ErrNo err = ENOERR;
576
 
577
    if ( !priv->init ) {
578
        cyg_drv_mutex_lock( &priv->lock );
579
        if ( !priv->init ) {  // retest as we may have been pre-empted
580
            priv->dev_handle = chan;
581
            err = real_termios_init( priv );
582
        }
583
        cyg_drv_mutex_unlock( &priv->lock );
584
    }
585
    return err;
586
}
587
 
588
//==========================================================================
589
 
590
#define WRITE_BUFSIZE 100 // FIXME: ->CDL
591
// #define MAX_CANON 64  FIXME: relevance?
592
 
593
 
594
static Cyg_ErrNo
595
termios_write(cyg_io_handle_t handle, const void *_buf, cyg_uint32 *len)
596
{
597
    cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle;
598
    struct termios_private_info *priv = (struct termios_private_info *)t->priv;
599
    cyg_io_handle_t chan = (cyg_io_handle_t)priv->dev_handle;
600
    cyg_int32 xbufsize, input_bytes_read;
601
    cyg_uint8 xbuf[WRITE_BUFSIZE];
602
    cyg_uint8 *buf = (cyg_uint8 *)_buf;
603
    Cyg_ErrNo res;
604
 
605
    xbufsize = input_bytes_read = 0;
606
    while (input_bytes_read++ < *len) {
607
        if ( (*buf == '\n') && (priv->termios.c_oflag & (OPOST|ONLCR)) ) {
608
            xbuf[xbufsize++] = '\r';
609
        }
610
        xbuf[xbufsize++] = *buf;
611
        if ((xbufsize >= (WRITE_BUFSIZE-1)) || (input_bytes_read == *len) ||
612
            (*buf == '\n'))
613
        {
614
            cyg_int32 size = xbufsize;
615
            res = cyg_io_write(chan, xbuf, &size);
616
            if (res != ENOERR) {
617
                *len = input_bytes_read - (xbufsize - size);
618
                return res;
619
            }
620
            xbufsize = 0;
621
        }
622
        buf++;
623
    }
624
    // Everything sent, so *len is correct.
625
    return ENOERR;
626
}
627
 
628
 
629
//==========================================================================
630
 
631
static Cyg_ErrNo
632
termios_read(cyg_io_handle_t handle, void *_buf, cyg_uint32 *len)
633
{
634
    cyg_devtab_entry_t *dt = (cyg_devtab_entry_t *)handle;
635
    struct termios_private_info *priv = (struct termios_private_info *)dt->priv;
636
    cyg_io_handle_t chan = (cyg_io_handle_t)priv->dev_handle;
637
    struct termios *t = &priv->termios;
638
    cyg_uint32 clen;
639
    cyg_uint32 size;
640
    Cyg_ErrNo res;
641
    cyg_uint8 c;
642
    cyg_uint8 *buf = (cyg_uint8 *)_buf;
643
    cyg_bool discardc; // should c be discarded (not read, not printed)
644
    cyg_bool returnnow = false; // return back to user after this char
645
 
646
    // if receiver off
647
    if (0 == (t->c_cflag & CREAD) ) {
648
        *len = 0;
649
        return -EINVAL;
650
    }
651
 
652
    size = 0;
653
    if ( 0 == (t->c_lflag & ICANON) ) {
654
        // In non-canonical mode we return the min of *len and the
655
        // number of bytes available
656
        // So we query the driver for how many bytes are available - this
657
        // guarantees we won't block
658
        cyg_serial_buf_info_t dev_buf_conf;
659
        cyg_uint32 dbc_len = sizeof( dev_buf_conf );
660
        res = cyg_io_get_config( chan,
661
                                 CYG_IO_GET_CONFIG_SERIAL_BUFFER_INFO,
662
                                 &dev_buf_conf, &dbc_len );
663
        CYG_ASSERT( res == ENOERR, "Query buffer status failed!" );
664
        *len = *len < dev_buf_conf.rx_count ? *len : dev_buf_conf.rx_count;
665
    } // if
666
 
667
    while (!returnnow && size < *len) {
668
        clen = 1;
669
        discardc = false;
670
        res = cyg_io_read(chan, &c, &clen);
671
        if (res != ENOERR) {
672
            *len = size;
673
            return res;
674
        }
675
 
676
        // lock to prevent termios getting corrupted while we read from it
677
        cyg_drv_mutex_lock( &priv->lock );
678
 
679
        if ( t->c_iflag & ISTRIP )
680
            c &= 0x7f;
681
 
682
        // canonical mode: erase, kill, and newline processing
683
        if ( t->c_lflag & ICANON ) {
684
            if ( t->c_cc[ VERASE ] == c ) {
685
                discardc = true;
686
                // erase on display?
687
                if ( (t->c_lflag & ECHO) && (t->c_lflag & ECHOE) ) {
688
                    cyg_uint8 erasebuf[3];
689
                    erasebuf[0] = erasebuf[2] = t->c_cc[ VERASE ];
690
                    erasebuf[1] = ' ';
691
                    clen = sizeof(erasebuf);
692
                    // FIXME: what about error or non-blocking?
693
                    cyg_io_write(chan, erasebuf, &clen);
694
                }
695
                if ( size )
696
                    size--;
697
            } // if
698
            else if ( t->c_cc[ VKILL ] == c ) {
699
                // kill line on display?
700
                if ( (t->c_lflag & ECHO) && (t->c_lflag & ECHOK) ) {
701
 
702
                    // we could try and be more efficient here and 
703
                    // output a stream of erases, and then a stream
704
                    // of spaces and then more erases. But this is poor
705
                    // because on a slow terminal the user will see characters
706
                    // delete from the middle forward in chunks!
707
                    // But at least we try and chunk up sets of writes
708
                    cyg_uint8 erasebuf[30];
709
                    cyg_uint8 erasechunks;
710
                    cyg_uint8 i;
711
 
712
                    erasechunks = size < (sizeof(erasebuf)/3) ?
713
                        size : (sizeof(erasebuf)/3);
714
 
715
                    for (i=0; i<erasechunks; i++) {
716
                        erasebuf[i*3] = erasebuf[i*3+2] = t->c_cc[ VERASE ];
717
                        erasebuf[i*3+1] = ' ';
718
                    }
719
 
720
                    while( size ) {
721
                        cyg_uint8 j;
722
 
723
                        j = size < (sizeof(erasebuf)/3) ?
724
                            size : (sizeof(erasebuf)/3);
725
                        clen = (j*3);
726
                        // FIXME: what about error or non-blocking?
727
                        cyg_io_write( chan, erasebuf, &clen );
728
                        size -= j;
729
                    }
730
                } else
731
                    size = 0;
732
                discardc = true;
733
            } // else if
734
            // CR
735
            else if ( '\r' == c ) {
736
                if ( t->c_iflag & IGNCR )
737
                    discardc = true;
738
                else if ( t->c_iflag & ICRNL )
739
                    c = '\n';
740
            }
741
            // newlines or similar.
742
            // Note: not an else if to catch CRNL conversion
743
            if ( (t->c_cc[ VEOF ] == c) || (t->c_cc[ VEOL ] == c) ||
744
                 ('\n' == c) ) {
745
                if ( t->c_cc[ VEOF ] == c )
746
                     discardc = true;
747
                if ( t->c_lflag & ECHONL ) { // don't check ECHO in this case
748
                    clen = 1;
749
                    // FIXME: what about error or non-blocking?
750
                    // FIXME: what if INLCR is set?
751
                    cyg_io_write( chan, "\n", &clen );
752
                }
753
                if ( t->c_iflag & INLCR )
754
                    c = '\r';
755
                returnnow = true; // FIXME: true even for INLCR?
756
            } // else if
757
        } else { // non-canonical mode
758
            if ( t->c_cc[ VMIN ] && (size+1 >= t->c_cc[ VMIN ]) )
759
                returnnow = true;
760
        } // else
761
 
762
#ifdef CYGSEM_IO_SERIAL_TERMIOS_USE_SIGNALS
763
        if ( (t->c_lflag & ISIG) && (t->c_cc[ VINTR ] == c) ) {
764
            discardc = true;
765
            if ( 0 == (t->c_lflag & NOFLSH) )
766
                size = 0;
767
            // raise could be a non-local jump - we should unlock mutex
768
            cyg_drv_mutex_unlock( &priv->lock );
769
 
770
            // FIXME: what if raise returns != 0?
771
            raise( SIGINT );
772
            cyg_drv_mutex_lock( &priv->lock );
773
        }
774
 
775
        if ( (t->c_lflag & ISIG) && (t->c_cc[ VQUIT ] == c) ) {
776
            discardc = true;
777
            if ( 0 == (t->c_lflag & NOFLSH) )
778
                size = 0;
779
            // raise could be a non-local jump - we should unlock mutex
780
            cyg_drv_mutex_unlock( &priv->lock );
781
 
782
            // FIXME: what if raise returns != 0?
783
            raise( SIGQUIT );
784
            cyg_drv_mutex_lock( &priv->lock );
785
        }
786
#endif
787
        if (!discardc) {
788
            buf[size++] = c;
789
            if ( t->c_lflag & ECHO ) {
790
                clen = 1;
791
                // FIXME: what about error or non-blocking?
792
                termios_write( handle, &c, &clen );
793
            }
794
        }
795
        cyg_drv_mutex_unlock( &priv->lock );
796
    } // while
797
 
798
    *len = size;
799
    return ENOERR;
800
}
801
 
802
 
803
//==========================================================================
804
 
805
static cyg_bool
806
termios_select(cyg_io_handle_t handle, cyg_uint32 which, CYG_ADDRWORD info)
807
{
808
    cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle;
809
    struct termios_private_info *priv = (struct termios_private_info *)t->priv;
810
    cyg_io_handle_t chan = (cyg_io_handle_t)priv->dev_handle;
811
 
812
    // Just pass it on to next driver level
813
    return cyg_io_select( chan, which, info );
814
}
815
 
816
 
817
//==========================================================================
818
 
819
static Cyg_ErrNo
820
termios_get_config(cyg_io_handle_t handle, cyg_uint32 key, void *buf,
821
                   cyg_uint32 *len)
822
{
823
    cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle;
824
    struct termios_private_info *priv = (struct termios_private_info *)t->priv;
825
    cyg_io_handle_t chan = (cyg_io_handle_t)priv->dev_handle;
826
    Cyg_ErrNo res = ENOERR;
827
 
828
    switch (key) {
829
    case CYG_IO_GET_CONFIG_TERMIOS:
830
        {
831
            if ( *len < sizeof(struct termios) ) {
832
                return -EINVAL;
833
            }
834
            cyg_drv_mutex_lock( &priv->lock );
835
            *(struct termios *)buf = priv->termios;
836
            cyg_drv_mutex_unlock( &priv->lock );
837
            *len = sizeof(struct termios);
838
        }
839
        break;
840
    default:  // Assume this is a 'serial' driver control
841
        res = cyg_io_get_config(chan, key, buf, len);
842
    } // switch
843
    return res;
844
}
845
 
846
 
847
//==========================================================================
848
 
849
 
850
static Cyg_ErrNo
851
termios_set_config(cyg_io_handle_t handle, cyg_uint32 key, const void *buf, cyg_uint32 *len)
852
{
853
    cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle;
854
    struct termios_private_info *priv = (struct termios_private_info *)t->priv;
855
    cyg_io_handle_t chan = (cyg_io_handle_t)priv->dev_handle;
856
    Cyg_ErrNo res = ENOERR;
857
 
858
    switch (key) {
859
    case CYG_IO_SET_CONFIG_TERMIOS:
860
        {
861
            setattr_struct *attr = (setattr_struct *)buf;
862
            int optact = attr->optact;
863
 
864
            if ( *len != sizeof( *attr ) ) {
865
                return -EINVAL;
866
            }
867
 
868
            CYG_ASSERT( (optact == TCSAFLUSH) || (optact == TCSADRAIN) ||
869
                        (optact == TCSANOW), "Invalid optact" );
870
 
871
            cyg_drv_mutex_lock( &priv->lock );
872
 
873
            if ( ( TCSAFLUSH == optact ) ||
874
                 ( TCSADRAIN == optact ) ) {
875
                res = cyg_io_get_config( chan,
876
                                         CYG_IO_GET_CONFIG_SERIAL_OUTPUT_DRAIN,
877
                                         NULL, NULL );
878
                CYG_ASSERT( ENOERR == res, "Drain request failed" );
879
            }
880
            if ( TCSAFLUSH == optact ) {
881
                res = cyg_io_get_config( chan,
882
                                         CYG_IO_GET_CONFIG_SERIAL_INPUT_FLUSH,
883
                                         NULL, NULL );
884
                CYG_ASSERT( ENOERR == res, "Flush request failed" );
885
            }
886
 
887
            res = set_attr( attr->termios_p, priv );
888
            cyg_drv_mutex_unlock( &priv->lock );
889
            return res;
890
        }
891
    default: // Pass on to serial driver
892
        res = cyg_io_set_config(chan, key, buf, len);
893
    }
894
    return res;
895
}
896
 
897
 
898
//==========================================================================
899
 
900
#endif // ifdef CYGPKG_IO_SERIAL_TERMIOS
901
 
902
// EOF termiostty.c

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.