00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 
00035 
00036 
00037 
00038 
00039 
00040 
00041 
00042 
00043 
00044 
00045 
00046 
00047 
00048 
00049 
00050 
00051 
00052 
00053 
00054 
00055 
00056 
00057 
00058 
00059 
00060 
00061 
00062 
00063 
00064 
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 
00085 
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     
00117     if ((rc = (*dcb->dcb_init) ()) == 0) {
00118         
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     
00140     NutEnterCritical();
00141     rbf->rbf_siz = 0;
00142     NutExitCritical();
00143 
00144     
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     
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         
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 
00211 
00212     if (rbf->rbf_siz == 0) {
00213         return -1;
00214     }
00215 
00216     
00217 
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 
00227 
00228 
00229     for (;;) {
00230         
00231         NutEnterCritical();
00232         avail = rbf->rbf_cnt;
00233         NutExitCritical();
00234         if (avail) {
00235             break;
00236         }
00237         
00238 
00239 
00240 
00241         (*dcb->dcb_rx_start) ();
00242         if (NutEventWait(&rbf->rbf_que, dcb->dcb_rtimeout)) {
00243             return 0;
00244         }
00245         
00246         if (rbf->rbf_siz == 0) {
00247             return -1;
00248         }
00249     }
00250 
00251     
00252 
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 
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 
00328 
00329     NutEnterCritical();
00330     rbf->rbf_cnt += added;
00331     rc = rbf->rbf_cnt;
00332     NutExitCritical();
00333 
00334     while (rc > left) {
00335         
00336         (*dcb->dcb_tx_start) ();
00337         if (NutEventWait(&rbf->rbf_que, dcb->dcb_wtimeout)) {
00338             break;
00339         }
00340         
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 
00374 
00375     if (rbf->rbf_siz == 0) {
00376         return -1;
00377     }
00378 
00379     
00380 
00381 
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 
00399 
00400 
00401     NutEnterCritical();
00402     cnt = rbf->rbf_cnt;
00403     NutExitCritical();
00404 
00405     
00406 
00407 
00408     cp = buffer;
00409     added = 0;
00410     for (rc = 0; rc < len;) {
00411         
00412 
00413 
00414 
00415         if (cnt + added >= rbf->rbf_hwm) {
00416             cnt = UsartFlushOutput(dcb, added, rbf->rbf_lwm);
00417             added = 0;
00418             
00419             if(cnt > rbf->rbf_lwm) {
00420                 break;
00421             }
00422         }
00423 
00424         
00425 
00426 
00427 
00428         ch = pflg ? PRG_RDB(cp) : *cp;
00429 
00430         
00431 
00432 
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     
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 
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 
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 
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     
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 
00603 
00604 
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 
00721 
00722 
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 
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     
00896     NutEnterCritical();
00897     avail = rbf->rbf_cnt;
00898     NutExitCritical();
00899 
00900     return avail;
00901 }
00902 
00903