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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [io/] [serial/] [current/] [src/] [common/] [serial.c] - Blame information for rev 786

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 786 skrzyp
//==========================================================================
2
//
3
//      io/serial/common/serial.c
4
//
5
//      High level serial 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, 2003 Free Software Foundation, Inc.
12
//
13
// eCos is free software; you can redistribute it and/or modify it under    
14
// the terms of the GNU General Public License as published by the Free     
15
// Software Foundation; either version 2 or (at your option) any later      
16
// version.                                                                 
17
//
18
// eCos is distributed in the hope that it will be useful, but WITHOUT      
19
// ANY 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        
24
// along with eCos; if not, write to the Free Software Foundation, Inc.,    
25
// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
26
//
27
// As a special exception, if other files instantiate templates or use      
28
// macros or inline functions from this file, or you compile this file      
29
// and link it with other works to produce a work based on this file,       
30
// this file does not by itself cause the resulting work to be covered by   
31
// the GNU General Public License. However the source code for this file    
32
// must still be made available in accordance with section (3) of the GNU   
33
// General Public License v2.                                               
34
//
35
// This exception does not invalidate any other reasons why a work based    
36
// on this file might be covered by the GNU General Public License.         
37
// -------------------------------------------                              
38
// ####ECOSGPLCOPYRIGHTEND####                                              
39
//==========================================================================
40
//#####DESCRIPTIONBEGIN####
41
//
42
// Author(s):    gthomas
43
// Contributors: gthomas, grante, jlarmour, jskov
44
// Date:         1999-02-04
45
// Purpose:      Top level serial driver
46
// Description: 
47
//
48
//####DESCRIPTIONEND####
49
//
50
//==========================================================================
51
 
52
#include <pkgconf/io.h>
53
#include <pkgconf/io_serial.h>
54
 
55
#include <cyg/io/io.h>
56
#include <cyg/io/devtab.h>
57
#include <cyg/io/serial.h>
58
#include <cyg/infra/cyg_ass.h>      // assertion support
59
#include <cyg/infra/diag.h>         // diagnostic output
60
 
61
static Cyg_ErrNo serial_write(cyg_io_handle_t handle, const void *buf, cyg_uint32 *len);
62
static Cyg_ErrNo serial_read(cyg_io_handle_t handle, void *buf, cyg_uint32 *len);
63
static cyg_bool serial_select(cyg_io_handle_t handle, cyg_uint32 which, CYG_ADDRWORD info);
64
static Cyg_ErrNo serial_get_config(cyg_io_handle_t handle, cyg_uint32 key, void *buf, cyg_uint32 *len);
65
static Cyg_ErrNo serial_set_config(cyg_io_handle_t handle, cyg_uint32 key, const void *buf, cyg_uint32 *len);
66
 
67
DEVIO_TABLE(cyg_io_serial_devio,
68
            serial_write,
69
            serial_read,
70
            serial_select,
71
            serial_get_config,
72
            serial_set_config
73
    );
74
 
75
static void serial_init(serial_channel *chan);
76
static void serial_xmt_char(serial_channel *chan);
77
static void serial_rcv_char(serial_channel *chan, unsigned char c);
78
#ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUS
79
static void serial_indicate_status(serial_channel *chan,
80
                                   cyg_serial_line_status_t *s);
81
#endif
82
#if CYGINT_IO_SERIAL_BLOCK_TRANSFER
83
static rcv_req_reply_t serial_data_rcv_req(serial_channel *chan, int avail,
84
                                           int* space_avail,
85
                                           unsigned char** space);
86
static void serial_data_rcv_done(serial_channel *chan, int chars_rcvd);
87
static xmt_req_reply_t serial_data_xmt_req(serial_channel *chan, int space,
88
                                           int* chars_avail,
89
                                           unsigned char** chars);
90
static void serial_data_xmt_done(serial_channel *chan, int chars_sent);
91
# ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUS
92
SERIAL_CALLBACKS(cyg_io_serial_callbacks,
93
                 serial_init,
94
                 serial_xmt_char,
95
                 serial_rcv_char,
96
                 serial_data_rcv_req,
97
                 serial_data_rcv_done,
98
                 serial_data_xmt_req,
99
                 serial_data_xmt_done,
100
                 serial_indicate_status);
101
 
102
# else
103
SERIAL_CALLBACKS(cyg_io_serial_callbacks,
104
                 serial_init,
105
                 serial_xmt_char,
106
                 serial_rcv_char,
107
                 serial_data_rcv_req,
108
                 serial_data_rcv_done,
109
                 serial_data_xmt_req,
110
                 serial_data_xmt_done);
111
# endif
112
#else
113
# ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUS
114
SERIAL_CALLBACKS(cyg_io_serial_callbacks,
115
                 serial_init,
116
                 serial_xmt_char,
117
                 serial_rcv_char,
118
                 serial_indicate_status);
119
# else
120
SERIAL_CALLBACKS(cyg_io_serial_callbacks,
121
                 serial_init,
122
                 serial_xmt_char,
123
                 serial_rcv_char);
124
# endif
125
#endif
126
 
127
// ---------------------------------------------------------------------------
128
 
129
#ifdef CYGPKG_IO_SERIAL_FLOW_CONTROL
130
 
131
static __inline__ void
132
throttle_tx( serial_channel *chan )
133
{
134
    chan->flow_desc.flags |= CYG_SERIAL_FLOW_OUT_THROTTLED;
135
    // the throttling itself occurs in the serial_xmt_char() callback
136
}
137
 
138
static __inline__ void
139
restart_tx( serial_channel *chan )
140
{
141
    serial_funs *funs = chan->funs;
142
 
143
    chan->flow_desc.flags &= ~CYG_SERIAL_FLOW_OUT_THROTTLED;
144
 
145
#ifdef CYGPKG_IO_SERIAL_SELECT_SUPPORT
146
    // See if there is now enough room to say it is available
147
    // for writing
148
    {
149
        cbuf_t *cbuf = &chan->out_cbuf;
150
        int space;
151
 
152
        space = cbuf->len - cbuf->nb;
153
        if (space >= cbuf->low_water)
154
            cyg_selwakeup( &cbuf->selinfo );
155
    }
156
#endif
157
    if ( chan->out_cbuf.nb > 0 )
158
        (funs->start_xmit)(chan);
159
}
160
 
