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 #include <compiler.h>
00063 #include <stdlib.h>
00064 #include <string.h>
00065
00066 #include <sys/atom.h>
00067 #include <sys/heap.h>
00068 #include <sys/event.h>
00069 #include <sys/timer.h>
00070
00071 #include <dev/irqreg.h>
00072 #include <dev/usart.h>
00073
00074 #include <fcntl.h>
00075
00076
00077
00078
00079
00080 #ifndef _IOFBF
00081 #define _IOFBF 0x00
00082 #define _IOLBF 0x01
00083 #define _IONBF 0x02
00084 #endif
00085
00090
00104 int UsartInit(NUTDEVICE * dev)
00105 {
00106 int rc;
00107 USARTDCB *dcb = dev->dev_dcb;
00108
00109
00110 if ((rc = (*dcb->dcb_init) ()) == 0) {
00111
00112 (*dcb->dcb_set_speed) (USART_INITSPEED);
00113 }
00114 return rc;
00115 }
00116
00127 static int UsartResetBuffer(RINGBUF * rbf, size_t size, size_t lowm, size_t hiwm)
00128 {
00129 u_char *xbp = rbf->rbf_start;
00130 size_t xsz = rbf->rbf_siz;
00131
00132
00133 NutEnterCritical();
00134 rbf->rbf_siz = 0;
00135 NutExitCritical();
00136
00137
00138 if (xsz != size) {
00139 if (xsz && xbp) {
00140 free(xbp);
00141 }
00142 if (size && (xbp = malloc(size)) == 0) {
00143 return -1;
00144 }
00145 }
00146
00147
00148 if (size) {
00149 rbf->rbf_start = xbp;
00150 rbf->rbf_head = xbp;
00151 rbf->rbf_tail = xbp;
00152 rbf->rbf_last = xbp + size;
00153 rbf->rbf_lwm = lowm;
00154 rbf->rbf_hwm = hiwm;
00155 rbf->rbf_cnt = 0;
00156
00157
00158 NutEnterCritical();
00159 rbf->rbf_siz = size;
00160 NutExitCritical();
00161 }
00162 return 0;
00163 }
00164
00191 int UsartRead(NUTFILE * fp, void *buffer, int size)
00192 {
00193 size_t rc;
00194 size_t avail;
00195 size_t taken = 0;
00196 u_char ch;
00197 u_char *cp = buffer;
00198 NUTDEVICE *dev = fp->nf_dev;
00199 USARTDCB *dcb = dev->dev_dcb;
00200 RINGBUF *rbf = &dcb->dcb_rx_rbf;
00201
00202
00203
00204
00205 if (rbf->rbf_siz == 0) {
00206 return -1;
00207 }
00208
00209
00210
00211
00212 if (buffer == 0) {
00213 UsartResetBuffer(rbf, rbf->rbf_siz, rbf->rbf_lwm, rbf->rbf_hwm);
00214 (*dcb->dcb_rx_start) ();
00215 return 0;
00216 }
00217
00218
00219
00220
00221
00222 for (;;) {
00223
00224 NutEnterCritical();
00225 avail = rbf->rbf_cnt;
00226 NutExitCritical();
00227 if (avail) {
00228 break;
00229 }
00230
00231
00232
00233
00234 (*dcb->dcb_rx_start) ();
00235 if (NutEventWait(&rbf->rbf_que, dcb->dcb_rtimeout)) {
00236 return 0;
00237 }
00238 }
00239
00240
00241
00242
00243 if (dcb->dcb_modeflags & USART_MF_COOKEDMODE) {
00244 for (rc = 0; rc < (size_t) size;) {
00245 if (taken >= avail) {
00246 break;
00247 }
00248 ch = *rbf->rbf_tail++;
00249 if (rbf->rbf_tail == rbf->rbf_last) {
00250 rbf->rbf_tail = rbf->rbf_start;
00251 }
00252 taken++;
00253 if (ch == '\r' || ch == '\n') {
00254 if (dcb->dcb_last_eol == 0 || dcb->dcb_last_eol == ch) {
00255 dcb->dcb_last_eol = ch;
00256 *cp++ = '\n';
00257 rc++;
00258 }
00259 } else {
00260 dcb->dcb_last_eol = 0;
00261 *cp++ = ch;
00262 rc++;
00263 }
00264 }
00265 }
00266
00267
00268
00269
00270 else {
00271 if ((rc = size) > avail)
00272 rc = avail;
00273 for (taken = 0; taken < rc; taken++) {
00274 *cp++ = *rbf->rbf_tail++;
00275 if (rbf->rbf_tail == rbf->rbf_last) {
00276 rbf->rbf_tail = rbf->rbf_start;
00277 }
00278 }
00279 }
00280
00281 if (taken) {
00282 NutEnterCritical();
00283 rbf->rbf_cnt -= taken;
00284 NutExitCritical();
00285 if (rbf->rbf_cnt < rbf->rbf_lwm) {
00286 (*dcb->dcb_rx_start) ();
00287 }
00288 }
00289 return (int) rc;
00290 }
00291
00310 static size_t UsartFlushOutput(USARTDCB *dcb, size_t added, size_t left)
00311 {
00312 size_t rc;
00313 RINGBUF *rbf = &dcb->dcb_tx_rbf;
00314
00315
00316
00317
00318 NutEnterCritical();
00319 rbf->rbf_cnt += added;
00320 rc = rbf->rbf_cnt;
00321 NutExitCritical();
00322
00323 while (rc > left) {
00324
00325 (*dcb->dcb_tx_start) ();
00326 if (NutEventWait(&rbf->rbf_que, dcb->dcb_wtimeout)) {
00327 break;
00328 }
00329
00330 NutEnterCritical();
00331 rc = rbf->rbf_cnt;
00332 NutExitCritical();
00333 };
00334 return rc;
00335 }
00336
00349 static int UsartPut(NUTDEVICE * dev, CONST void *buffer, int len, int pflg)
00350 {
00351 int rc;
00352 CONST u_char *cp;
00353 u_char lbmode;
00354 ureg_t cooked;
00355 u_char ch;
00356 size_t cnt;
00357 size_t added;
00358 USARTDCB *dcb = dev->dev_dcb;
00359 RINGBUF *rbf = &dcb->dcb_tx_rbf;
00360
00361
00362
00363
00364 if (rbf->rbf_siz == 0) {
00365 return -1;
00366 }
00367
00368
00369
00370
00371
00372 if (buffer == 0) {
00373 return UsartFlushOutput(dcb, 0, 0);
00374 }
00375
00376 if (dcb->dcb_modeflags & USART_MF_LINEBUFFER)
00377 lbmode = 1;
00378 else
00379 lbmode = 0;
00380
00381 if (dcb->dcb_modeflags & USART_MF_COOKEDMODE)
00382 cooked = 1;
00383 else
00384 cooked = 0;
00385
00386
00387
00388
00389
00390 NutEnterCritical();
00391 cnt = rbf->rbf_cnt;
00392 NutExitCritical();
00393
00394
00395
00396
00397 cp = buffer;
00398 added = 0;
00399 for (rc = 0; rc < len;) {
00400
00401
00402
00403
00404 if (cnt + added >= rbf->rbf_hwm) {
00405 cnt = UsartFlushOutput(dcb, added, rbf->rbf_lwm);
00406 added = 0;
00407
00408 if(cnt > rbf->rbf_lwm) {
00409 break;
00410 }
00411 }
00412
00413
00414
00415
00416
00417 ch = pflg ? PRG_RDB(cp) : *cp;
00418
00419
00420
00421
00422
00423 if (cooked == 1 && ch == '\n') {
00424 cooked = 2;
00425 ch = '\r';
00426 if (lbmode == 1)
00427 lbmode = 2;
00428 } else {
00429 if (cooked == 2)
00430 cooked = 1;
00431 cp++;
00432 rc++;
00433 }
00434 *rbf->rbf_head++ = ch;
00435 if (rbf->rbf_head == rbf->rbf_last) {
00436 rbf->rbf_head = rbf->rbf_start;
00437 }
00438 added++;
00439 }
00440
00441 if (added) {
00442 NutEnterCritical();
00443 rbf->rbf_cnt += added;
00444 NutExitCritical();
00445 (*dcb->dcb_tx_start) ();
00446 }
00447
00448 return rc;
00449 }
00450
00470 int UsartWrite(NUTFILE * fp, CONST void *buffer, int len)
00471 {
00472 return UsartPut(fp->nf_dev, buffer, len, 0);
00473 }
00474
00496 int UsartWrite_P(NUTFILE * fp, PGM_P buffer, int len)
00497 {
00498 return UsartPut(fp->nf_dev, (CONST char *) buffer, len, 1);
00499 }
00500
00514 int UsartClose(NUTFILE * fp)
00515 {
00516 NUTDEVICE *dev = fp->nf_dev;
00517 USARTDCB *dcb = dev->dev_dcb;
00518
00519 if (fp == 0 || fp == NUTFILE_EOF)
00520 return -1;
00521
00522 free(fp);
00523 UsartResetBuffer(&dcb->dcb_tx_rbf, 0, 0, 0);
00524 UsartResetBuffer(&dcb->dcb_rx_rbf, 0, 0, 0);
00525
00526 return 0;
00527 }
00528
00547 NUTFILE *UsartOpen(NUTDEVICE * dev, CONST char *name, int mode, int acc)
00548 {
00549 USARTDCB *dcb = dev->dev_dcb;
00550 NUTFILE *fp;
00551
00552
00553
00554
00555 if ((mode & 0x0003) != _O_RDONLY) {
00556 if (UsartResetBuffer(&dcb->dcb_tx_rbf, USART_TXBUFSIZ, USART_TXLOWMARK, USART_TXHIWMARK)) {
00557 return NUTFILE_EOF;
00558 }
00559 }
00560
00561
00562
00563
00564 if ((mode & 0x0003) != _O_WRONLY) {
00565 if (UsartResetBuffer(&dcb->dcb_rx_rbf, USART_RXBUFSIZ, USART_RXLOWMARK, USART_RXHIWMARK)) {
00566 free(dcb->dcb_tx_rbf.rbf_start);
00567 return NUTFILE_EOF;
00568 }
00569 }
00570
00571
00572
00573
00574 if ((fp = malloc(sizeof(NUTFILE))) == 0) {
00575 free(dcb->dcb_tx_rbf.rbf_start);
00576 free(dcb->dcb_rx_rbf.rbf_start);
00577 return NUTFILE_EOF;
00578 }
00579
00580
00581 if ((mode & 0xC000) == _O_BINARY) {
00582 dcb->dcb_modeflags &= ~USART_MF_COOKEDMODE;
00583 } else {
00584 dcb->dcb_modeflags |= USART_MF_COOKEDMODE;
00585 }
00586
00587
00588
00589
00590
00591
00592 fp->nf_next = 0;
00593 fp->nf_dev = dev;
00594 fp->nf_fcb = 0;
00595
00596 if ((mode & 0x0003) != _O_WRONLY) {
00597 (*dcb->dcb_rx_start) ();
00598 }
00599
00600 return fp;
00601 }
00602
00662 int UsartIOCtl(NUTDEVICE * dev, int req, void *conf)
00663 {
00664 int rc = 0;
00665 USARTDCB *dcb;
00666 RINGBUF *rbf;
00667 u_long *lvp = (u_long *) conf;
00668 u_long lv = *lvp;
00669 u_char bv = (u_char) lv;
00670
00671 dcb = dev->dev_dcb;
00672
00673 switch (req) {
00674 case UART_SETSPEED:
00675 rc = (*dcb->dcb_set_speed) (lv);
00676 break;
00677 case UART_GETSPEED:
00678 *lvp = (*dcb->dcb_get_speed) ();
00679 break;
00680
00681 case UART_SETDATABITS:
00682 rc = (*dcb->dcb_set_data_bits) (bv);
00683 break;
00684 case UART_GETDATABITS:
00685 *lvp = (*dcb->dcb_get_data_bits) ();
00686 break;
00687
00688 case UART_SETPARITY:
00689 rc = (*dcb->dcb_set_parity) (bv);
00690 break;
00691 case UART_GETPARITY:
00692 *lvp = (*dcb->dcb_get_parity) ();
00693 break;
00694
00695 case UART_SETSTOPBITS:
00696 rc = (*dcb->dcb_set_stop_bits) (bv);
00697 break;
00698 case UART_GETSTOPBITS:
00699 *lvp = (*dcb->dcb_get_stop_bits) ();
00700 break;
00701
00702 case UART_SETSTATUS:
00703
00704
00705
00706
00707
00708 if (lv & UART_RXBUFFEREMPTY) {
00709 rbf = &dcb->dcb_rx_rbf;
00710 UsartResetBuffer(rbf, rbf->rbf_siz, rbf->rbf_lwm, rbf->rbf_hwm);
00711 (*dcb->dcb_rx_start) ();
00712 }
00713 if (lv & UART_TXBUFFEREMPTY) {
00714 rbf = &dcb->dcb_tx_rbf;
00715 UsartResetBuffer(rbf, rbf->rbf_siz, rbf->rbf_lwm, rbf->rbf_hwm);
00716 }
00717 rc = (*dcb->dcb_set_status) (lv & ~(UART_RXBUFFEREMPTY | UART_TXBUFFEREMPTY));
00718 break;
00719 case UART_GETSTATUS:
00720 *lvp = (*dcb->dcb_get_status) ();
00721
00722
00723
00724 if (dcb->dcb_rx_rbf.rbf_cnt == 0) {
00725 *lvp |= UART_RXBUFFEREMPTY;
00726 }
00727 if (dcb->dcb_tx_rbf.rbf_cnt == 0) {
00728 *lvp |= UART_TXBUFFEREMPTY;
00729 }
00730 break;
00731
00732 case UART_SETREADTIMEOUT:
00733 dcb->dcb_rtimeout = lv;
00734 break;
00735 case UART_GETREADTIMEOUT:
00736 *lvp = dcb->dcb_rtimeout;
00737 break;
00738
00739 case UART_SETWRITETIMEOUT:
00740 dcb->dcb_wtimeout = lv;
00741 break;
00742 case UART_GETWRITETIMEOUT:
00743 *lvp = dcb->dcb_wtimeout;
00744 break;
00745
00746 case UART_SETLOCALECHO:
00747 if (bv)
00748 dcb->dcb_modeflags |= USART_MF_LOCALECHO;
00749 else
00750 dcb->dcb_modeflags &= ~USART_MF_LOCALECHO;
00751 break;
00752 case UART_GETLOCALECHO:
00753 if (dcb->dcb_modeflags & USART_MF_LOCALECHO)
00754 *lvp = 1;
00755 else
00756 *lvp = 0;
00757 break;
00758
00759 case UART_SETFLOWCONTROL:
00760 rc = (*dcb->dcb_set_flow_control) (lv);
00761 break;
00762 case UART_GETFLOWCONTROL:
00763 *lvp = (*dcb->dcb_get_flow_control) ();
00764 break;
00765
00766 case UART_SETCOOKEDMODE:
00767 if (bv)
00768 dcb->dcb_modeflags |= USART_MF_COOKEDMODE;
00769 else
00770 dcb->dcb_modeflags &= ~USART_MF_COOKEDMODE;
00771 break;
00772 case UART_GETCOOKEDMODE:
00773 if (dcb->dcb_modeflags & USART_MF_COOKEDMODE)
00774 *lvp = 1;
00775 else
00776 *lvp = 0;
00777 break;
00778
00779 case UART_SETCLOCKMODE:
00780 rc = (*dcb->dcb_set_clock_mode) (lv);
00781 break;
00782 case UART_GETCLOCKMODE:
00783 *lvp = (*dcb->dcb_get_clock_mode) ();
00784 break;
00785
00786 case UART_SETTXBUFSIZ:
00787 rbf = &dcb->dcb_tx_rbf;
00788 rc = UsartResetBuffer(rbf, (size_t) lv, rbf->rbf_lwm, rbf->rbf_hwm);
00789 if (rc == 0) {
00790 (*dcb->dcb_rx_start) ();
00791 }
00792 break;
00793 case UART_GETTXBUFSIZ:
00794 *lvp = dcb->dcb_tx_rbf.rbf_siz;
00795 break;
00796
00797 case UART_SETRXBUFSIZ:
00798 rbf = &dcb->dcb_rx_rbf;
00799 rc = UsartResetBuffer(rbf, (size_t) lv, rbf->rbf_lwm, rbf->rbf_hwm);
00800 break;
00801 case UART_GETRXBUFSIZ:
00802 *lvp = dcb->dcb_rx_rbf.rbf_siz;
00803 break;
00804
00805 case UART_SETTXBUFLWMARK:
00806 NutEnterCritical();
00807 dcb->dcb_tx_rbf.rbf_lwm = (size_t) lv;
00808 NutExitCritical();
00809 break;
00810 case UART_GETTXBUFLWMARK:
00811 *lvp = dcb->dcb_tx_rbf.rbf_lwm;
00812 break;
00813
00814 case UART_SETTXBUFHWMARK:
00815 NutEnterCritical();
00816 dcb->dcb_tx_rbf.rbf_hwm = (size_t) lv;
00817 NutExitCritical();
00818 break;
00819 case UART_GETTXBUFHWMARK:
00820 *lvp = dcb->dcb_tx_rbf.rbf_hwm;
00821 break;
00822
00823 case UART_SETRXBUFLWMARK:
00824 NutEnterCritical();
00825 dcb->dcb_rx_rbf.rbf_lwm = (size_t) lv;
00826 NutExitCritical();
00827 break;
00828 case UART_GETRXBUFLWMARK:
00829 *lvp = dcb->dcb_rx_rbf.rbf_lwm;
00830 break;
00831
00832 case UART_SETRXBUFHWMARK:
00833 NutEnterCritical();
00834 dcb->dcb_rx_rbf.rbf_hwm = (size_t) lv;
00835 NutExitCritical();
00836 break;
00837 case UART_GETRXBUFHWMARK:
00838 *lvp = dcb->dcb_rx_rbf.rbf_hwm;
00839 break;
00840
00841 default:
00842 rc = -1;
00843 break;
00844 }
00845 return rc;
00846 }
00847
00859 long UsartSize (NUTFILE *fp)
00860 {
00861 long avail;
00862 NUTDEVICE *dev = fp->nf_dev;
00863 USARTDCB *dcb = dev->dev_dcb;
00864 RINGBUF *rbf = &dcb->dcb_rx_rbf;
00865
00866
00867 NutEnterCritical();
00868 avail = rbf->rbf_cnt;
00869 NutExitCritical();
00870
00871 return avail;
00872 }
00873
00874