Nut/OS  4.10.3
API Reference
at91_ahdlc.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2008 by Szemzo András. All rights reserved.
00003  * Copyright (C) 2003-2004 by egnite Software GmbH. All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  *
00009  * 1. Redistributions of source code must retain the above copyright
00010  *    notice, this list of conditions and the following disclaimer.
00011  * 2. Redistributions in binary form must reproduce the above copyright
00012  *    notice, this list of conditions and the following disclaimer in the
00013  *    documentation and/or other materials provided with the distribution.
00014  * 3. Neither the name of the copyright holders nor the names of
00015  *    contributors may be used to endorse or promote products derived
00016  *    from this software without specific prior written permission.
00017  *
00018  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00019  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00020  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00021  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00022  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00023  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00024  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00025  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00026  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00027  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00028  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00029  * SUCH DAMAGE.
00030  *
00031  * For additional information see http://www.ethernut.de/
00032  *
00033  */
00034 
00035 /*
00036  * $Log$
00037  * Revision 1.3  2009/02/06 15:37:39  haraldkipp
00038  * Added stack space multiplier and addend. Adjusted stack space.
00039  *
00040  * Revision 1.2  2008/08/11 06:59:03  haraldkipp
00041  * BSD types replaced by stdint types (feature request #1282721).
00042  *
00043  * Revision 1.1  2008/04/18 13:27:41  haraldkipp
00044  * First ARM implementation, done by Szemzo Andras.
00045  *
00046  */
00047 
00048 // TODO - 
00049 /*
00050  - add proper close function
00051  - add proper ioctrl
00052  - rewrite to enable uart0 as well
00053 */
00054 
00055 #define NUT_DEPRECATED
00056 
00057 #include <cfg/ahdlc.h>
00058 
00059 #include <string.h>
00060 #include <stdlib.h>
00061 #include <fcntl.h>
00062 
00063 #include <sys/nutconfig.h>
00064 #include <sys/atom.h>
00065 #include <sys/heap.h>
00066 #include <sys/event.h>
00067 #include <sys/timer.h>
00068 #include <sys/thread.h>
00069 
00070 #include <dev/irqreg.h>
00071 #include <dev/ppp.h>
00072 
00073 #include <netinet/if_ppp.h>
00074 #include <net/ppp.h>
00075 #include <net/if_var.h>
00076 
00077 #include <dev/usartat91.h>
00078 #include <dev/at91_ahdlc.h>
00079 
00080 
00081 #ifndef NUT_AHDLC_RECV_DMA_SIZE
00082 #define NUT_AHDLC_RECV_DMA_SIZE 64
00083 #endif
00084 
00085 // rxDMA buffer
00086 static unsigned char DMA_RxBuf0[NUT_AHDLC_RECV_DMA_SIZE];
00087 
00088 #define UART_RECEIVER_TIMEOUT           32      /* in bit-times */
00089 
00090 #define SIG_UART                sig_UART1
00091 #define US_ID           US1_ID
00092 #define US_GPIO_PINS    0x00000360
00093 
00094 
00095 
00100 
00101 static AHDLCDCB dcb_ahdlc;
00102 
00109 NUTDEVICE devAhdlc1 = {
00110     0,                          /* Pointer to next device. */
00111     {'u', 'a', 'r', 't', '1', 0, 0, 0, 0},      /* Unique device name. */
00112     IFTYP_CHAR,                 /* Type of device. */
00113     1,                          /* Base address. */
00114     0,                          /* First interrupt number. */
00115     0,                          /* Interface control block. */
00116     &dcb_ahdlc,                 /* Driver control block. */
00117     AhdlcAt91Init,              /* Driver initialization routine, dev_init. */
00118     AhdlcAt91IOCtl,             /* Driver specific control function, dev_ioctl. */
00119     AhdlcAt91Read,              /* Read from device, dev_read. */
00120     AhdlcAt91Write,             /* Write to device, dev_write. */
00121     AhdlcAt91Open,              /* Open a device or file, dev_open. */
00122     AhdlcAt91Close,             /* Close a device or file, dev_close. */
00123     0                           /* Request file size, dev_size. */
00124 };
00125 
00126 
00127 /*
00128  * FCS lookup table located in program memory space.
00129  */
00130 static prog_char fcstab[512] = {
00131     0x00, 0x00, 0x11, 0x89, 0x23, 0x12, 0x32, 0x9b, 0x46, 0x24, 0x57, 0xad, 0x65, 0x36, 0x74, 0xbf,
00132     0x8c, 0x48, 0x9d, 0xc1, 0xaf, 0x5a, 0xbe, 0xd3, 0xca, 0x6c, 0xdb, 0xe5, 0xe9, 0x7e, 0xf8, 0xf7,
00133     0x10, 0x81, 0x01, 0x08, 0x33, 0x93, 0x22, 0x1a, 0x56, 0xa5, 0x47, 0x2c, 0x75, 0xb7, 0x64, 0x3e,
00134     0x9c, 0xc9, 0x8d, 0x40, 0xbf, 0xdb, 0xae, 0x52, 0xda, 0xed, 0xcb, 0x64, 0xf9, 0xff, 0xe8, 0x76,
00135     0x21, 0x02, 0x30, 0x8b, 0x02, 0x10, 0x13, 0x99, 0x67, 0x26, 0x76, 0xaf, 0x44, 0x34, 0x55, 0xbd,
00136     0xad, 0x4a, 0xbc, 0xc3, 0x8e, 0x58, 0x9f, 0xd1, 0xeb, 0x6e, 0xfa, 0xe7, 0xc8, 0x7c, 0xd9, 0xf5,
00137     0x31, 0x83, 0x20, 0x0a, 0x12, 0x91, 0x03, 0x18, 0x77, 0xa7, 0x66, 0x2e, 0x54, 0xb5, 0x45, 0x3c,
00138     0xbd, 0xcb, 0xac, 0x42, 0x9e, 0xd9, 0x8f, 0x50, 0xfb, 0xef, 0xea, 0x66, 0xd8, 0xfd, 0xc9, 0x74,
00139 
00140     0x42, 0x04, 0x53, 0x8d, 0x61, 0x16, 0x70, 0x9f, 0x04, 0x20, 0x15, 0xa9, 0x27, 0x32, 0x36, 0xbb,
00141     0xce, 0x4c, 0xdf, 0xc5, 0xed, 0x5e, 0xfc, 0xd7, 0x88, 0x68, 0x99, 0xe1, 0xab, 0x7a, 0xba, 0xf3,
00142     0x52, 0x85, 0x43, 0x0c, 0x71, 0x97, 0x60, 0x1e, 0x14, 0xa1, 0x05, 0x28, 0x37, 0xb3, 0x26, 0x3a,
00143     0xde, 0xcd, 0xcf, 0x44, 0xfd, 0xdf, 0xec, 0x56, 0x98, 0xe9, 0x89, 0x60, 0xbb, 0xfb, 0xaa, 0x72,
00144     0x63, 0x06, 0x72, 0x8f, 0x40, 0x14, 0x51, 0x9d, 0x25, 0x22, 0x34, 0xab, 0x06, 0x30, 0x17, 0xb9,
00145     0xef, 0x4e, 0xfe, 0xc7, 0xcc, 0x5c, 0xdd, 0xd5, 0xa9, 0x6a, 0xb8, 0xe3, 0x8a, 0x78, 0x9b, 0xf1,
00146     0x73, 0x87, 0x62, 0x0e, 0x50, 0x95, 0x41, 0x1c, 0x35, 0xa3, 0x24, 0x2a, 0x16, 0xb1, 0x07, 0x38,
00147     0xff, 0xcf, 0xee, 0x46, 0xdc, 0xdd, 0xcd, 0x54, 0xb9, 0xeb, 0xa8, 0x62, 0x9a, 0xf9, 0x8b, 0x70,
00148 
00149     0x84, 0x08, 0x95, 0x81, 0xa7, 0x1a, 0xb6, 0x93, 0xc2, 0x2c, 0xd3, 0xa5, 0xe1, 0x3e, 0xf0, 0xb7,
00150     0x08, 0x40, 0x19, 0xc9, 0x2b, 0x52, 0x3a, 0xdb, 0x4e, 0x64, 0x5f, 0xed, 0x6d, 0x76, 0x7c, 0xff,
00151     0x94, 0x89, 0x85, 0x00, 0xb7, 0x9b, 0xa6, 0x12, 0xd2, 0xad, 0xc3, 0x24, 0xf1, 0xbf, 0xe0, 0x36,
00152     0x18, 0xc1, 0x09, 0x48, 0x3b, 0xd3, 0x2a, 0x5a, 0x5e, 0xe5, 0x4f, 0x6c, 0x7d, 0xf7, 0x6c, 0x7e,
00153     0xa5, 0x0a, 0xb4, 0x83, 0x86, 0x18, 0x97, 0x91, 0xe3, 0x2e, 0xf2, 0xa7, 0xc0, 0x3c, 0xd1, 0xb5,
00154     0x29, 0x42, 0x38, 0xcb, 0x0a, 0x50, 0x1b, 0xd9, 0x6f, 0x66, 0x7e, 0xef, 0x4c, 0x74, 0x5d, 0xfd,
00155     0xb5, 0x8b, 0xa4, 0x02, 0x96, 0x99, 0x87, 0x10, 0xf3, 0xaf, 0xe2, 0x26, 0xd0, 0xbd, 0xc1, 0x34,
00156     0x39, 0xc3, 0x28, 0x4a, 0x1a, 0xd1, 0x0b, 0x58, 0x7f, 0xe7, 0x6e, 0x6e, 0x5c, 0xf5, 0x4d, 0x7c,
00157 
00158     0xc6, 0x0c, 0xd7, 0x85, 0xe5, 0x1e, 0xf4, 0x97, 0x80, 0x28, 0x91, 0xa1, 0xa3, 0x3a, 0xb2, 0xb3,
00159     0x4a, 0x44, 0x5b, 0xcd, 0x69, 0x56, 0x78, 0xdf, 0x0c, 0x60, 0x1d, 0xe9, 0x2f, 0x72, 0x3e, 0xfb,
00160     0xd6, 0x8d, 0xc7, 0x04, 0xf5, 0x9f, 0xe4, 0x16, 0x90, 0xa9, 0x81, 0x20, 0xb3, 0xbb, 0xa2, 0x32,
00161     0x5a, 0xc5, 0x4b, 0x4c, 0x79, 0xd7, 0x68, 0x5e, 0x1c, 0xe1, 0x0d, 0x68, 0x3f, 0xf3, 0x2e, 0x7a,
00162     0xe7, 0x0e, 0xf6, 0x87, 0xc4, 0x1c, 0xd5, 0x95, 0xa1, 0x2a, 0xb0, 0xa3, 0x82, 0x38, 0x93, 0xb1,
00163     0x6b, 0x46, 0x7a, 0xcf, 0x48, 0x54, 0x59, 0xdd, 0x2d, 0x62, 0x3c, 0xeb, 0x0e, 0x70, 0x1f, 0xf9,
00164     0xf7, 0x8f, 0xe6, 0x06, 0xd4, 0x9d, 0xc5, 0x14, 0xb1, 0xab, 0xa0, 0x22, 0x92, 0xb9, 0x83, 0x30,
00165     0x7b, 0xc7, 0x6a, 0x4e, 0x58, 0xd5, 0x49, 0x5c, 0x3d, 0xe3, 0x2c, 0x6a, 0x1e, 0xf1, 0x0f, 0x78
00166 };
00167 
00171 #define IN_ACC_MAP(c, m) (( ((uint8_t) (c)) < 0x20)  && ((m) & (1UL << (c))) != 0)
00172 
00173 #ifndef NUT_THREAD_AHDLCRXSTACK
00174 #define NUT_THREAD_AHDLCRXSTACK     2048
00175 #endif
00176 
00177 
00178 
00184 static void At91UsartInterrupt(void *arg)
00185 {
00186     AHDLCDCB *dcb = arg;
00187     uint16_t count, i;
00188     ureg_t csr = inr(US1_CSR);
00189 
00190     if (csr & (US_ENDRX | US_RXBUFF | US_TIMEOUT)) {
00191         // Todo, handle error flags
00192 
00193         if (csr & US_TIMEOUT) {
00194             count = NUT_AHDLC_RECV_DMA_SIZE - inr(USART1_BASE + PERIPH_RCR_OFF);
00195         } else {
00196             count = NUT_AHDLC_RECV_DMA_SIZE;
00197         }
00198 
00199         for (i = 0; i < count; i++) {
00200             dcb->dcb_rx_buf[dcb->dcb_rx_idx] = DMA_RxBuf0[i];
00201             dcb->dcb_rx_idx++;
00202         }
00203 
00204         outr(USART1_BASE + PERIPH_RPR_OFF, (unsigned int) DMA_RxBuf0);
00205         outr(USART1_BASE + PERIPH_RCR_OFF, NUT_AHDLC_RECV_DMA_SIZE);
00206         outr(USART1_BASE + PERIPH_PTCR_OFF, PDC_RXTEN);
00207         outr(US1_CR, inr(US1_CR) | US_STTTO);
00208         NutEventPostFromIrq(&dcb->dcb_rx_rdy);
00209     }
00210 
00211     if (csr & US_TXRDY) {
00212         if (dcb->dcb_tx_idx != dcb->dcb_wr_idx) {
00213             outr(US1_THR, dcb->dcb_tx_buf[dcb->dcb_tx_idx]);
00214             dcb->dcb_tx_idx++;
00215         } else {
00216             outr(US1_IDR, US_TXRDY);
00217             NutEventPostFromIrq(&dcb->dcb_tx_rdy);
00218         }
00219     }
00220 
00221 }
00222 
00223 
00224 
00225 /*
00226  * \return 0 on success, -1 in case of any errors.
00227  */
00228 static int SendRawByte(AHDLCDCB * dcb, uint8_t ch, uint8_t flush)
00229 {
00230     /*
00231        * If transmit buffer is full, wait until interrupt routine
00232        * signals an empty buffer or until a timeout occurs.
00233      */
00234     while ((uint8_t) (dcb->dcb_wr_idx + 1) == dcb->dcb_tx_idx) {
00235         if (NutEventWait(&dcb->dcb_tx_rdy, dcb->dcb_wtimeout))
00236             break;
00237     }
00238 
00239     /*
00240      * If transmit buffer is still full, we have a write timeout.
00241      */
00242     if ((uint8_t) (dcb->dcb_wr_idx + 1) == dcb->dcb_tx_idx) {
00243         return -1;
00244     }
00245 
00246     /*
00247      * Buffer has room for more data. Put the byte in the buffer
00248      * and increment the write index.
00249      */
00250     dcb->dcb_tx_buf[dcb->dcb_wr_idx] = ch;
00251     dcb->dcb_wr_idx++;
00252 
00253     /*
00254      * If transmit buffer has become full and the transmitter
00255      * is not active, then activate it.
00256      */
00257     if (flush || (uint8_t) (dcb->dcb_wr_idx + 1) == dcb->dcb_tx_idx) {
00258 
00259         NutEnterCritical();
00260 
00261         outr(US1_IER, US_TXRDY);
00262 
00263         NutExitCritical();
00264     }
00265     return 0;
00266 }
00267 
00268 
00269 /*
00270  * Characters are properly escaped and checksum is updated.
00271  *
00272  * \return 0 on success, -1 in case of any errors.
00273  */
00274 static int SendHdlcData(AHDLCDCB * dcb, CONST uint8_t * data, uint16_t len, uint16_t * txfcs)
00275 {
00276     uint16_t tbx;
00277     uint16_t fcs;
00278 
00279     if (txfcs)
00280         fcs = *txfcs;
00281     else
00282         fcs = 0;
00283 
00284     while (len) {
00285         tbx = (uint16_t) ((uint8_t) fcs ^ *data) << 1;
00286         fcs >>= 8;
00287         fcs ^= ((uint16_t) PRG_RDB(fcstab + tbx) << 8) | PRG_RDB(fcstab + tbx + 1);
00288 
00289         if (IN_ACC_MAP(*data, dcb->dcb_tx_accm) || *data == AHDLC_FLAG || *data == AHDLC_ESCAPE) {
00290             if (SendRawByte(dcb, AHDLC_ESCAPE, 0)) {
00291                 return -1;
00292             }
00293             if (SendRawByte(dcb, *data ^ AHDLC_TRANS, 0)) {
00294                 return -1;
00295             }
00296         } else if (SendRawByte(dcb, *data, 0)) {
00297             return -1;
00298         }
00299         data++;
00300         len--;
00301     }
00302     if (txfcs)
00303         *txfcs = fcs;
00304 
00305     return 0;
00306 }
00307 
00318 int AhdlcOutput(NUTDEVICE * dev, NETBUF * nb)
00319 {
00320     uint16_t txfcs;
00321     AHDLCDCB *dcb = dev->dev_dcb;
00322     uint16_t sz;
00323 
00324     /*
00325      * If we are in RAW mode we are not allowed to send AHDLC output.
00326      * We just emulate packet loss behaviour in here.
00327      */
00328     if (dcb->dcb_modeflags & UART_MF_RAWMODE) {
00329         return 0;
00330     }
00331 
00332     /*
00333      * Calculate the number of bytes to be send. Do not
00334      * send packets larger than transmit mru.
00335      */
00336     sz = nb->nb_dl.sz + nb->nb_nw.sz + nb->nb_tp.sz + nb->nb_ap.sz;
00337 
00338     if (sz > dcb->dcb_tx_mru) {
00339         return -1;
00340     }
00341 
00342     /*
00343      * TODO: If transmitter is running, we may omit the flag.
00344      */
00345     SendRawByte(dcb, AHDLC_FLAG, 0);
00346 
00347     /* Initialize the checksum and send the NETBUF. */
00348     txfcs = AHDLC_INITFCS;
00349     if (SendHdlcData(dcb, nb->nb_dl.vp, nb->nb_dl.sz, &txfcs))
00350         return -1;
00351     if (SendHdlcData(dcb, nb->nb_nw.vp, nb->nb_nw.sz, &txfcs))
00352         return -1;
00353     if (SendHdlcData(dcb, nb->nb_tp.vp, nb->nb_tp.sz, &txfcs))
00354         return -1;
00355     if (SendHdlcData(dcb, nb->nb_ap.vp, nb->nb_ap.sz, &txfcs))
00356         return -1;
00357 
00358     /* Send the checksum and the final flag. */
00359     txfcs ^= 0xffff;
00360     if (SendHdlcData(dcb, (uint8_t *) & txfcs, 2, 0))
00361         return -1;
00362 
00363     SendRawByte(dcb, AHDLC_FLAG, 1);
00364 
00365     return 0;
00366 }
00367 
00374 THREAD(AhdlcRx, arg)
00375 {
00376     NUTDEVICE *dev = arg;
00377     NUTDEVICE *netdev;
00378     AHDLCDCB *dcb = dev->dev_dcb;
00379     IFNET *ifn;
00380     NETBUF *nb;
00381     uint8_t *rxbuf;
00382     uint8_t *rxptr;
00383     uint16_t rxcnt;
00384     uint8_t ch;
00385     uint16_t tbx;
00386     uint8_t inframe;
00387     uint8_t escaped;
00388     uint16_t rxfcs;
00389 
00390     NutThreadSetPriority(9);
00391     for (;;) {
00392         /*
00393          * Reset variables to their initial state
00394          */
00395         rxptr = 0;
00396         rxcnt = 0;
00397         escaped = 0;
00398         rxfcs = AHDLC_INITFCS;
00399         inframe = 0;
00400 
00401         for (;;) {
00402             /*
00403              * Wait until the network interface has been attached.
00404              * This will be initiated by the application calling
00405              * NutNetIfConfig(), which in turn calls a HDLC_SETIFNET
00406              * ioctl() to store the NUTDEVICE pointer of the network
00407              * device in dev_icb and trigger an event on dcb_mf_evt.
00408              */
00409             while ((netdev = dev->dev_icb) == 0) {
00410                 if (NutEventWait(&dcb->dcb_mf_evt, 1000) == 0) {
00411                     NutSleep(100);
00412                 }
00413             }
00414             ifn = netdev->dev_icb;
00415             dcb->dcb_rtimeout = 1000;
00416             inframe = 0;
00417 
00418             /*
00419              * Allocate the receive buffer, if this fails, we are in a
00420              * low memory situation. Take a nap and see, if the
00421              * situation improved.
00422              */
00423             if ((rxbuf = NutHeapAlloc(dcb->dcb_rx_mru)) != 0) {
00424                 break;
00425             }
00426             NutSleep(1000);
00427         }
00428 
00429         /*
00430          * Signal the link driver that we are up.
00431          */
00432         ifn->if_send = AhdlcOutput;
00433         netdev->dev_ioctl(netdev, LCP_LOWERUP, 0);
00434 
00435         for (;;) {
00436             /*
00437              * If we are still connected to a network, fetch the next
00438              * character from the buffer.
00439              */
00440             while (dcb->dcb_rd_idx == dcb->dcb_rx_idx) {
00441                 if (dev->dev_icb == 0)
00442                     break;
00443                 // TODO: Check for idle timeout. 
00444                 if (NutEventWait(&dcb->dcb_rx_rdy, dcb->dcb_rtimeout)) {
00445                     continue;
00446                 }
00447             }
00448 
00449             /*
00450              * Leave loop if network interface is detached
00451              */
00452             if (dev->dev_icb == 0)
00453                 break;
00454 
00455             /*
00456              * If RAW mode is active, we are not allowing any data encapsulation
00457              * processing. So we just sleep for a while.
00458              */
00459             if (dcb->dcb_modeflags & UART_MF_RAWMODE) {
00460                 /*
00461                  * It is a must to sleep here, because if we just yield it could create
00462                  * too much processing in here and stall processing elsewhere. This gives
00463                  * opportunity to other threads to process incoming data from USART.
00464                  */
00465                 NutSleep(100);
00466                 continue;
00467             }
00468 
00469             /*
00470              * Read next character from input buffer
00471              */
00472             ch = dcb->dcb_rx_buf[dcb->dcb_rd_idx++];
00473 
00474             if (inframe) {
00475                 if (ch != AHDLC_FLAG) {
00476                     if (ch == AHDLC_ESCAPE) {
00477                         escaped = 1;
00478                         continue;
00479                     }
00480                     if (escaped) {
00481                         ch ^= AHDLC_TRANS;
00482                         escaped = 0;
00483                     }
00484 
00485                     /*
00486                      * Unless the peer lied to us about the negotiated MRU,
00487                      * we should never get a frame which is too long. If it
00488                      * happens, toss it away and grab the next incoming one.
00489                      */
00490                     if (rxcnt++ < dcb->dcb_rx_mru) {
00491                         /* Update calculated checksum and store character in buffer. */
00492                         tbx = (uint16_t) ((uint8_t) rxfcs ^ ch) << 1;
00493                         rxfcs >>= 8;
00494                         rxfcs ^= ((uint16_t) PRG_RDB(fcstab + tbx) << 8) | PRG_RDB(fcstab + tbx + 1);
00495                         *rxptr++ = ch;
00496                     } else
00497                         inframe = 0;
00498                     continue;
00499                 }
00500 
00501                 if (rxcnt > 6 && rxfcs == AHDLC_GOODFCS) {
00502                     /*
00503                        * If the frame checksum is valid, create a NETBUF
00504                        * and pass it to the network specific receive handler.
00505                      */
00506                     rxcnt -= 2;
00507                     if ((nb = NutNetBufAlloc(0, NBAF_DATALINK, rxcnt)) != 0) {
00508                         memcpy(nb->nb_dl.vp, rxbuf, rxcnt);
00509                         (*ifn->if_recv) (netdev, nb);
00510                     }
00511                 }
00512             }
00513 
00514             /*
00515              * If frame flag is received, resync frame processing
00516              */
00517             if (ch == AHDLC_FLAG) {
00518                 inframe = 1;
00519                 escaped = 0;
00520                 rxptr = rxbuf;
00521                 rxcnt = 0;
00522                 rxfcs = AHDLC_INITFCS;
00523             }
00524         }
00525 
00526 
00527         /* Signal the link driver that we are down. */
00528         netdev->dev_ioctl(netdev, LCP_LOWERDOWN, 0);
00529 
00530         /* Disconnected, clean up. */
00531         if (rxbuf) {
00532             NutHeapFree(rxbuf);
00533             rxbuf = 0;
00534         }
00535     }
00536 }
00537 
00538 /*
00539  * \param dev Indicates the UART device.
00540  *
00541  * \return 0 on success, -1 otherwise.
00542  */
00543 static int AhdlcAt91GetStatus(NUTDEVICE * dev, uint32_t * status)
00544 {
00545     AHDLCDCB *dcb = dev->dev_dcb;
00546     //SAAM   u_char us;
00547 
00548     *status = 0;
00549 
00550 #ifdef __AVR_ENHANCED__
00551     if (dev->dev_base) {
00552 #ifdef UART1_CTS_BIT
00553         if (bit_is_set(UART1_CTS_PIN, UART1_CTS_BIT))
00554             *status |= UART_CTSDISABLED;
00555         else
00556             *status |= UART_CTSENABLED;
00557 #endif
00558 #ifdef UART1_RTS_BIT
00559         if (bit_is_set(UART1_RTS_PORT, UART1_RTS_BIT))
00560             *status |= UART_RTSDISABLED;
00561         else
00562             *status |= UART_RTSENABLED;
00563 #endif
00564 #ifdef UART1_DTR_BIT
00565         if (bit_is_set(UART1_DTR_PORT, UART1_DTR_BIT))
00566             *status |= UART_DTRDISABLED;
00567         else
00568             *status |= UART_DTRENABLED;
00569 #endif
00570         us = inb(UCSR1A);
00571     } else
00572 #endif                          /* __AVR_ENHANCED__ */
00573     {
00574 #ifdef UART0_CTS_BIT
00575         if (bit_is_set(UART0_CTS_PIN, UART0_CTS_BIT))
00576             *status |= UART_CTSDISABLED;
00577         else
00578             *status |= UART_CTSENABLED;
00579 #endif
00580 #ifdef UART0_RTS_BIT
00581         if (bit_is_set(UART0_RTS_PORT, UART0_RTS_BIT))
00582             *status |= UART_RTSDISABLED;
00583         else
00584             *status |= UART_RTSENABLED;
00585 #endif
00586 #ifdef UART0_DTR_BIT
00587         if (bit_is_set(UART0_DTR_PORT, UART0_DTR_BIT))
00588             *status |= UART_DTRDISABLED;
00589         else
00590             *status |= UART_DTRENABLED;
00591 #endif
00592         //SAAM       us = inb(USR);
00593     }
00594 //SAAM    if (us & FE)
00595     //SAAM       *status |= UART_FRAMINGERROR;
00596     //SAAM  if (us & DOR)
00597     //SAAM      *status |= UART_OVERRUNERROR;
00598     if (dcb->dcb_tx_idx == dcb->dcb_wr_idx)
00599         *status |= UART_TXBUFFEREMPTY;
00600     if (dcb->dcb_rd_idx == dcb->dcb_rx_idx)
00601         *status |= UART_RXBUFFEREMPTY;
00602 
00603     return 0;
00604 }
00605 
00606 /*
00607  * \param dev Indicates the UART device.
00608  *
00609  * \return 0 on success, -1 otherwise.
00610  */
00611 static int AhdlcAt91SetStatus(NUTDEVICE * dev, uint32_t status)
00612 {
00613 
00614 #ifdef __AVR_ENHANCED__
00615     if (dev->dev_base) {
00616 #ifdef UART1_RTS_BIT
00617         if (status & UART_RTSDISABLED)
00618             sbi(UART1_RTS_PORT, UART1_RTS_BIT);
00619         else if (status & UART_RTSENABLED)
00620             cbi(UART1_RTS_PORT, UART1_RTS_BIT);
00621 #endif
00622 #ifdef UART1_DTR_BIT
00623         if (status & UART_DTRDISABLED)
00624             sbi(UART1_DTR_PORT, UART1_DTR_BIT);
00625         else if (status & UART_DTRENABLED)
00626             cbi(UART1_DTR_PORT, UART1_DTR_BIT);
00627 #endif
00628     } else
00629 #endif                          /* __AVR_ENHANCED__ */
00630     {
00631 #ifdef UART0_RTS_BIT
00632         if (status & UART_RTSDISABLED)
00633             sbi(UART0_RTS_PORT, UART0_RTS_BIT);
00634         else if (status & UART_RTSENABLED)
00635             cbi(UART0_RTS_PORT, UART0_RTS_BIT);
00636 #endif
00637 #ifdef UART0_DTR_BIT
00638         if (status & UART_DTRDISABLED)
00639             sbi(UART0_DTR_PORT, UART0_DTR_BIT);
00640         else if (status & UART_DTRENABLED)
00641             cbi(UART0_DTR_PORT, UART0_DTR_BIT);
00642 #endif
00643     }
00644     return 0;
00645 }
00646 
00647 /*
00648  * Carefully enable UART functions.
00649  */
00650 static void AhdlcAt91Enable(uint16_t base)
00651 {
00652 
00653     NutEnterCritical();
00654 
00655     outr(US1_RTOR, UART_RECEIVER_TIMEOUT);
00656     outr(USART1_BASE + PERIPH_PTCR_OFF, PDC_RXTEN);     // enable Rx DMA
00657     outr(US1_CR, US_TXEN | US_RXEN | US_STTTO); /* Enable UART receiver and transmitter. */
00658 
00659     /* Enable UART receiver interrupts. */
00660     outr(US1_IER, US_ENDRX | US_RXBUFF | US_TIMEOUT);
00661 
00662     NutIrqEnable(&SIG_UART);
00663 
00664     NutExitCritical();
00665 }
00666 
00667 
00668 /*
00669  * Carefully disable UART functions.
00670  */
00671 static void AhdlcAt91Disable(uint16_t base)
00672 {
00673 
00674     NutEnterCritical();
00675 
00676     NutIrqDisable(&SIG_UART);
00677 
00678     outr(US1_IDR, -1);
00679     outr(USART1_BASE + PERIPH_PTCR_OFF, PDC_RXTDIS);
00680 
00681     NutExitCritical();
00682     /*
00683        * Allow incoming or outgoing character to finish.
00684      */
00685     NutDelay(10);
00686 
00687     /*
00688        * Disable USART transmit and receive.
00689      */
00690     outr(US1_CR, US_RXDIS | US_TXDIS);
00691 }
00692 
00730 int AhdlcAt91IOCtl(NUTDEVICE * dev, int req, void *conf)
00731 {
00732     int rc = 0;
00733     AHDLCDCB *dcb;
00734     void **ppv = (void **) conf;
00735     uint32_t *lvp = (uint32_t *) conf;
00736     uint8_t bv;
00737     ureg_t cs;
00738 
00739     if (dev == 0) {
00740         dev = &devUsartAt910;
00741     }
00742 
00743     dcb = dev->dev_dcb;
00744 
00745     switch (req) {
00746 
00747     case UART_SETSPEED:
00748 
00749         AhdlcAt91Disable(dcb->dcb_base);
00750 #if defined(AT91_PLL_MAINCK)
00751         outr(USART1_BASE + US_BRGR_OFF, (At91GetMasterClock() / (8 * (*lvp)) + 1) / 2);
00752 #else
00753         outr(USART1_BASE + US_BRGR_OFF, (NutGetCpuClock() / (8 * (*lvp)) + 1) / 2);
00754 #endif
00755         AhdlcAt91Enable(dcb->dcb_base);
00756         break;
00757 
00758     case UART_GETSPEED:
00759         cs = inr(USART1_BASE + US_MR_OFF);
00760         uint32_t clk;
00761 #if defined(AT91_PLL_MAINCK)
00762         clk = At91GetMasterClock();
00763 #else
00764         clk = NutGetCpuClock();
00765 #endif
00766         if ((cs & US_CLKS) == US_CLKS_MCK8) {
00767             clk /= 8;
00768         } else if ((cs & US_CLKS) != US_CLKS_MCK) {
00769             clk = 0;
00770         }
00771         *lvp = (clk / (16UL * (inr(USART1_BASE + US_BRGR_OFF) & 0xFFFF)));
00772         break;
00773 
00774     case UART_GETSTATUS:
00775         AhdlcAt91GetStatus(dev, lvp);
00776         break;
00777     case UART_SETSTATUS:
00778         AhdlcAt91SetStatus(dev, *lvp);
00779         break;
00780 
00781     case UART_SETREADTIMEOUT:
00782         dcb->dcb_rtimeout = *lvp;
00783         break;
00784     case UART_GETREADTIMEOUT:
00785         *lvp = dcb->dcb_rtimeout;
00786         break;
00787 
00788     case UART_SETWRITETIMEOUT:
00789         dcb->dcb_wtimeout = *lvp;
00790         break;
00791     case UART_GETWRITETIMEOUT:
00792         *lvp = dcb->dcb_wtimeout;
00793         break;
00794 
00795     case UART_SETLOCALECHO:
00796         bv = (uint8_t) (*lvp);
00797         if (bv)
00798             dcb->dcb_modeflags |= UART_MF_LOCALECHO;
00799         else
00800             dcb->dcb_modeflags &= ~UART_MF_LOCALECHO;
00801         break;
00802     case UART_GETLOCALECHO:
00803         if (dcb->dcb_modeflags & UART_MF_LOCALECHO)
00804             *lvp = 1;
00805         else
00806             *lvp = 0;
00807         break;
00808 
00809     case UART_SETFLOWCONTROL:
00810         bv = (uint8_t) (*lvp);
00811         if (bv)
00812             dcb->dcb_modeflags |= UART_MF_LOCALECHO;
00813         else
00814             dcb->dcb_modeflags &= ~UART_MF_LOCALECHO;
00815         break;
00816     case UART_GETFLOWCONTROL:
00817         break;
00818 
00819     case UART_SETRAWMODE:
00820         bv = (uint8_t) (*lvp);
00821         if (bv)
00822             dcb->dcb_modeflags |= UART_MF_RAWMODE;
00823         else
00824             dcb->dcb_modeflags &= ~UART_MF_RAWMODE;
00825         break;
00826 
00827     case UART_GETRAWMODE:
00828         if (dcb->dcb_modeflags & UART_MF_RAWMODE)
00829             *lvp = 1;
00830         else
00831             *lvp = 0;
00832         break;
00833 
00834     case HDLC_SETIFNET:
00835         if (ppv && (*ppv != 0)) {
00836             dev->dev_icb = *ppv;
00837             dev->dev_type = IFTYP_NET;
00838             NutEventPost(&dcb->dcb_mf_evt);
00839         } else {
00840 
00841             dev->dev_type = IFTYP_CHAR;
00842 
00843             if (dev->dev_icb != 0) {
00844                 dev->dev_icb = 0;
00845 
00846                 /*
00847                  * Signal AHDLC Thread, so it can change it's state instantly
00848                  */
00849                 NutEventPost(&dcb->dcb_rx_rdy);
00850             }
00851         }
00852         break;
00853 
00854     case HDLC_GETIFNET:
00855         *ppv = dev->dev_icb;
00856         break;
00857 
00858     default:
00859         rc = -1;
00860         break;
00861     }
00862     return rc;
00863 }
00864 
00865 
00878 int AhdlcAt91Init(NUTDEVICE * dev)
00879 {
00880     int rc = 0;
00881     AHDLCDCB *dcb;
00882 //    u_long baudrate = 9600;
00883 
00884     /* Disable UART. */
00885     AhdlcAt91Disable(dev->dev_base);
00886 
00887     /* Initialize driver control block. */
00888     dcb = dev->dev_dcb;
00889     memset(dcb, 0, sizeof(AHDLCDCB));
00890     dcb->dcb_base = dev->dev_base;
00891     dcb->dcb_rx_buf = NutHeapAlloc(256);
00892     dcb->dcb_tx_buf = NutHeapAlloc(256);
00893     dcb->dcb_rx_mru = 1500;
00894     dcb->dcb_tx_mru = 1500;
00895     dcb->dcb_tx_accm = 0xFFFFFFFF;
00896 
00897 
00898     if (NutRegisterIrqHandler(&SIG_UART, At91UsartInterrupt, dcb)) {
00899         return -1;
00900     }
00901 
00902     outr(PMC_PCER, _BV(US1_ID));
00903 //      outr(PIOA_PDR, _BV(5) | _BV(6) | _BV(8) | _BV(9));
00904     outr(PIOA_PDR, US_GPIO_PINS);
00905 
00906     /* Reset UART. */
00907     outr(US1_CR, US_RSTRX | US_RSTTX | US_RXDIS | US_TXDIS);
00908     /* Disable all UART interrupts. */
00909     outr(US1_IDR, 0xFFFFFFFF);
00910     /* Clear UART counter registers. */
00911 #if defined (US_RCR_OFF)
00912     outr(US1_RCR, 0);
00913 #endif
00914 #if defined (US_TCR_OFF)
00915     outr(US1_TCR, 0);
00916 #endif
00917     /* Set UART baud rate generator register. */
00918 #if defined(AT91_PLL_MAINCK)
00919     outr(US1_BRGR, (At91GetMasterClock() / (8 * (115200)) + 1) / 2);
00920 #else
00921     outr(US1_BRGR, (NutGetCpuClock() / (8 * (115200)) + 1) / 2);
00922 #endif
00923     /* Set UART mode to 8 data bits, no parity and 1 stop bit, in hw handshake mode */
00924     outr(US1_MR, US_CHMODE_NORMAL | US_CHRL_8 | US_PAR_NO | US_NBSTOP_1 | US_MODE_HWHANDSHAKE);
00925 
00926     // setup DMA controller for receive
00927     outr(USART1_BASE + PERIPH_PTCR_OFF, PDC_RXTDIS);    // disable Rx DMA
00928     outr(USART1_BASE + PERIPH_RPR_OFF, (unsigned int) DMA_RxBuf0);
00929     outr(USART1_BASE + PERIPH_RCR_OFF, NUT_AHDLC_RECV_DMA_SIZE);
00930     outr(USART1_BASE + PERIPH_RNPR_OFF, 0);
00931     outr(USART1_BASE + PERIPH_RNCR_OFF, 0);
00932 
00933     /*
00934      * If we have been successful so far, start the HDLC receiver thread,
00935      * set the initial baudrate and enable the UART.
00936      */
00937     if (rc == 0 && NutThreadCreate("ahdlcrx", AhdlcRx, dev, 
00938         (NUT_THREAD_AHDLCRXSTACK * NUT_THREAD_STACK_MULT) + NUT_THREAD_STACK_ADD)) {
00939 //        AhdlcAvrIOCtl(dev, UART_SETSPEED, &baudrate);
00940         return 0;
00941     }
00942 
00943     /* We failed, clean up. */
00944     if (dcb->dcb_rx_buf)
00945         NutHeapFree((void *) dcb->dcb_rx_buf);
00946     if (dcb->dcb_tx_buf)
00947         NutHeapFree((void *) dcb->dcb_tx_buf);
00948 
00949     return -1;
00950 }
00951 
00952 
00953 
00954 
00981 int AhdlcAt91Read(NUTFILE * fp, void *buffer, int size)
00982 {
00983     int rc = 0;
00984     AHDLCDCB *dcb = fp->nf_dev->dev_dcb;
00985     uint8_t *cp = buffer;
00986 
00987     /*
00988      * Get characters from receive buffer.
00989      */
00990     if (buffer) {
00991         while (rc < size) {
00992             if (dcb->dcb_rd_idx != dcb->dcb_rx_idx) {
00993                 *cp++ = dcb->dcb_rx_buf[dcb->dcb_rd_idx++];
00994                 rc++;
00995             } else if (rc || NutEventWait(&dcb->dcb_rx_rdy, dcb->dcb_rtimeout))
00996                 break;
00997         }
00998     }
00999 
01000     /*
01001      * Call without data buffer discards receive buffer.
01002      */
01003     else
01004         dcb->dcb_rd_idx = dcb->dcb_rx_idx;
01005 
01006     return rc;
01007 }
01008 
01021 int AhdlcAt91Put(NUTDEVICE * dev, CONST void *buffer, int len, int pflg)
01022 {
01023     int rc = 0;
01024     AHDLCDCB *dcb = dev->dev_dcb;
01025     CONST uint8_t *cp = buffer;
01026 
01027     /*
01028      * Put characters in transmit buffer.
01029      */
01030     if (buffer) {
01031         while (rc < len) {
01032             if (SendRawByte(dcb, pflg ? PRG_RDB(cp) : *cp, 0))
01033                 break;
01034             cp++;
01035             rc++;
01036         }
01037     }
01038 
01039     /*
01040      * Call without data pointer starts transmission.
01041      */
01042     else {
01043 
01044         NutEnterCritical();
01045 
01046         outr(US1_IER, US_TXRDY);
01047 
01048         NutExitCritical();
01049     }
01050     return rc;
01051 }
01052 
01072 int AhdlcAt91Write(NUTFILE * fp, CONST void *buffer, int len)
01073 {
01074     return AhdlcAt91Put(fp->nf_dev, buffer, len, 0);
01075 }
01076 
01098 int AhdlcAt91Write_P(NUTFILE * fp, PGM_P buffer, int len)
01099 {
01100     return AhdlcAt91Put(fp->nf_dev, (CONST char *) buffer, len, 1);
01101 }
01102 
01119 NUTFILE *AhdlcAt91Open(NUTDEVICE * dev, CONST char *name, int mode, int acc)
01120 {
01121     NUTFILE *fp;
01122 
01123     if ((fp = NutHeapAlloc(sizeof(NUTFILE))) == 0)
01124         return NUTFILE_EOF;
01125 
01126     fp->nf_next = 0;
01127     fp->nf_dev = dev;
01128     fp->nf_fcb = 0;
01129 
01130     outr(US1_RTOR, UART_RECEIVER_TIMEOUT);
01131     outr(USART1_BASE + PERIPH_PTCR_OFF, PDC_RXTEN);     /* enable rx DMA */
01132     outr(US1_CR, US_TXEN | US_RXEN | US_STTTO); /* Enable UART receiver and transmitter. */
01133 
01134     /* Enable UART receiver and transmitter interrupts. */
01135     outr(US1_IER, US_ENDRX | US_RXBUFF | US_TIMEOUT);
01136 
01137     NutEnterCritical();
01138 
01139     NutIrqEnable(&SIG_UART);
01140 
01141     NutExitCritical();
01142 
01143     return fp;
01144 }
01145 
01159 int AhdlcAt91Close(NUTFILE * fp)
01160 {
01161     if (fp && fp != NUTFILE_EOF) {
01162         NutHeapFree(fp);
01163         return 0;
01164     }
01165     return -1;
01166 }
01167