161
static __inline__ void
162
throttle_rx( serial_channel *chan, cyg_bool force )
163
{
164
    serial_funs *funs = chan->funs;
165
#ifdef CYGOPT_IO_SERIAL_FLOW_CONTROL_SOFTWARE
166
    cyg_uint32 prev_flags = chan->flow_desc.flags;
167
#endif
168
 
169
    chan->flow_desc.flags |= CYG_SERIAL_FLOW_IN_THROTTLED;
170
#ifdef CYGOPT_IO_SERIAL_FLOW_CONTROL_SOFTWARE
171
    // send an xoff if not already done (throttled)
172
    if ( force ||
173
        ((chan->config.flags & CYGNUM_SERIAL_FLOW_XONXOFF_RX) &&
174
         (0==(prev_flags & CYG_SERIAL_FLOW_IN_THROTTLED))) ) {
175
        CYG_ASSERT(force||(chan->flow_desc.xchar=='\0')||(chan->flow_desc.xchar==CYGDAT_IO_SERIAL_FLOW_CONTROL_XOFF_CHAR), "xchar already set (XOFF)");
176
        chan->flow_desc.xchar = CYGDAT_IO_SERIAL_FLOW_CONTROL_XOFF_CHAR;
177
        // Make sure xmit is running so we can send it
178
        (funs->start_xmit)(chan);
179
    }
180
#endif
181
#ifdef CYGOPT_IO_SERIAL_FLOW_CONTROL_HW
182
    {
183
        cyg_uint32 i=1;
184
        cyg_uint32 len = sizeof(i);
185
 
186
        // set hardware flow control - don't care if it fails
187
        if ( force || (chan->config.flags & CYGNUM_SERIAL_FLOW_RTSCTS_RX) ||
188
             (chan->config.flags & CYGNUM_SERIAL_FLOW_DSRDTR_RX) )
189
            (funs->set_config)(chan,
190
                               CYG_IO_SET_CONFIG_SERIAL_HW_RX_FLOW_THROTTLE,
191
                               &i, &len);
192
    }
193
#endif
194
}
195
 
196
static __inline__ void
197
restart_rx( serial_channel *chan, cyg_bool force )
198
{
199
    serial_funs *funs = chan->funs;
200
#ifdef CYGOPT_IO_SERIAL_FLOW_CONTROL_SOFTWARE
201
    cyg_uint32 prev_flags = chan->flow_desc.flags;
202
#endif
203
 
204
    chan->flow_desc.flags &= ~CYG_SERIAL_FLOW_IN_THROTTLED;
205
#ifdef CYGOPT_IO_SERIAL_FLOW_CONTROL_SOFTWARE
206
    // send an xon, if we haven't already
207
    if ( force ||
208
        ((chan->config.flags & CYGNUM_SERIAL_FLOW_XONXOFF_RX) &&
209
         (prev_flags & CYG_SERIAL_FLOW_IN_THROTTLED)) ) {
210
        CYG_ASSERT(force||(chan->flow_desc.xchar=='\0')||(chan->flow_desc.xchar==CYGDAT_IO_SERIAL_FLOW_CONTROL_XON_CHAR), "xchar already set (XON)");
211
        chan->flow_desc.xchar = CYGDAT_IO_SERIAL_FLOW_CONTROL_XON_CHAR;
212
        (funs->start_xmit)(chan);  // Make sure xmit is running so we can send it
213
    }
214
#endif
215
#ifdef CYGOPT_IO_SERIAL_FLOW_CONTROL_HW
216
    {
217
        cyg_uint32 i=0;
218
        cyg_uint32 len = sizeof(i);
219
 
220
        // set hardware flow control - don't care if it fails
221
        if ( force || (chan->config.flags & CYGNUM_SERIAL_FLOW_RTSCTS_RX) ||
222
             (chan->config.flags & CYGNUM_SERIAL_FLOW_DSRDTR_RX) )
223
            (funs->set_config)(chan,
224
                               CYG_IO_SET_CONFIG_SERIAL_HW_RX_FLOW_THROTTLE,
225
                               &i, &len);
226
    }
227
#endif
228
}
229
 
230
#endif
231
 
232
// ---------------------------------------------------------------------------
233
 
234
static void
235
serial_init(serial_channel *chan)
236
{
237
    if (chan->init) return;
238
    if (chan->out_cbuf.len != 0) {
239
#ifdef CYGDBG_IO_INIT
240
        diag_printf("Set output buffer - buf: %p len: %d\n", chan->out_cbuf.data, chan->out_cbuf.len);
241
#endif
242
        chan->out_cbuf.waiting = false;
243
        chan->out_cbuf.abort = false;
244
#ifdef CYGOPT_IO_SERIAL_SUPPORT_NONBLOCKING
245
        chan->out_cbuf.blocking = true;
246
#endif
247
        chan->out_cbuf.pending = 0;
248
        cyg_drv_mutex_init(&chan->out_cbuf.lock);
249
        cyg_drv_cond_init(&chan->out_cbuf.wait, &chan->out_cbuf.lock);
250
        chan->out_cbuf.low_water = chan->out_cbuf.len / 4;
251
#ifdef CYGPKG_IO_SERIAL_SELECT_SUPPORT
252
        cyg_selinit( &chan->out_cbuf.selinfo );
253
#endif        
254
    }
255
    if (chan->in_cbuf.len != 0) {
256
        cbuf_t *cbuf = &chan->in_cbuf;
257
 
258
#ifdef CYGDBG_IO_INIT
259
        diag_printf("Set input buffer - buf: %p len: %d\n", cbuf->data, cbuf->len);
260
#endif
261
        cbuf->waiting = false;
262
        cbuf->abort = false;
263
#ifdef CYGOPT_IO_SERIAL_SUPPORT_NONBLOCKING
264
        cbuf->blocking = true;
265
#endif
266
#ifdef CYGPKG_IO_SERIAL_SELECT_SUPPORT
267
        cyg_selinit( &cbuf->selinfo );
268
#endif
269
#ifdef CYGPKG_IO_SERIAL_FLOW_CONTROL
270
        cbuf->low_water =
271
            (CYGNUM_IO_SERIAL_FLOW_CONTROL_LOW_WATER_PERCENT * cbuf->len) / 100;
272
        cbuf->high_water =
273
            (CYGNUM_IO_SERIAL_FLOW_CONTROL_HIGH_WATER_PERCENT * cbuf->len) / 100;
274
# ifdef CYGOPT_IO_SERIAL_FLOW_CONTROL_SOFTWARE
275
        // But make sure it is at least 35 below buffer size, to allow
276
        // for 16 byte fifos, twice, plus some latency before s/w flow
277
        // control can kick in. This doesn't apply to h/w flow control
278
        // as it is near-instantaneous
279
        if ( (cbuf->len - cbuf->high_water) < 35 )
280
            cbuf->high_water = cbuf->len - 35;
281
        // and just in case...
282
        if ( cbuf->high_water <= 0 )
283
            cbuf->high_water = 1;
284
        if ( cbuf->low_water > cbuf->high_water )
285
            cbuf->low_water = cbuf->high_water;
286
# endif
287
#endif
288
        cyg_drv_mutex_init(&cbuf->lock);
289
        cyg_drv_cond_init(&cbuf->wait, &cbuf->lock);
290
    }
291
#ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUS
292
    chan->status_callback = NULL;
293
#endif
294
 
295
#ifdef CYGDBG_USE_ASSERTS
296
#if CYGINT_IO_SERIAL_BLOCK_TRANSFER
297
    chan->in_cbuf.block_mode_xfer_running = false;
298
    chan->out_cbuf.block_mode_xfer_running = false;
299
#endif // CYGINT_IO_SERIAL_BLOCK_TRANSFER
300
#endif // CYGDBG_USE_ASSERTS
301
    chan->init = true;
302
}
303
 
