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