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

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