304
// ---------------------------------------------------------------------------
305
 
306
static Cyg_ErrNo
307
serial_write(cyg_io_handle_t handle, const void *_buf, cyg_uint32 *len)
308
{
309
    cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle;
310
    serial_channel *chan = (serial_channel *)t->priv;
311
    serial_funs *funs = chan->funs;
312
    cyg_int32 size = *len;
313
    cyg_uint8 *buf = (cyg_uint8 *)_buf;
314
    int next;
315
    cbuf_t *cbuf = &chan->out_cbuf;
316
    Cyg_ErrNo res = ENOERR;
317
 
318
    cyg_drv_mutex_lock(&cbuf->lock);
319
    cbuf->abort = false;
320
 
321
    if (cbuf->len == 0) {
322
        // Non interrupt driven (i.e. polled) operation
323
        while (size-- > 0) {
324
#ifdef CYGPKG_IO_SERIAL_FLOW_CONTROL
325
            while ( ( 0 != (chan->flow_desc.flags & CYG_SERIAL_FLOW_OUT_THROTTLED) ) ||
326
                    ((funs->putc)(chan, *buf) == false) )
327
                ;  // Ignore full, keep trying
328
#else
329
            while ((funs->putc)(chan, *buf) == false)
330
                ;  // Ignore full, keep trying
331
#endif
332
            buf++;
333
        }
334
    } else {
335
        cyg_drv_dsr_lock();  // Avoid race condition testing pointers
336
        while (size > 0) {
337
            next = cbuf->put + 1;
338
            if (next == cbuf->len) next = 0;
339
            if (cbuf->nb == cbuf->len) {
340
                cbuf->waiting = true;
341
                // Buffer full - wait for space
342
#ifdef CYGPKG_IO_SERIAL_FLOW_CONTROL
343
                if ( 0 == (chan->flow_desc.flags & CYG_SERIAL_FLOW_OUT_THROTTLED) )
344
#endif
345
                    (funs->start_xmit)(chan);  // Make sure xmit is running
346
 
347
                // Check flag: 'start_xmit' may have obviated the need
348
                // to wait :-)
349
                if (cbuf->waiting) {
350
#ifdef CYGOPT_IO_SERIAL_SUPPORT_NONBLOCKING
351
                    // Optionally return if configured for non-blocking mode.
352
                    if (!cbuf->blocking) {
353
                        *len -= size;   // number of characters actually sent
354
                        cbuf->waiting = false;
355
                        res = (*len == 0) ? -EAGAIN : ENOERR;
356
                        break;
357
                    }
358
#endif // CYGOPT_IO_SERIAL_SUPPORT_NONBLOCKING
359
                    cbuf->pending += size;  // Have this much more to send [eventually]
360
                    if( !cyg_drv_cond_wait(&cbuf->wait) )
361
                        cbuf->abort = true;
362
                    cbuf->pending -= size;
363
                }
364
                if (cbuf->abort) {
365
                    // Give up!
366
                    *len -= size;   // number of characters actually sent
367
                    cbuf->abort = false;
368
                    cbuf->waiting = false;
369
                    res = -EINTR;
370
                    break;
371
                }
372
            } else {
373
                cbuf->data[cbuf->put++] = *buf++;
374
                cbuf->put = next;
375
                cbuf->nb++;
376
                size--;  // Only count if actually sent!
377
            }
378
        }
379
#ifdef CYGPKG_IO_SERIAL_FLOW_CONTROL
380
        if ( 0 == (chan->flow_desc.flags & CYG_SERIAL_FLOW_OUT_THROTTLED) )
381
#endif
382
            (funs->start_xmit)(chan);  // Start output as necessary
383
        cyg_drv_dsr_unlock();
384
    }
385
    cyg_drv_mutex_unlock(&cbuf->lock);
386
    return res;
387
}
388
 
389
 
390
// ---------------------------------------------------------------------------
391
 
392
static Cyg_ErrNo
393
serial_read(cyg_io_handle_t handle, void *_buf, cyg_uint32 *len)
394
{
395
    cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle;
396
    serial_channel *chan = (serial_channel *)t->priv;
397
    serial_funs *funs = chan->funs;
398
    cyg_uint8 *buf = (cyg_uint8 *)_buf;
399
    cyg_int32 size = 0;
400
    cbuf_t *cbuf = &chan->in_cbuf;
401
    Cyg_ErrNo res = ENOERR;
402
#ifdef XX_CYGDBG_DIAG_BUF
403
            extern int enable_diag_uart;
404
            int _enable = enable_diag_uart;
405
            int _time, _stime;
406
            externC cyg_tick_count_t cyg_current_time(void);
407
#endif // CYGDBG_DIAG_BUF
408
 
409
    cyg_drv_mutex_lock(&cbuf->lock);
410
    cbuf->abort = false;
411
 
412
    if (cbuf->len == 0) {
413
        // Non interrupt driven (i.e. polled) operation
414
        while (size++ < *len) {
415
            cyg_uint8 c = (funs->getc)(chan);
416
#ifdef CYGOPT_IO_SERIAL_FLOW_CONTROL_SOFTWARE
417
            // for software flow control, if the driver returns one of the
418
            // characters we act on it and then drop it (the app must not
419
            // see it)
420
            if ( chan->config.flags & CYGNUM_SERIAL_FLOW_XONXOFF_TX ) {
421
                if ( c == CYGDAT_IO_SERIAL_FLOW_CONTROL_XOFF_CHAR ) {
422
                    throttle_tx( chan );
423
                } else if ( c == CYGDAT_IO_SERIAL_FLOW_CONTROL_XON_CHAR ) {
424
                    restart_tx( chan );
425
                }
426
                else
427
                    *buf++ = c;
428
            }
429
            else
430
                *buf++ = c;
431
#else
432
            *buf++ = c;
433
#endif    
434
        }
435
    } else {
436
        cyg_drv_dsr_lock();  // Avoid races
437
        while (size < *len) {
438
            if (cbuf->nb > 0) {
439
#ifdef CYGPKG_IO_SERIAL_FLOW_CONTROL
440
                if ( (cbuf->nb <= cbuf->low_water) &&
441
                     (chan->flow_desc.flags & CYG_SERIAL_FLOW_IN_THROTTLED) )
442
                    restart_rx( chan, false );
443
#endif
444
                *buf++ = cbuf->data[cbuf->get];
445
                if (++cbuf->get == cbuf->len) cbuf->get = 0;
446
                cbuf->nb--;
447
                size++;
448
            } else {
449
#ifdef CYGOPT_IO_SERIAL_SUPPORT_NONBLOCKING
450
                if (!cbuf->blocking) {
451
                    *len = size;        // characters actually read
452
                    res = size == 0 ? -EAGAIN : ENOERR;
453
                    break;
454
                }
455
#endif // CYGOPT_IO_SERIAL_SUPPORT_NONBLOCKING
456
                cbuf->waiting = true;
457
#ifdef XX_CYGDBG_DIAG_BUF
458
                enable_diag_uart = 0;
459
                HAL_CLOCK_READ(&_time);
460
                _stime = (int)cyg_current_time();
461
                diag_printf("READ wait - get: %d, put: %d, time: %x.%x\n", cbuf->get, cbuf->put, _stime, _time);
462
                enable_diag_uart = _enable;
463
#endif // CYGDBG_DIAG_BUF
464
                if( !cyg_drv_cond_wait(&cbuf->wait) )
465
                    cbuf->abort = true;
466
#ifdef XX_CYGDBG_DIAG_BUF
467
                enable_diag_uart = 0;
468
                HAL_CLOCK_READ(&_time);
469
                _stime = (int)cyg_current_time();
470
                diag_printf("READ continue - get: %d, put: %d, time: %x.%x\n", cbuf->get, cbuf->put, _stime, _time);
471
                enable_diag_uart = _enable;
472
#endif // CYGDBG_DIAG_BUF
473
                if (cbuf->abort) {
474
                    // Give up!
475
                    *len = size;        // characters actually read
476
                    cbuf->abort = false;
477
                    cbuf->waiting = false;
478
                    res = -EINTR;
479
                    break;
480
                }
481
            }
482
        }
483
        cyg_drv_dsr_unlock();
484
    }
485
#ifdef XX_CYGDBG_DIAG_BUF
486
    cyg_drv_isr_lock();
487
    enable_diag_uart = 0;
488
    HAL_CLOCK_READ(&_time);
489
    _stime = (int)cyg_current_time();
490
    diag_printf("READ done - size: %d, len: %d, time: %x.%x\n", size, *len, _stime, _time);
491
    enable_diag_uart = _enable;
492
    cyg_drv_isr_unlock();
493
#endif // CYGDBG_DIAG_BUF
494
    cyg_drv_mutex_unlock(&cbuf->lock);
495
    return res;
496
}
497
 
