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     }
00246 
00247     /*
00248      * Get cooked characters from receive buffer.
00249      */
00250     if (dcb->dcb_modeflags & USART_MF_COOKEDMODE) {
00251         for (rc = 0; rc < (size_t) size;) {
00252             if (taken >= avail) {
00253                 break;
00254             }
00255             ch = *rbf->rbf_tail++;
00256             if (rbf->rbf_tail == rbf->rbf_last) {
00257                 rbf->rbf_tail = rbf->rbf_start;
00258             }
00259             taken++;
00260             if (ch == '\r' || ch == '\n') {
00261                 if (dcb->dcb_last_eol == 0 || dcb->dcb_last_eol == ch) {
00262                     dcb->dcb_last_eol = ch;
00263                     *cp++ = '\n';
00264                     rc++;
00265                 }
00266             } else {
00267                 dcb->dcb_last_eol = 0;
00268                 *cp++ = ch;
00269                 rc++;
00270             }
00271         }
00272     }
00273 
00274     /*
00275      * Get raw characters from receive buffer.
00276      */
00277     else {
00278         if ((rc = size) > avail)
00279             rc = avail;
00280         for (taken = 0; taken < rc; taken++) {
00281             *cp++ = *rbf->rbf_tail++;
00282             if (rbf->rbf_tail == rbf->rbf_last) {
00283                 rbf->rbf_tail = rbf->rbf_start;
00284             }
00285         }
00286     }
00287 
00288     if (taken) {
00289         NutEnterCritical();
00290         rbf->rbf_cnt -= taken;
00291         NutExitCritical();
00292         if (rbf->rbf_cnt < rbf->rbf_lwm) {
00293             (*dcb->dcb_rx_start) ();
00294         }
00295     }
00296     return (int) rc;
00297 }
00298 
00317 static size_t UsartFlushOutput(USARTDCB *dcb, size_t added, size_t left)
00318 {
00319     size_t rc;
00320     RINGBUF *rbf = &dcb->dcb_tx_rbf;
00321 
00322     /*
00323      * Add the new characters to the buffer count.
00324      */
00325     NutEnterCritical();
00326     rbf->rbf_cnt += added;
00327     rc = rbf->rbf_cnt;
00328     NutExitCritical();
00329 
00330     while (rc > left) {
00331         /* Start transmitter and wait for the next event. */
00332         (*dcb->dcb_tx_start) ();
00333         if (NutEventWait(&rbf->rbf_que, dcb->dcb_wtimeout)) {
00334             break;
00335         }
00336         /* Refresh the count. */
00337         NutEnterCritical();
00338         rc = rbf->rbf_cnt;
00339         NutExitCritical();
00340     };
00341     return rc;
00342 }
00343 
00356 static int UsartPut(NUTDEVICE * dev, CONST void *buffer, int len, int pflg)
00357 {
00358     int rc;
00359     CONST uint8_t *cp;
00360     uint8_t lbmode;
00361     ureg_t cooked;
00362     uint8_t ch;
00363     size_t cnt;
00364     size_t added;
00365     USARTDCB *dcb = dev->dev_dcb;
00366     RINGBUF *rbf = &dcb->dcb_tx_rbf;
00367 
00368     /*
00369      * No output ring buffer allocated, this device is read only.
00370      */
00371     if (rbf->rbf_siz == 0) {
00372         return -1;
00373     }
00374 
00375     /*
00376      * Call without data pointer flushes the buffer. In this case a return
00377      * value not equal zero indicates write timeout.
00378      */
00379     if (buffer == 0) {
00380         return UsartFlushOutput(dcb, 0, 0);
00381     }
00382 
00383     if (dcb->dcb_modeflags & USART_MF_LINEBUFFER)
00384         lbmode = 1;
00385     else
00386         lbmode = 0;
00387 
00388     if (dcb->dcb_modeflags & USART_MF_COOKEDMODE)
00389         cooked = 1;
00390     else
00391         cooked = 0;
00392 
00393     /*
00394      * Get the number of buffered bytes. The transmit interrupt will modify
00395      * this value, so make the query atomic.
00396      */
00397     NutEnterCritical();
00398     cnt = rbf->rbf_cnt;
00399     NutExitCritical();
00400 
00401     /*
00402      * Move bytes to the transmit buffer.
00403      */
00404     cp = buffer;
00405     added = 0;
00406     for (rc = 0; rc < len;) {
00407         /*
00408          * If we reached the high watermark, then kick the hardware driver
00409          * to start transmission and wait until the low watermark is reached.
00410          */
00411         if (cnt + added >= rbf->rbf_hwm) {
00412             cnt = UsartFlushOutput(dcb, added, rbf->rbf_lwm);
00413             added = 0;
00414             /* If still above the mark, then a timeout occured. */
00415             if(cnt > rbf->rbf_lwm) {
00416                 break;
00417             }
00418         }
00419 
00420         /*
00421          * Get the next data byte. If the pflg parameter is set, then data
00422          * is located in program space.
00423          */
00424         ch = pflg ? PRG_RDB(cp) : *cp;
00425 
00426         /*
00427          * In cooked mode we prepend a carriage return to any linefeed
00428          * character.
00429          */
00430         if (cooked == 1 && ch == '\n') {
00431             cooked = 2;
00432             ch = '\r';
00433             if (lbmode == 1)
00434                 lbmode = 2;
00435         } else {
00436             if (cooked == 2)
00437                 cooked = 1;
00438             cp++;
00439             rc++;
00440         }
00441         *rbf->rbf_head++ = ch;
00442         if (rbf->rbf_head == rbf->rbf_last) {
00443             rbf->rbf_head = rbf->rbf_start;
00444         }
00445         added++;
00446     }
00447 
00448     if (added) {
00449         NutEnterCritical();
00450         rbf->rbf_cnt += added;
00451         NutExitCritical();
00452         (*dcb->dcb_tx_start) ();
00453     }
00454 
00455     return rc;
00456 }
00457 
00477 int UsartWrite(NUTFILE * fp, CONST void *buffer, int len)
00478 {
00479     return UsartPut(fp->nf_dev, buffer, len, 0);
00480 }
00481 
00503 int UsartWrite_P(NUTFILE * fp, PGM_P buffer, int len)
00504 {
00505     return UsartPut(fp->nf_dev, (CONST char *) buffer, len, 1);
00506 }
00507 
00521 int UsartClose(NUTFILE * fp)
00522 {
00523     NUTDEVICE *dev = fp->nf_dev;
00524     USARTDCB *dcb = dev->dev_dcb;
00525 
00526     if (fp == 0 || fp == NUTFILE_EOF)
00527         return -1;
00528 
00529     free(fp);
00530     UsartResetBuffer(&dcb->dcb_tx_rbf, 0, 0, 0);
00531     UsartResetBuffer(&dcb->dcb_rx_rbf, 0, 0, 0);
00532 
00533     return 0;
00534 }
00535 
00554 NUTFILE *UsartOpen(NUTDEVICE * dev, CONST char *name, int mode, int acc)
00555 {
00556     USARTDCB *dcb = dev->dev_dcb;
00557     NUTFILE *fp;
00558 
00559     /*
00560      * Create the tranmit buffer unless this is used for read only.
00561      */
00562     if ((mode & 0x0003) != _O_RDONLY) {
00563         if (UsartResetBuffer(&dcb->dcb_tx_rbf, USART_TXBUFSIZ, USART_TXLOWMARK, USART_TXHIWMARK)) {
00564             return NUTFILE_EOF;
00565         }
00566     }
00567 
00568     /*
00569      * Create the receive buffer unless this is used for write only.
00570      */
00571     if ((mode & 0x0003) != _O_WRONLY) {
00572         if (UsartResetBuffer(&dcb->dcb_rx_rbf, USART_RXBUFSIZ, USART_RXLOWMARK, USART_RXHIWMARK)) {
00573             free(dcb->dcb_tx_rbf.rbf_start);
00574             return NUTFILE_EOF;
00575         }
00576     }
00577 
00578     /*
00579      * Allocate memory for the file structure.
00580      */
00581     if ((fp = malloc(sizeof(NUTFILE))) == 0) {
00582         free(dcb->dcb_tx_rbf.rbf_start);
00583         free(dcb->dcb_rx_rbf.rbf_start);
00584         return NUTFILE_EOF;
00585     }
00586 
00587     /* Set proper device modes. */
00588     if ((mode & 0xC000) == _O_BINARY) {
00589         dcb->dcb_modeflags &= ~USART_MF_COOKEDMODE;
00590     } else {
00591         dcb->dcb_modeflags |= USART_MF_COOKEDMODE;
00592     }
00593 
00594     /*
00595      * For now we do the initialization here. Later we may implement
00596      * a file creation routine to get a linked list of all opened
00597      * files in the system.
00598      */
00599     fp->nf_next = 0;
00600     fp->nf_dev = dev;
00601     fp->nf_fcb = 0;
00602 
00603     if ((mode & 0x0003) != _O_WRONLY) {
00604         (*dcb->dcb_rx_start) ();
00605     }
00606 
00607     return fp;
00608 }
00609 
00671 int UsartIOCtl(NUTDEVICE * dev, int req, void *conf)
00672 {
00673     int rc = 0;
00674     USARTDCB *dcb;
00675     RINGBUF *rbf;
00676     uint32_t *lvp = (uint32_t *) conf;
00677     uint32_t lv = *lvp;
00678     uint8_t bv = (uint8_t) lv;
00679 
00680     dcb = dev->dev_dcb;
00681 
00682     switch (req) {
00683     case UART_SETSPEED:
00684         rc = (*dcb->dcb_set_speed) (lv);
00685         break;
00686     case UART_GETSPEED:
00687         *lvp = (*dcb->dcb_get_speed) ();
00688         break;
00689 
00690     case UART_SETDATABITS:
00691         rc = (*dcb->dcb_set_data_bits) (bv);
00692         break;
00693     case UART_GETDATABITS:
00694         *lvp = (*dcb->dcb_get_data_bits) ();
00695         break;
00696 
00697     case UART_SETPARITY:
00698         rc = (*dcb->dcb_set_parity) (bv);
00699         break;
00700     case UART_GETPARITY:
00701         *lvp = (*dcb->dcb_get_parity) ();
00702         break;
00703 
00704     case UART_SETSTOPBITS:
00705         rc = (*dcb->dcb_set_stop_bits) (bv);
00706         break;
00707     case UART_GETSTOPBITS:
00708         *lvp = (*dcb->dcb_get_stop_bits) ();
00709         break;
00710 
00711     case UART_SETSTATUS:
00712         /*
00713          * We are not changing the buffer size. Thus, we can safely ignore the
00714          * result of UsartResetBuffer(). This way we found a work around for
00715          * the AVRGCC 4.1.1 bug, which appeared here previously.
00716          */
00717         if (lv & UART_RXBUFFEREMPTY) {
00718             rbf = &dcb->dcb_rx_rbf;
00719             UsartResetBuffer(rbf, rbf->rbf_siz, rbf->rbf_lwm, rbf->rbf_hwm);
00720             (*dcb->dcb_rx_start) ();
00721         }
00722         if (lv & UART_TXBUFFEREMPTY) {
00723             rbf = &dcb->dcb_tx_rbf;
00724             UsartResetBuffer(rbf, rbf->rbf_siz, rbf->rbf_lwm, rbf->rbf_hwm);
00725         }
00726         rc = (*dcb->dcb_set_status) (lv & ~(UART_RXBUFFEREMPTY | UART_TXBUFFEREMPTY));
00727         break;
00728     case UART_GETSTATUS:
00729         *lvp = (*dcb->dcb_get_status) ();
00730         /*
00731          * Determine buffer status.
00732          */
00733         if (dcb->dcb_rx_rbf.rbf_cnt == 0) {
00734             *lvp |= UART_RXBUFFEREMPTY;
00735         }
00736         if (dcb->dcb_tx_rbf.rbf_cnt == 0) {
00737             *lvp |= UART_TXBUFFEREMPTY;
00738         }
00739         break;
00740 
00741     case UART_SETREADTIMEOUT:
00742         dcb->dcb_rtimeout = lv;
00743         break;
00744     case UART_GETREADTIMEOUT:
00745         *lvp = dcb->dcb_rtimeout;
00746         break;
00747 
00748     case UART_SETWRITETIMEOUT:
00749         dcb->dcb_wtimeout = lv;
00750         break;
00751     case UART_GETWRITETIMEOUT:
00752         *lvp = dcb->dcb_wtimeout;
00753         break;
00754 
00755     case UART_SETLOCALECHO:
00756         if (bv)
00757             dcb->dcb_modeflags |= USART_MF_LOCALECHO;
00758         else
00759             dcb->dcb_modeflags &= ~USART_MF_LOCALECHO;
00760         break;
00761     case UART_GETLOCALECHO:
00762         if (dcb->dcb_modeflags & USART_MF_LOCALECHO)
00763             *lvp = 1;
00764         else
00765             *lvp = 0;
00766         break;
00767 
00768     case UART_SETFLOWCONTROL:
00769         rc = (*dcb->dcb_set_flow_control) (lv);
00770         break;
00771     case UART_GETFLOWCONTROL:
00772         *lvp = (*dcb->dcb_get_flow_control) ();
00773         break;
00774 
00775     case UART_SETCOOKEDMODE:
00776         if (bv)
00777             dcb->dcb_modeflags |= USART_MF_COOKEDMODE;
00778         else
00779             dcb->dcb_modeflags &= ~USART_MF_COOKEDMODE;
00780         break;
00781     case UART_GETCOOKEDMODE:
00782         if (dcb->dcb_modeflags & USART_MF_COOKEDMODE)
00783             *lvp = 1;
00784         else
00785             *lvp = 0;
00786         break;
00787 
00788     case UART_SETHDPXMODE:
00789         if (bv)
00790             dcb->dcb_modeflags |= USART_MF_HALFDUPLEX;
00791         else
00792             dcb->dcb_modeflags &= ~USART_MF_HALFDUPLEX;
00793         break;
00794     case UART_GETHDPXMODE:
00795         if (dcb->dcb_modeflags & USART_MF_HALFDUPLEX)
00796             *lvp = 1;
00797         else
00798             *lvp = 0;
00799         break;
00800 
00801     case UART_SETCLOCKMODE:
00802         rc = (*dcb->dcb_set_clock_mode) (lv);
00803         break;
00804     case UART_GETCLOCKMODE:
00805         *lvp = (*dcb->dcb_get_clock_mode) ();
00806         break;
00807 
00808     case UART_SETTXBUFSIZ:
00809         rbf = &dcb->dcb_tx_rbf;
00810         rc = UsartResetBuffer(rbf, (size_t) lv, rbf->rbf_lwm, rbf->rbf_hwm);
00811         if (rc == 0) {
00812             (*dcb->dcb_rx_start) ();
00813         }
00814         break;
00815     case UART_GETTXBUFSIZ:
00816         *lvp = dcb->dcb_tx_rbf.rbf_siz;
00817         break;
00818 
00819     case UART_SETRXBUFSIZ:
00820         rbf = &dcb->dcb_rx_rbf;
00821         rc = UsartResetBuffer(rbf, (size_t) lv, rbf->rbf_lwm, rbf->rbf_hwm);
00822         break;
00823     case UART_GETRXBUFSIZ:
00824         *lvp = dcb->dcb_rx_rbf.rbf_siz;
00825         break;
00826 
00827     case UART_SETTXBUFLWMARK:
00828         NutEnterCritical();
00829         dcb->dcb_tx_rbf.rbf_lwm = (size_t) lv;
00830         NutExitCritical();
00831         break;
00832     case UART_GETTXBUFLWMARK:
00833         *lvp = dcb->dcb_tx_rbf.rbf_lwm;
00834         break;
00835 
00836     case UART_SETTXBUFHWMARK:
00837         NutEnterCritical();
00838         dcb->dcb_tx_rbf.rbf_hwm = (size_t) lv;
00839         NutExitCritical();
00840         break;
00841     case UART_GETTXBUFHWMARK:
00842         *lvp = dcb->dcb_tx_rbf.rbf_hwm;
00843         break;
00844 
00845     case UART_SETRXBUFLWMARK:
00846         NutEnterCritical();
00847         dcb->dcb_rx_rbf.rbf_lwm = (size_t) lv;
00848         NutExitCritical();
00849         break;
00850     case UART_GETRXBUFLWMARK:
00851         *lvp = dcb->dcb_rx_rbf.rbf_lwm;
00852         break;
00853 
00854     case UART_SETRXBUFHWMARK:
00855         NutEnterCritical();
00856         dcb->dcb_rx_rbf.rbf_hwm = (size_t) lv;
00857         NutExitCritical();
00858         break;
00859     case UART_GETRXBUFHWMARK:
00860         *lvp = dcb->dcb_rx_rbf.rbf_hwm;
00861         break;
00862 
00863     default:
00864         rc = -1;
00865         break;
00866     }
00867     return rc;
00868 }
00869 
00881 long UsartSize (NUTFILE *fp)
00882 {
00883     long avail;
00884     NUTDEVICE *dev = fp->nf_dev;
00885     USARTDCB *dcb = dev->dev_dcb;
00886     RINGBUF *rbf = &dcb->dcb_rx_rbf;
00887 
00888     /* Atomic access to the ring buffer counter. */
00889     NutEnterCritical();
00890     avail = rbf->rbf_cnt;
00891     NutExitCritical();
00892 
00893     return avail;
00894 }
00895 
00896 

© 2000-2007 by egnite Software GmbH - visit http://www.ethernut.de/