Nut/OS  4.10.3
API Reference
usart.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2001-2003 by egnite Software GmbH. All rights reserved.
00003  *
00004  * Redistribution and use in source and binary forms, with or without
00005  * modification, are permitted provided that the following conditions
00006  * are met:
00007  *
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the copyright holders nor the names of
00014  *    contributors may be used to endorse or promote products derived
00015  *    from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY EGNITE SOFTWARE GMBH AND CONTRIBUTORS
00018  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00019  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00020  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EGNITE
00021  * SOFTWARE GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00022  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00023  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00024  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00025  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00026  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00027  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00028  * SUCH DAMAGE.
00029  *
00030  * For additional information see http://www.ethernut.de/
00031  */
00032 
00033 /*
00034  * $Log$
00035  * Revision 1.10  2009/02/13 14:52:05  haraldkipp
00036  * Include memdebug.h for heap management debugging support.
00037  *
00038  * Revision 1.9  2008/08/11 06:59:42  haraldkipp
00039  * BSD types replaced by stdint types (feature request #1282721).
00040  *
00041  * Revision 1.8  2007/03/17 14:33:21  haraldkipp
00042  * Workaround for AVRGCC 4.1.1 bug, which failed to compile UsartIOCtl().
00043  *
00044  * Revision 1.7  2006/10/05 17:20:54  haraldkipp
00045  * Added a comment to warn the user about ioctl() functions, that may not be
00046  * supported.
00047  *
00048  * Revision 1.6  2006/08/23 09:20:47  freckle
00049  * fix bug #1541139
00050  *
00051  * Revision 1.5  2004/10/14 16:43:06  drsung
00052  * Fixed compiler warning "comparison between signed and unsigned"
00053  *
00054  * Revision 1.4  2004/05/24 20:17:15  drsung
00055  * Added function UsartSize to return number of chars in input buffer.
00056  *
00057  * Revision 1.3  2004/05/20 09:05:07  drsung
00058  * Memory was allocated twice for NUTFILE in UsartOpen.
00059  *
00060  * Revision 1.2  2004/03/18 13:59:14  haraldkipp
00061  * Comment updated
00062  *
00063  * Revision 1.1  2003/12/15 19:25:33  haraldkipp
00064  * New USART driver added
00065  *
00066  */
00067 
00068 #include <compiler.h>
00069 #include <stdlib.h>
00070 #include <string.h>
00071 #include <memdebug.h>
00072 
00073 #include <sys/atom.h>
00074 #include <sys/heap.h>
00075 #include <sys/event.h>
00076 #include <sys/timer.h>
00077 
00078 #include <dev/irqreg.h>
00079 #include <dev/usart.h>
00080 
00081 #include <fcntl.h>
00082 
00083 /*
00084  * Not nice because stdio already defined them. But in order to save memory,
00085  * we do the whole buffering and including stdio here would be more weird.
00086  */
00087 #ifndef _IOFBF
00088 #define _IOFBF  0x00
00089 #define _IOLBF  0x01
00090 #define _IONBF  0x02
00091 #endif
00092 
00097 
00111 int UsartInit(NUTDEVICE * dev)
00112 {
00113     int rc;
00114     USARTDCB *dcb = dev->dev_dcb;
00115 
00116     /* Initialize the low level hardware driver. */
00117     if ((rc = (*dcb->dcb_init) ()) == 0) {
00118         /* Ignore errors on initial configuration. */
00119         (*dcb->dcb_set_speed) (USART_INITSPEED);
00120     }
00121     return rc;
00122 }
00123 
00134 static int UsartResetBuffer(RINGBUF * rbf, size_t size, size_t lowm, size_t hiwm)
00135 {
00136     uint8_t *xbp = rbf->rbf_start;
00137     size_t xsz = rbf->rbf_siz;
00138 
00139     /* Disable further buffer usage. */
00140     NutEnterCritical();
00141     rbf->rbf_siz = 0;
00142     NutExitCritical();
00143 
00144     /* Resize the buffer, if required. */
00145     if (xsz != size) {
00146         if (xsz && xbp) {
00147             free(xbp);
00148         }
00149         if (size && (xbp = malloc(size)) == 0) {
00150             return -1;
00151         }
00152     }
00153 
00154     /* Update ring buffer status. */
00155     if (size) {
00156         rbf->rbf_start = xbp;
00157         rbf->rbf_head = xbp;
00158         rbf->rbf_tail = xbp;
00159         rbf->rbf_last = xbp + size;
00160         rbf->rbf_lwm = lowm;
00161         rbf->rbf_hwm = hiwm;
00162         rbf->rbf_cnt = 0;
00163 
00164         /* Re-enable buffer usage. */
00165         NutEnterCritical();
00166         rbf->rbf_siz = size;
00167         NutExitCritical();
00168     }
00169     return 0;
00170 }
00171 
00198 int UsartRead(NUTFILE * fp, void *buffer, int size)
00199 {
00200     size_t rc;
00201     size_t avail;
00202     size_t taken = 0;
00203     uint8_t ch;
00204     uint8_t *cp = buffer;
00205     NUTDEVICE *dev = fp->nf_dev;
00206     USARTDCB *dcb = dev->dev_dcb;
00207     RINGBUF *rbf = &dcb->dcb_rx_rbf;
00208 
00209     /*
00210      * No buffer allocated, this device is read only.
00211      */
00212     if (rbf->rbf_siz == 0) {
00213         return -1;
00214     }
00215 
00216     /*
00217      * Call without data pointer discards receive buffer.
00218      */
00219     if (buffer == 0) {
00220         UsartResetBuffer(rbf, rbf->rbf_siz, rbf->rbf_lwm, rbf->rbf_hwm);
00221         (*dcb->dcb_rx_start) ();
00222         return 0;
00223     }
00224 
00225     /*
00226      * Wait until at least one character is buffered or until a read
00227      * timeout occured.
00228      */
00229     for (;;) {
00230         /* Atomic access to the ring buffer counter. */
00231         NutEnterCritical();
00232         avail = rbf->rbf_cnt;
00233         NutExitCritical();
00234         if (avail) {
00235             break;
00236         }
00237         /*
00238          * This will enable RTS hardware handshake or re-enable the
00239          * remote transmitter by sending a XON character.
00240          */
00241         (*dcb->dcb_rx_start) ();
00242         if (NutEventWait(&rbf->rbf_que, dcb->dcb_rtimeout)) {
00243             return 0;
00244         }
00245         /* Device closed by another thread. */
00246         if (rbf->rbf_siz == 0) {
00247             return -1;
00248         }
00249     }
00250 
00251     /*
00252      * Get cooked characters from receive buffer.
00253      */
00254     if (dcb->dcb_modeflags & USART_MF_COOKEDMODE) {
00255         for (rc = 0; rc < (size_t) size;) {
00256             if (taken >= avail) {
00257                 break;
00258             }
00259             ch = *rbf->rbf_tail++;
00260             if (rbf->rbf_tail == rbf->rbf_last) {
00261                 rbf->rbf_tail = rbf->rbf_start;
00262             }
00263             taken++;
00264             if (ch == '\r' || ch == '\n') {
00265                 if (dcb->dcb_last_eol == 0 || dcb->dcb_last_eol == ch) {
00266                     dcb->dcb_last_eol = ch;
00267                     *cp++ = '\n';
00268                     rc++;
00269                 }
00270             } else {
00271                 dcb->dcb_last_eol = 0;
00272                 *cp++ = ch;
00273                 rc++;
00274             }
00275         }
00276     }
00277 
00278     /*
00279      * Get raw characters from receive buffer.
00280      */
00281     else {
00282         if ((rc = size) > avail)
00283             rc = avail;
00284         for (taken = 0; taken < rc; taken++) {
00285             *cp++ = *rbf->rbf_tail++;
00286             if (rbf->rbf_tail == rbf->rbf_last) {
00287                 rbf->rbf_tail = rbf->rbf_start;
00288             }
00289         }
00290     }
00291 
00292     if (taken) {
00293         NutEnterCritical();
00294         rbf->rbf_cnt -= taken;
00295         NutExitCritical();
00296         if (rbf->rbf_cnt < rbf->rbf_lwm) {
00297             (*dcb->dcb_rx_start) ();
00298         }
00299     }
00300     return (int) rc;
00301 }
00302 
00321 static size_t UsartFlushOutput(USARTDCB *dcb, size_t added, size_t left)
00322 {
00323     size_t rc;
00324     RINGBUF *rbf = &dcb->dcb_tx_rbf;
00325 
00326     /*
00327      * Add the new characters to the buffer count.
00328      */
00329     NutEnterCritical();
00330     rbf->rbf_cnt += added;
00331     rc = rbf->rbf_cnt;
00332     NutExitCritical();
00333 
00334     while (rc > left) {
00335         /* Start transmitter and wait for the next event. */
00336         (*dcb->dcb_tx_start) ();
00337         if (NutEventWait(&rbf->rbf_que, dcb->dcb_wtimeout)) {
00338             break;
00339         }
00340         /* Refresh the count. */
00341         NutEnterCritical();
00342         rc = rbf->rbf_cnt;
00343         NutExitCritical();
00344     };
00345     return rc;
00346 }
00347 
00360 static int UsartPut(NUTDEVICE * dev, CONST void *buffer, int len, int pflg)
00361 {
00362     int rc;
00363     CONST uint8_t *cp;
00364     uint8_t lbmode;
00365     ureg_t cooked;
00366     uint8_t ch;
00367     size_t cnt;
00368     size_t added;
00369     USARTDCB *dcb = dev->dev_dcb;
00370     RINGBUF *rbf = &dcb->dcb_tx_rbf;
00371 
00372     /*
00373      * No output ring buffer allocated, this device is read only.
00374      */
00375     if (rbf->rbf_siz == 0) {
00376         return -1;
00377     }
00378 
00379     /*
00380      * Call without data pointer flushes the buffer. In this case a return
00381      * value not equal zero indicates write timeout.
00382      */
00383     if (buffer == 0) {
00384         return UsartFlushOutput(dcb, 0, 0);
00385     }
00386 
00387     if (dcb->dcb_modeflags & USART_MF_LINEBUFFER)
00388         lbmode = 1;
00389     else
00390         lbmode = 0;
00391 
00392     if (dcb->dcb_modeflags & USART_MF_COOKEDMODE)
00393         cooked = 1;
00394     else
00395         cooked = 0;
00396 
00397     /*
00398      * Get the number of buffered bytes. The transmit interrupt will modify
00399      * this value, so make the query atomic.
00400      */
00401     NutEnterCritical();
00402     cnt = rbf->rbf_cnt;
00403     NutExitCritical();
00404 
00405     /*
00406      * Move bytes to the transmit buffer.
00407      */
00408     cp = buffer;
00409     added = 0;
00410     for (rc = 0; rc < len;) {
00411         /*
00412          * If we reached the high watermark, then kick the hardware driver
00413          * to start transmission and wait until the low watermark is reached.
00414          */
00415         if (cnt + added >= rbf->rbf_hwm) {
00416             cnt = UsartFlushOutput(dcb, added, rbf->rbf_lwm);
00417             added = 0;
00418             /* If still above the mark, then a timeout occured. */
00419             if(cnt > rbf->rbf_lwm) {
00420                 break;
00421             }
00422         }
00423 
00424         /*
00425          * Get the next data byte. If the pflg parameter is set, then data
00426          * is located in program space.
00427          */
00428         ch = pflg ? PRG_RDB(cp) : *cp;
00429 
00430         /*
00431          * In cooked mode we prepend a carriage return to any linefeed
00432          * character.
00433          */
00434         if (cooked == 1 && ch == '\n') {
00435             cooked = 2;
00436             ch = '\r';
00437             if (lbmode == 1)
00438                 lbmode = 2;
00439         } else {
00440             if (cooked == 2)
00441                 cooked = 1;
00442             cp++;
00443             rc++;
00444         }
00445         *rbf->rbf_head++ = ch;
00446         if (rbf->rbf_head == rbf->rbf_last) {
00447             rbf->rbf_head = rbf->rbf_start;
00448         }
00449         added++;
00450     }
00451 
00452     if (added) {
00453         NutEnterCritical();
00454         rbf->rbf_cnt += added;
00455         NutExitCritical();
00456         (*dcb->dcb_tx_start) ();
00457     }
00458 
00459     return rc;
00460 }
00461 
00481 int UsartWrite(NUTFILE * fp, CONST void *buffer, int len)
00482 {
00483     return UsartPut(fp->nf_dev, buffer, len, 0);
00484 }
00485 
00507 int UsartWrite_P(NUTFILE * fp, PGM_P buffer, int len)
00508 {
00509     return UsartPut(fp->nf_dev, (CONST char *) buffer, len, 1);
00510 }
00511 
00525 int UsartClose(NUTFILE * fp)
00526 {
00527     NUTDEVICE *dev = fp->nf_dev;
00528     USARTDCB *dcb = dev->dev_dcb;
00529 
00530     if (fp == 0 || fp == NUTFILE_EOF)
00531         return -1;
00532 
00533     (*dcb->dcb_set_status) (UART_RTSDISABLED);
00534     free(fp);
00535     UsartResetBuffer(&dcb->dcb_tx_rbf, 0, 0, 0);
00536     UsartResetBuffer(&dcb->dcb_rx_rbf, 0, 0, 0);
00537     /* Wake-up all threads waiting for incoming data. */
00538     NutEventBroadcast(&dcb->dcb_rx_rbf.rbf_que);
00539 
00540     return 0;
00541 }
00542 
00561 NUTFILE *UsartOpen(NUTDEVICE * dev, CONST char *name, int mode, int acc)
00562 {
00563     USARTDCB *dcb = dev->dev_dcb;
00564     NUTFILE *fp;
00565 
00566     /*
00567      * Create the tranmit buffer unless this is used for read only.
00568      */
00569     if ((mode & 0x0003) != _O_RDONLY) {
00570         if (UsartResetBuffer(&dcb->dcb_tx_rbf, USART_TXBUFSIZ, USART_TXLOWMARK, USART_TXHIWMARK)) {
00571             return NUTFILE_EOF;
00572         }
00573     }
00574 
00575     /*
00576      * Create the receive buffer unless this is used for write only.
00577      */
00578     if ((mode & 0x0003) != _O_WRONLY) {
00579         if (UsartResetBuffer(&dcb->dcb_rx_rbf, USART_RXBUFSIZ, USART_RXLOWMARK, USART_RXHIWMARK)) {
00580             free(dcb->dcb_tx_rbf.rbf_start);
00581             return NUTFILE_EOF;
00582         }
00583     }
00584 
00585     /*
00586      * Allocate memory for the file structure.
00587      */
00588     if ((fp = malloc(sizeof(NUTFILE))) == 0) {
00589         free(dcb->dcb_tx_rbf.rbf_start);
00590         free(dcb->dcb_rx_rbf.rbf_start);
00591         return NUTFILE_EOF;
00592     }
00593 
00594     /* Set proper device modes. */
00595     if ((mode & 0xC000) == _O_BINARY) {
00596         dcb->dcb_modeflags &= ~USART_MF_COOKEDMODE;
00597     } else {
00598         dcb->dcb_modeflags |= USART_MF_COOKEDMODE;
00599     }
00600 
00601     /*
00602      * For now we do the initialization here. Later we may implement
00603      * a file creation routine to get a linked list of all opened
00604      * files in the system.
00605      */
00606     fp->nf_next = 0;
00607     fp->nf_dev = dev;
00608     fp->nf_fcb = 0;
00609 
00610     if ((mode & 0x0003) != _O_WRONLY) {
00611         (*dcb->dcb_rx_start) ();
00612     }
00613 
00614     return fp;
00615 }
00616 
00678 int UsartIOCtl(NUTDEVICE * dev, int req, void *conf)
00679 {
00680     int rc = 0;
00681     USARTDCB *dcb;
00682     RINGBUF *rbf;
00683     uint32_t *lvp = (uint32_t *) conf;
00684     uint32_t lv = *lvp;
00685     uint8_t bv = (uint8_t) lv;
00686 
00687     dcb = dev->dev_dcb;
00688 
00689     switch (req) {
00690     case UART_SETSPEED:
00691         rc = (*dcb->dcb_set_speed) (lv);
00692         break;
00693     case UART_GETSPEED:
00694         *lvp = (*dcb->dcb_get_speed) ();
00695         break;
00696 
00697     case UART_SETDATABITS:
00698         rc = (*dcb->dcb_set_data_bits) (bv);
00699         break;
00700     case UART_GETDATABITS:
00701         *lvp = (*dcb->dcb_get_data_bits) ();
00702         break;
00703 
00704     case UART_SETPARITY:
00705         rc = (*dcb->dcb_set_parity) (bv);
00706         break;
00707     case UART_GETPARITY:
00708         *lvp = (*dcb->dcb_get_parity) ();
00709         break;
00710 
00711     case UART_SETSTOPBITS:
00712         rc = (*dcb->dcb_set_stop_bits) (bv);
00713         break;
00714     case UART_GETSTOPBITS:
00715         *lvp = (*dcb->dcb_get_stop_bits) ();
00716         break;
00717 
00718     case UART_SETSTATUS:
00719         /*
00720          * We are not changing the buffer size. Thus, we can safely ignore the
00721          * result of UsartResetBuffer(). This way we found a work around for
00722          * the AVRGCC 4.1.1 bug, which appeared here previously.
00723          */
00724         if (lv & UART_RXBUFFEREMPTY) {
00725             rbf = &dcb->dcb_rx_rbf;
00726             UsartResetBuffer(rbf, rbf->rbf_siz, rbf->rbf_lwm, rbf->rbf_hwm);
00727             (*dcb->dcb_rx_start) ();
00728         }
00729         if (lv & UART_TXBUFFEREMPTY) {
00730             rbf = &dcb->dcb_tx_rbf;
00731             UsartResetBuffer(rbf, rbf->rbf_siz, rbf->rbf_lwm, rbf->rbf_hwm);
00732         }
00733         rc = (*dcb->dcb_set_status) (lv & ~(UART_RXBUFFEREMPTY | UART_TXBUFFEREMPTY));
00734         break;
00735     case UART_GETSTATUS:
00736         *lvp = (*dcb->dcb_get_status) ();
00737         /*
00738          * Determine buffer status.
00739          */
00740         if (dcb->dcb_rx_rbf.rbf_cnt == 0) {
00741             *lvp |= UART_RXBUFFEREMPTY;
00742         }
00743         if (dcb->dcb_tx_rbf.rbf_cnt == 0) {
00744             *lvp |= UART_TXBUFFEREMPTY;
00745         }
00746         break;
00747 
00748     case UART_SETREADTIMEOUT:
00749         dcb->dcb_rtimeout = lv;
00750         break;
00751     case UART_GETREADTIMEOUT:
00752         *lvp = dcb->dcb_rtimeout;
00753         break;
00754 
00755     case UART_SETWRITETIMEOUT:
00756         dcb->dcb_wtimeout = lv;
00757         break;
00758     case UART_GETWRITETIMEOUT:
00759         *lvp = dcb->dcb_wtimeout;
00760         break;
00761 
00762     case UART_SETLOCALECHO:
00763         if (bv)
00764             dcb->dcb_modeflags |= USART_MF_LOCALECHO;
00765         else
00766             dcb->dcb_modeflags &= ~USART_MF_LOCALECHO;
00767         break;
00768     case UART_GETLOCALECHO:
00769         if (dcb->dcb_modeflags & USART_MF_LOCALECHO)
00770             *lvp = 1;
00771         else
00772             *lvp = 0;
00773         break;
00774 
00775     case UART_SETFLOWCONTROL:
00776         rc = (*dcb->dcb_set_flow_control) (lv);
00777         break;
00778     case UART_GETFLOWCONTROL:
00779         *lvp = (*dcb->dcb_get_flow_control) ();
00780         break;
00781 
00782     case UART_SETCOOKEDMODE:
00783         if (bv)
00784             dcb->dcb_modeflags |= USART_MF_COOKEDMODE;
00785         else
00786             dcb->dcb_modeflags &= ~USART_MF_COOKEDMODE;
00787         break;
00788     case UART_GETCOOKEDMODE:
00789         if (dcb->dcb_modeflags & USART_MF_COOKEDMODE)
00790             *lvp = 1;
00791         else
00792             *lvp = 0;
00793         break;
00794 
00795         case UART_SETHDPXMODE:
00796                 if (bv)
00797                         dcb->dcb_modeflags |= USART_MF_HALFDUPLEX;
00798                 else
00799                         dcb->dcb_modeflags &= ~USART_MF_HALFDUPLEX;
00800                 break;
00801         case UART_GETHDPXMODE:
00802                 if (dcb->dcb_modeflags & USART_MF_HALFDUPLEX)
00803                         *lvp = 1;
00804                 else
00805                         *lvp = 0;
00806                 break;
00807 
00808     case UART_SETCLOCKMODE:
00809         rc = (*dcb->dcb_set_clock_mode) (lv);
00810         break;
00811     case UART_GETCLOCKMODE:
00812         *lvp = (*dcb->dcb_get_clock_mode) ();
00813         break;
00814 
00815     case UART_SETTXBUFSIZ:
00816         rbf = &dcb->dcb_tx_rbf;
00817         rc = UsartResetBuffer(rbf, (size_t) lv, rbf->rbf_lwm, rbf->rbf_hwm);
00818         if (rc == 0) {
00819             (*dcb->dcb_rx_start) ();
00820         }
00821         break;
00822     case UART_GETTXBUFSIZ:
00823         *lvp = dcb->dcb_tx_rbf.rbf_siz;
00824         break;
00825 
00826     case UART_SETRXBUFSIZ:
00827         rbf = &dcb->dcb_rx_rbf;
00828         rc = UsartResetBuffer(rbf, (size_t) lv, rbf->rbf_lwm, rbf->rbf_hwm);
00829         break;
00830     case UART_GETRXBUFSIZ:
00831         *lvp = dcb->dcb_rx_rbf.rbf_siz;
00832         break;
00833 
00834     case UART_SETTXBUFLWMARK:
00835         NutEnterCritical();
00836         dcb->dcb_tx_rbf.rbf_lwm = (size_t) lv;
00837         NutExitCritical();
00838         break;
00839     case UART_GETTXBUFLWMARK:
00840         *lvp = dcb->dcb_tx_rbf.rbf_lwm;
00841         break;
00842 
00843     case UART_SETTXBUFHWMARK:
00844         NutEnterCritical();
00845         dcb->dcb_tx_rbf.rbf_hwm = (size_t) lv;
00846         NutExitCritical();
00847         break;
00848     case UART_GETTXBUFHWMARK:
00849         *lvp = dcb->dcb_tx_rbf.rbf_hwm;
00850         break;
00851 
00852     case UART_SETRXBUFLWMARK:
00853         NutEnterCritical();
00854         dcb->dcb_rx_rbf.rbf_lwm = (size_t) lv;
00855         NutExitCritical();
00856         break;
00857     case UART_GETRXBUFLWMARK:
00858         *lvp = dcb->dcb_rx_rbf.rbf_lwm;
00859         break;
00860 
00861     case UART_SETRXBUFHWMARK:
00862         NutEnterCritical();
00863         dcb->dcb_rx_rbf.rbf_hwm = (size_t) lv;
00864         NutExitCritical();
00865         break;
00866     case UART_GETRXBUFHWMARK:
00867         *lvp = dcb->dcb_rx_rbf.rbf_hwm;
00868         break;
00869 
00870     default:
00871         rc = -1;
00872         break;
00873     }
00874     return rc;
00875 }
00876 
00888 long UsartSize (NUTFILE *fp)
00889 {
00890     long avail;
00891     NUTDEVICE *dev = fp->nf_dev;
00892     USARTDCB *dcb = dev->dev_dcb;
00893     RINGBUF *rbf = &dcb->dcb_rx_rbf;
00894 
00895     /* Atomic access to the ring buffer counter. */
00896     NutEnterCritical();
00897     avail = rbf->rbf_cnt;
00898     NutExitCritical();
00899 
00900     return avail;
00901 }
00902 
00903