498
 
499
// ---------------------------------------------------------------------------
500
 
501
static cyg_bool
502
serial_select(cyg_io_handle_t handle, cyg_uint32 which, CYG_ADDRWORD info)
503
{
504
#ifdef CYGPKG_IO_SERIAL_SELECT_SUPPORT
505
 
506
    cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle;
507
    serial_channel *chan = (serial_channel *)t->priv;
508
    cyg_bool retval = false;
509
 
510
    switch( which )
511
    {
512
    case CYG_FREAD:
513
        {
514
            cbuf_t *cbuf = &chan->in_cbuf;
515
 
516
            cyg_drv_mutex_lock(&cbuf->lock);
517
            cyg_drv_dsr_lock(); // Avoid races
518
 
519
            // Check for data in the input buffer. If there is none,
520
            // register the select operation, otherwise return true.
521
 
522
            if( cbuf->nb == 0 )
523
                cyg_selrecord( info, &cbuf->selinfo );
524
            else retval = true;
525
 
526
            cyg_drv_dsr_unlock();
527
            cyg_drv_mutex_unlock(&cbuf->lock);
528
        }
529
        break;
530
 
531
    case CYG_FWRITE:
532
        {
533
            // Check for space in the output buffer. If there is none,
534
            // register the select operation, otherwise return true.
535
 
536
            int space ;
537
            cbuf_t *cbuf = &chan->out_cbuf;
538
 
539
            cyg_drv_mutex_lock(&cbuf->lock);
540
            cyg_drv_dsr_lock(); // Avoid races
541
 
542
            space = cbuf->len - cbuf->nb;
543
#ifdef CYGPKG_IO_SERIAL_FLOW_CONTROL
544
            if ( (space < cbuf->low_water) ||
545
                 (chan->flow_desc.flags & CYG_SERIAL_FLOW_OUT_THROTTLED) )
546
                cyg_selrecord( info, &cbuf->selinfo );
547
#else
548
            if (space < cbuf->low_water)
549
                cyg_selrecord( info, &cbuf->selinfo );
550
#endif
551
            else retval = true;
552
 
553
            cyg_drv_dsr_unlock();
554
            cyg_drv_mutex_unlock(&cbuf->lock);
555
        }
556
        break;
557
 
558
    case 0: // exceptions - none supported
559
        break;
560
    }
561
    return retval;
562
#else
563
 
564
    // With no select support, we simply return true.
565
    return true;
566
#endif    
567
}
568
 
569
 
570
// ---------------------------------------------------------------------------
571
 
572
static Cyg_ErrNo
573
serial_get_config(cyg_io_handle_t handle, cyg_uint32 key, void *xbuf,
574
                  cyg_uint32 *len)
575
{
576
    cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle;
577
    serial_channel *chan = (serial_channel *)t->priv;
578
    cyg_serial_info_t *buf = (cyg_serial_info_t *)xbuf;
579
    Cyg_ErrNo res = ENOERR;
580
    cbuf_t *out_cbuf = &chan->out_cbuf;
581
    cbuf_t *in_cbuf = &chan->in_cbuf;
582
    serial_funs *funs = chan->funs;
583
 
584
    switch (key) {
585
    case CYG_IO_GET_CONFIG_SERIAL_INFO:
586
        if (*len < sizeof(cyg_serial_info_t)) {
587
            return -EINVAL;
588
        }
589
        *buf = chan->config;
590
        *len = sizeof(chan->config);
591
        break;
592
 
593
    case CYG_IO_GET_CONFIG_SERIAL_BUFFER_INFO:
594
        // return rx/tx buffer sizes and counts
595
        {
596
            cyg_serial_buf_info_t *p;
597
            if (*len < sizeof(cyg_serial_buf_info_t))
598
                return -EINVAL;
599
 
600
            *len = sizeof(cyg_serial_buf_info_t);
601
            p = (cyg_serial_buf_info_t *)xbuf;
602
 
603
            p->rx_bufsize = in_cbuf->len;
604
            if (p->rx_bufsize)
605
                p->rx_count = in_cbuf->nb;
606
            else
607
                p->rx_count = 0;
608
 
609
            p->tx_bufsize = out_cbuf->len;
610
            if (p->tx_bufsize)
611
                p->tx_count = out_cbuf->nb;
612
            else
613
                p->tx_count = 0;
614
        }
615
      break;
616
 
617
    case CYG_IO_GET_CONFIG_SERIAL_OUTPUT_DRAIN:
618
// Wait for any pending output to complete
619
        if (out_cbuf->len == 0) break;  // Nothing to do if not buffered
620
        cyg_drv_mutex_lock(&out_cbuf->lock);  // Stop any further output processing
621
        cyg_drv_dsr_lock();
622
        while (out_cbuf->pending || (out_cbuf->nb > 0)) {
623
            out_cbuf->waiting = true;
624
            if(!cyg_drv_cond_wait(&out_cbuf->wait) )
625
                res = -EINTR;
626
        }
627
        cyg_drv_dsr_unlock();
628
        cyg_drv_mutex_unlock(&out_cbuf->lock);
629
        break;
630
 
631
    case CYG_IO_GET_CONFIG_SERIAL_INPUT_FLUSH:
632
        // Flush any buffered input
633
        if (in_cbuf->len == 0) break;  // Nothing to do if not buffered
634
        cyg_drv_mutex_lock(&in_cbuf->lock);  // Stop any further input processing
635
        cyg_drv_dsr_lock();
636
        if (in_cbuf->waiting) {
637
            in_cbuf->abort = true;
638
            cyg_drv_cond_broadcast(&in_cbuf->wait);
639
            in_cbuf->waiting = false;
640
        }
641
        in_cbuf->get = in_cbuf->put = in_cbuf->nb = 0;  // Flush buffered input
642
 
643
        // Pass to the hardware driver in case it wants to flush FIFOs etc.
644
        (funs->set_config)(chan,
645
                           CYG_IO_SET_CONFIG_SERIAL_INPUT_FLUSH,
646
                           NULL, NULL);
647
        cyg_drv_dsr_unlock();
648
        cyg_drv_mutex_unlock(&in_cbuf->lock);
649
#ifdef CYGPKG_IO_SERIAL_FLOW_CONTROL
650
        // Restart receiver if it was shutdown
651
        if ((chan->flow_desc.flags & CYG_SERIAL_FLOW_IN_THROTTLED) != 0) {
652
            restart_rx( chan, false );
653
        }
654
#endif
655
        break;
656
 
657
    case CYG_IO_GET_CONFIG_SERIAL_ABORT:
658
        // Abort any outstanding I/O, including blocked reads
659
        // Caution - assumed to be called from 'timeout' (i.e. DSR) code
660
        if (in_cbuf->len != 0) {
661
            in_cbuf->abort = true;
662
            cyg_drv_cond_broadcast(&in_cbuf->wait);
663
        }
664
        if (out_cbuf->len != 0) {
665
            out_cbuf->abort = true;
666
            cyg_drv_cond_broadcast(&out_cbuf->wait);
667
        }
668
        break;
669
 
670
    case CYG_IO_GET_CONFIG_SERIAL_OUTPUT_FLUSH:
671
// Throw away any pending output
672
        if (out_cbuf->len == 0) break;  // Nothing to do if not buffered
673
        cyg_drv_mutex_lock(&out_cbuf->lock);  // Stop any further output processing
674
        cyg_drv_dsr_lock();
675
        if (out_cbuf->nb > 0) {
676
            out_cbuf->get = out_cbuf->put = out_cbuf->nb = 0;  // Empties queue!
677
            (funs->stop_xmit)(chan);  // Done with transmit
678
        }
679
        // Pass to the hardware driver in case it wants to flush FIFOs etc.
680
        (funs->set_config)(chan,
681
                           CYG_IO_SET_CONFIG_SERIAL_OUTPUT_FLUSH,
682
                           NULL, NULL);
683
        if (out_cbuf->waiting) {
684
            out_cbuf->abort = true;
685
            cyg_drv_cond_broadcast(&out_cbuf->wait);
686
            out_cbuf->waiting = false;
687
        }
688
        cyg_drv_dsr_unlock();
689
        cyg_drv_mutex_unlock(&out_cbuf->lock);
690
        break;
691
 
692
#ifdef CYGOPT_IO_SERIAL_SUPPORT_NONBLOCKING
693
    case CYG_IO_GET_CONFIG_READ_BLOCKING:
694
        if (*len < sizeof(cyg_uint32)) {
695
            return -EINVAL;
696
        }
697
        *(cyg_uint32*)xbuf = (in_cbuf->blocking) ? 1 : 0;
698
        break;
699
 
700
    case CYG_IO_GET_CONFIG_WRITE_BLOCKING:
701
        if (*len < sizeof(cyg_uint32)) {
702
            return -EINVAL;
703
        }
704
        *(cyg_uint32*)xbuf = (out_cbuf->blocking) ? 1 : 0;
705
        break;
706
#endif // CYGOPT_IO_SERIAL_SUPPORT_NONBLOCKING
707
 
708
    default:
709
        res = -EINVAL;
710
    }
711
    return res;
712
}
713
 
714
 
715
// ---------------------------------------------------------------------------
716
 
717
static Cyg_ErrNo
718
serial_set_config(cyg_io_handle_t handle, cyg_uint32 key, const void *xbuf,
719
                  cyg_uint32 *len)
720
{
721
    Cyg_ErrNo res = ENOERR;
722
    cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle;
723
    serial_channel *chan = (serial_channel *)t->priv;
724
#ifdef CYGOPT_IO_SERIAL_SUPPORT_NONBLOCKING
725
    cbuf_t *out_cbuf = &chan->out_cbuf;
726
    cbuf_t *in_cbuf = &chan->in_cbuf;
727
#endif
728
    serial_funs *funs = chan->funs;
729
 
730
    switch (key) {
731
#ifdef CYGOPT_IO_SERIAL_SUPPORT_NONBLOCKING
732
    case CYG_IO_SET_CONFIG_READ_BLOCKING:
733
        if (*len < sizeof(cyg_uint32) || 0 == in_cbuf->len) {
734
            return -EINVAL;
735
        }
736
        in_cbuf->blocking = (1 == *(cyg_uint32*)xbuf) ? true : false;
737
        break;
738
    case CYG_IO_SET_CONFIG_WRITE_BLOCKING:
739
        if (*len < sizeof(cyg_uint32) || 0 == out_cbuf->len) {
740
            return -EINVAL;
741
        }
742
        out_cbuf->blocking = (1 == *(cyg_uint32*)xbuf) ? true : false;
743
        break;
744
#endif // CYGOPT_IO_SERIAL_SUPPORT_NONBLOCKING
745
 
746
#ifdef CYGPKG_IO_SERIAL_FLOW_CONTROL
747
    case CYG_IO_SET_CONFIG_SERIAL_FLOW_CONTROL_METHOD:
748
        {
749
            cyg_uint32 *f = (cyg_uint32 *)xbuf;
750
 
751
            if (*len < sizeof(*f))
752
                return -EINVAL;
753
 
754
            cyg_drv_dsr_lock();
755
 
756
            chan->config.flags &= ~(CYGNUM_SERIAL_FLOW_XONXOFF_RX|
757
                                    CYGNUM_SERIAL_FLOW_XONXOFF_TX|
758
                                    CYGNUM_SERIAL_FLOW_RTSCTS_RX|
759
                                    CYGNUM_SERIAL_FLOW_RTSCTS_TX|
760
                                    CYGNUM_SERIAL_FLOW_DSRDTR_RX|
761
                                    CYGNUM_SERIAL_FLOW_DSRDTR_TX);
762
            chan->config.flags |= (*f & (
763
#ifdef CYGOPT_IO_SERIAL_FLOW_CONTROL_SOFTWARE
764
                CYGNUM_SERIAL_FLOW_XONXOFF_RX|
765
                CYGNUM_SERIAL_FLOW_XONXOFF_TX|
766
#endif
767
#ifdef CYGOPT_IO_SERIAL_FLOW_CONTROL_HW
768
                CYGNUM_SERIAL_FLOW_RTSCTS_RX|
769
                CYGNUM_SERIAL_FLOW_RTSCTS_TX|
770
                CYGNUM_SERIAL_FLOW_DSRDTR_RX|
771
                CYGNUM_SERIAL_FLOW_DSRDTR_TX|
772
#endif
773
                0));
774
#ifdef CYGOPT_IO_SERIAL_FLOW_CONTROL_HW
775
            // up to hardware driver to clear flags if rejected
776
            res = (funs->set_config)(chan,
777
                                     CYG_IO_SET_CONFIG_SERIAL_HW_FLOW_CONFIG,
778
                                     NULL, NULL);
779
#endif
780
            cyg_drv_dsr_unlock();
781
        }
782
        break;
783
 
784
    case CYG_IO_SET_CONFIG_SERIAL_FLOW_CONTROL_FORCE:
785
        {
786
            cyg_uint32 *f = (cyg_uint32 *)xbuf;
787
 
788
            if (*len < sizeof(*f))
789
                return -EINVAL;
790
 
791
            cyg_drv_dsr_lock();
792
            switch (*f) {
793
            case CYGNUM_SERIAL_FLOW_THROTTLE_RX:
794
                throttle_rx( chan, true );
795
                break;
796
            case CYGNUM_SERIAL_FLOW_RESTART_RX:
797
                restart_rx( chan, true );
798
                break;
799
            case CYGNUM_SERIAL_FLOW_THROTTLE_TX:
800
                throttle_tx( chan );
801
                break;
802
            case CYGNUM_SERIAL_FLOW_RESTART_TX:
803
                restart_tx( chan );
804
                break;
805
            default:
806
                res = -EINVAL;
807
                break;
808
            }
809
            cyg_drv_dsr_unlock();
810
        }
811
        break;
812
#endif // CYGPKG_IO_SERIAL_FLOW_CONTROL
813
 
814
#ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUS
815
    case CYG_IO_SET_CONFIG_SERIAL_STATUS_CALLBACK:
816
        {
817
            cyg_serial_line_status_callback_fn_t newfn;
818
            CYG_ADDRWORD newpriv;
819
            cyg_serial_line_status_callback_t *tmp =
820
                (cyg_serial_line_status_callback_t *)xbuf;
821
 
822
            if ( *len < sizeof(*tmp) )
823
                return -EINVAL;
824
 
825
            newfn = tmp->fn;
826
            newpriv = tmp->priv;
827
 
828
            // prevent callbacks while we do this
829
            cyg_drv_dsr_lock();
830
            // store old callbacks in same structure
831
            tmp->fn = chan->status_callback;
832
            tmp->priv = chan->status_callback_priv;
833
            chan->status_callback = newfn;
834
            chan->status_callback_priv = newpriv;
835
            cyg_drv_dsr_unlock();
836
            *len = sizeof(*tmp);
837
        }
838
        break;
839
#endif
840
 
841
    default:
842
        // pass down to lower layers
843
        return (funs->set_config)(chan, key, xbuf, len);
844
    }
845
    return res;
846
}
847
 
848
// ---------------------------------------------------------------------------
849
 
850
static void
851
serial_xmt_char(serial_channel *chan)
852
{
853
    cbuf_t *cbuf = &chan->out_cbuf;
854
    serial_funs *funs = chan->funs;
855
    unsigned char c;
856
    int space;
857
 
858
#if CYGINT_IO_SERIAL_BLOCK_TRANSFER
859
    CYG_ASSERT(false == cbuf->block_mode_xfer_running,
860
               "Attempting char xmt while block transfer is running");
861
#endif
862
#ifdef CYGOPT_IO_SERIAL_FLOW_CONTROL_SOFTWARE
863
    // if we are required to send an XON/XOFF char, send it before
864
    // anything else
865
    // FIXME: what if XON gets corrupted in transit to the other end?
866
    // Should we resend XON even though the other end may not be wanting
867
    // to send us stuff at this point?
868
    if ( chan->config.flags & CYGNUM_SERIAL_FLOW_XONXOFF_RX ) {
869
        if ( chan->flow_desc.xchar ) {
870
            if ( (funs->putc)(chan, chan->flow_desc.xchar) ) {
871
                chan->flow_desc.xchar = '\0';
872
            } else {  // otherwise there's no space and we have to wait
873
                return;
874
            }
875
        }
876
    }
877
#endif
878
#ifdef CYGPKG_IO_SERIAL_FLOW_CONTROL
879
    // if we're meant to be throttled, just stop and leave
880
    if ( chan->flow_desc.flags & CYG_SERIAL_FLOW_OUT_THROTTLED ) {
881
        (funs->stop_xmit)(chan);  // Stop transmitting for now
882
        return;
883
    }
884
#endif
885
    while (cbuf->nb > 0) {
886
        c = cbuf->data[cbuf->get];
887
        if ((funs->putc)(chan, c)) {
888
            cbuf->get++;
889
            if (cbuf->get == cbuf->len) cbuf->get = 0;
890
            cbuf->nb--;
891
        } else {
892
            // See if there is now enough room to restart writer
893
            space = cbuf->len - cbuf->nb;
894
            if (space >= cbuf->low_water) {
895
                if (cbuf->waiting) {
896
                    cbuf->waiting = false;
897
                    cyg_drv_cond_broadcast(&cbuf->wait);
898
                }
899
#ifdef CYGPKG_IO_SERIAL_SELECT_SUPPORT
900
                cyg_selwakeup( &cbuf->selinfo );
901
#endif                    
902
            }
903
            return;  // Need to wait for more space
904
        }
905
    }
906
    (funs->stop_xmit)(chan);  // Done with transmit
907
 
908
    // must signal waiters, and wake up selecters for the case when
909
    // this was the last char to be sent and they hadn't been signalled
910
    // before (e.g. because of flow control)
911
    if (cbuf->waiting) {
912
        cbuf->waiting = false;
913
        cyg_drv_cond_broadcast(&cbuf->wait);
914
    }
915
#ifdef CYGPKG_IO_SERIAL_SELECT_SUPPORT
916
    cyg_selwakeup( &cbuf->selinfo );
917
#endif                    
918
}
919
 
920
// ---------------------------------------------------------------------------
921
 
922
static void
923
serial_rcv_char(serial_channel *chan, unsigned char c)
924
{
925
    cbuf_t *cbuf = &chan->in_cbuf;
926
 
927
#if CYGINT_IO_SERIAL_BLOCK_TRANSFER
928
    CYG_ASSERT(false == cbuf->block_mode_xfer_running,
929
               "Attempting char rcv while block transfer is running");
930
#endif
931
#ifdef CYGOPT_IO_SERIAL_FLOW_CONTROL_SOFTWARE
932
    // for software flow control, if the driver returns one of the characters
933
    // we act on it and then drop it (the app must not see it)
934
    if ( chan->config.flags & CYGNUM_SERIAL_FLOW_XONXOFF_TX ) {
935
        if ( c == CYGDAT_IO_SERIAL_FLOW_CONTROL_XOFF_CHAR ) {
936
            throttle_tx( chan );
937
            return; // it wasn't a "real" character
938
        } else if ( c == CYGDAT_IO_SERIAL_FLOW_CONTROL_XON_CHAR ) {
939
            restart_tx( chan );
940
            return; // it wasn't a "real" character
941
        }
942
    }
943
#endif    
944
#ifdef CYGPKG_IO_SERIAL_FLOW_CONTROL
945
    // If we've hit the high water mark, tell the other side to stop
946
    if ( cbuf->nb >= cbuf->high_water ) {
947
        throttle_rx( chan, false );
948
    }
949
#endif
950
#ifdef CYGPKG_IO_SERIAL_SELECT_SUPPORT
951
    // Wake up any pending selectors if we are about to
952
    // put some data into a previously empty buffer.
953
    if( cbuf->nb == 0 )
954
        cyg_selwakeup( &cbuf->selinfo );
955
#endif
956
 
957
    // If the flow control is not enabled/sufficient and the buffer is
958
    // already full, just throw new characters away.
959
 
960
    if ( cbuf->nb < cbuf->len ) {
961
        cbuf->data[cbuf->put++] = c;
962
        if (cbuf->put == cbuf->len) cbuf->put = 0;
963
        cbuf->nb++;
964
    } // note trailing else
965
#ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUS
966
    else {
967
        // Overrun. Report the error.
968
        cyg_serial_line_status_t stat;
969
        stat.which = CYGNUM_SERIAL_STATUS_OVERRUNERR;
970
        serial_indicate_status(chan, &stat);
971
    }
972
#endif
973
 
974
    if (cbuf->waiting) {
975
#ifdef XX_CYGDBG_DIAG_BUF
976
            extern int enable_diag_uart;
977
            int _enable = enable_diag_uart;
978
            int _time, _stime;
979
            externC cyg_tick_count_t cyg_current_time(void);
980
            enable_diag_uart = 0;
981
            HAL_CLOCK_READ(&_time);
982
            _stime = (int)cyg_current_time();
983
            diag_printf("Signal reader - time: %x.%x\n", _stime, _time);
984
            enable_diag_uart = _enable;
985
#endif // CYGDBG_DIAG_BUF
986
        cbuf->waiting = false;
987
        cyg_drv_cond_broadcast(&cbuf->wait);
988
    }
989
}
990
 
991
//----------------------------------------------------------------------------
992
// Flow control indication callback
993
 
994
#ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUS
995
static void
996
serial_indicate_status(serial_channel *chan, cyg_serial_line_status_t *s )
997
{
998
#ifdef CYGPKG_IO_SERIAL_FLOW_CONTROL
999
    if ( CYGNUM_SERIAL_STATUS_FLOW == s->which ) {
1000
        if ( s->value )
1001
            restart_tx( chan );
1002
        else
1003
            throttle_tx( chan );
1004
    }
1005
#endif
1006
    if ( chan->status_callback )
1007
        (*chan->status_callback)(s, chan->status_callback_priv);
1008
}
1009
#endif // ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUS
1010
 
1011
//----------------------------------------------------------------------------
1012
// Block transfer functions. Not all drivers require these. Those that
1013
// do must follow the required semantics:
1014
//
1015
// Attempt to transfer as much via the block transfer function as
1016
// possible, _but_ if that fails, do the remaining bytes via the
1017
// single-char function. That ensures that all policy decisions can be
1018
// made in this driver, and not in the device driver.
1019
//
1020
// Note: if the driver uses DMA for transmission, an initial failing
1021
// call to the xmt_req function must cause the start_xmit function to
1022
// fall-back to regular CPU-interrupt based single-character
1023
// transmission.
1024
 
1025
#if CYGINT_IO_SERIAL_BLOCK_TRANSFER
1026
 
1027
static rcv_req_reply_t
1028
serial_data_rcv_req(serial_channel *chan, int avail,
1029
                    int* space_avail, unsigned char** space)
1030
{
1031
    cbuf_t *cbuf = &chan->in_cbuf;
1032
    int gap;
1033
 
1034
#ifdef CYGOPT_IO_SERIAL_FLOW_CONTROL_SOFTWARE
1035
    // When there is software flow-control, force the serial device
1036
    // driver to use the single-char xmt/rcv functions, since these
1037
    // have to make policy decision based on the data. Rcv function
1038
    // may also have to transmit data to throttle the xmitter.
1039
    if (chan->config.flags & (CYGNUM_SERIAL_FLOW_XONXOFF_TX|CYGNUM_SERIAL_FLOW_XONXOFF_RX))
1040
        return CYG_RCV_DISABLED;
1041
#endif
1042
 
1043
    CYG_ASSERT(false == cbuf->block_mode_xfer_running,
1044
               "Attempting new block transfer while another is running");
1045
    // Check for space
1046
    gap = cbuf->nb;
1047
    if (gap == cbuf->len)
1048
        return CYG_RCV_FULL;
1049
 
1050
#ifdef CYGDBG_USE_ASSERTS
1051
    cbuf->block_mode_xfer_running = true;
1052
#endif
1053
 
1054
    if (0 == gap) {
1055
        // Buffer is empty. Reset put/get indexes to get max transfer in
1056
        // one chunk.
1057
        cbuf->get = 0;
1058
        cbuf->put = 0;
1059
        gap = cbuf->len;
1060
    } else {
1061
        // Free space (G = get, P = put, x = data, . = empty)
1062
        //  positive: xxxxP.....Gxxx
1063
        //  negative: ..GxxxxxP.....        [offer last chunk only]
1064
 
1065
        // First try for a gap between put and get locations
1066
        gap = cbuf->get - cbuf->put;
1067
        if (gap < 0) {
1068
            // If failed, the gap is between put and the end of buffer
1069
            gap = cbuf->len - cbuf->put;
1070
        }
1071
    }
1072
 
1073
    if (avail < gap) gap = avail;   // bound by what's available from hw
1074
 
1075
    *space_avail = gap;
1076
    *space = &cbuf->data[cbuf->put];
1077
 
1078
    CYG_ASSERT((gap+cbuf->nb) <= cbuf->len, "Buffer will overflow");
1079
    CYG_ASSERT(cbuf->put < cbuf->len, "Invalid put ptr");
1080
    CYG_ASSERT(cbuf->get < cbuf->len, "Invalid get ptr");
1081
 
1082
    return CYG_RCV_OK;
1083
}
1084
 
1085
static void
1086
serial_data_rcv_done(serial_channel *chan, int chars_rcvd)
1087
{
1088
    cbuf_t *cbuf = &chan->in_cbuf;
1089
 
1090
    cbuf->put += chars_rcvd;
1091
    cbuf->nb += chars_rcvd;
1092
 
1093
    if (cbuf->put == cbuf->len) cbuf->put = 0;
1094
 
1095
    CYG_ASSERT(cbuf->nb <= cbuf->len, "Buffer overflow");
1096
    CYG_ASSERT(cbuf->put < cbuf->len, "Invalid put ptr");
1097
    CYG_ASSERT(cbuf->get < cbuf->len, "Invalid get ptr");
1098
 
1099
    if (cbuf->waiting) {
1100
        cbuf->waiting = false;
1101
        cyg_drv_cond_broadcast(&cbuf->wait);
1102
    }
1103
#ifdef CYGPKG_IO_SERIAL_FLOW_CONTROL
1104
    // If we've hit the high water mark, tell the other side to stop
1105
    if ( cbuf->nb >= cbuf->high_water ) {
1106
        throttle_rx( chan, false );
1107
    }
1108
#endif
1109
#ifdef CYGPKG_IO_SERIAL_SELECT_SUPPORT
1110
    // Wake up any pending selectors if we have
1111
    // put some data into a previously empty buffer.
1112
    if (chars_rcvd == cbuf->nb)
1113
        cyg_selwakeup( &cbuf->selinfo );
1114
#endif
1115
 
1116
#ifdef CYGDBG_USE_ASSERTS
1117
    cbuf->block_mode_xfer_running = false;
1118
#endif
1119
}
1120
 
1121
static xmt_req_reply_t
1122
serial_data_xmt_req(serial_channel *chan, int space,
1123
                    int* chars_avail, unsigned char** chars)
1124
{
1125
    cbuf_t *cbuf = &chan->out_cbuf;
1126
    int avail;
1127
 
1128
#ifdef CYGOPT_IO_SERIAL_FLOW_CONTROL_SOFTWARE
1129
    // When there is software flow-control, force the serial device
1130
    // driver to use the single-char xmt/rcv functions, since these
1131
    // have to make policy decision based on the data. Rcv function
1132
    // may also have to transmit data to throttle the xmitter.
1133
    if (chan->config.flags & (CYGNUM_SERIAL_FLOW_XONXOFF_TX|CYGNUM_SERIAL_FLOW_XONXOFF_RX))
1134
        return CYG_XMT_DISABLED;
1135
#endif
1136
 
1137
    CYG_ASSERT(false == cbuf->block_mode_xfer_running,
1138
               "Attempting new block transfer while another is running");
1139
 
1140
#ifdef CYGPKG_IO_SERIAL_FLOW_CONTROL
1141
    // if we're meant to be throttled, just stop and leave
1142
    if ( chan->flow_desc.flags & CYG_SERIAL_FLOW_OUT_THROTTLED ) {
1143
        (chan->funs->stop_xmit)(chan);  // Stop transmitting for now
1144
        return CYG_XMT_EMPTY;
1145
    }
1146
#endif
1147
 
1148
    // Available data (G = get, P = put, x = data, . = empty)
1149
    //  0:        no data
1150
    //  negative: xxxxP.....Gxxx        [offer last chunk only]
1151
    //  positive: ..GxxxxxP.....
1152
    if (0 == cbuf->nb)
1153
        return CYG_XMT_EMPTY;
1154
 
1155
#ifdef CYGDBG_USE_ASSERTS
1156
    cbuf->block_mode_xfer_running = true;
1157
#endif
1158
 
1159
    if (cbuf->get >= cbuf->put) {
1160
        avail = cbuf->len - cbuf->get;
1161
    } else {
1162
        avail = cbuf->put - cbuf->get;
1163
    }
1164
 
1165
    if (avail > space) avail = space;   // bound by space in hardware
1166
 
1167
    *chars_avail = avail;
1168
    *chars = &cbuf->data[cbuf->get];
1169
 
1170
    CYG_ASSERT(avail <= cbuf->len, "Avail overflow");
1171
    CYG_ASSERT(cbuf->nb <= cbuf->len, "Buffer overflow");
1172
    CYG_ASSERT(cbuf->put < cbuf->len, "Invalid put ptr");
1173
    CYG_ASSERT(cbuf->get < cbuf->len, "Invalid get ptr");
1174
 
1175
    return CYG_XMT_OK;
1176
}
1177
 
1178
static void
1179
serial_data_xmt_done(serial_channel *chan, int chars_sent)
1180
{
1181
    cbuf_t *cbuf = &chan->out_cbuf;
1182
    serial_funs *funs = chan->funs;
1183
    int space;
1184
 
1185
    cbuf->get += chars_sent;
1186
    cbuf->nb -= chars_sent;
1187
 
1188
    if (cbuf->get == cbuf->len) cbuf->get = 0;
1189
 
1190
    CYG_ASSERT(cbuf->nb <= cbuf->len, "Buffer overflow");
1191
    CYG_ASSERT(cbuf->nb >= 0, "Buffer underflow");
1192
    CYG_ASSERT(cbuf->put < cbuf->len, "Invalid put ptr");
1193
    CYG_ASSERT(cbuf->get < cbuf->len, "Invalid get ptr");
1194
 
1195
    if (0 == cbuf->nb) {
1196
        (funs->stop_xmit)(chan);  // Done with transmit
1197
        cbuf->get = cbuf->put = 0; // reset ptrs if empty
1198
    }
1199
 
1200
    // See if there is now enough room to restart writer
1201
    space = cbuf->len - cbuf->nb;
1202
    if (space >= cbuf->low_water) {
1203
        if (cbuf->waiting) {
1204
            cbuf->waiting = false;
1205
            cyg_drv_cond_broadcast(&cbuf->wait);
1206
        }
1207
#ifdef CYGPKG_IO_SERIAL_SELECT_SUPPORT
1208
        cyg_selwakeup( &cbuf->selinfo );
1209
#endif                    
1210
    }
1211
 
1212
#ifdef CYGDBG_USE_ASSERTS
1213
    cbuf->block_mode_xfer_running = false;
1214
#endif
1215
}
1216
 
1217
#endif // CYGINT_IO_SERIAL_BLOCK_TRANSFER
1218
 
1219
// ---------------------------------------------------------------------------
1220
 
1221
// EOF serial.c

powered by: WebSVN 2.1.0

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