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 = inp(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 = inp(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     uint8_t devnum;
00738     ureg_t cs;
00739 
00740     if (dev == 0) {
00741         dev = &devUsartAt910;
00742     }
00743 
00744     devnum = dev->dev_base;
00745     dcb = dev->dev_dcb;
00746 
00747     switch (req) {
00748 
00749     case UART_SETSPEED:
00750 
00751         AhdlcAt91Disable(dcb->dcb_base);
00752 #if defined(AT91_PLL_MAINCK)
00753         outr(USART1_BASE + US_BRGR_OFF, (At91GetMasterClock() / (8 * (*lvp)) + 1) / 2);
00754 #else
00755         outr(USART1_BASE + US_BRGR_OFF, (NutGetCpuClock() / (8 * (*lvp)) + 1) / 2);
00756 #endif
00757         AhdlcAt91Enable(dcb->dcb_base);
00758         break;
00759 
00760     case UART_GETSPEED:
00761         cs = inr(USART1_BASE + US_MR_OFF);
00762         uint32_t clk;
00763 #if defined(AT91_PLL_MAINCK)
00764         clk = At91GetMasterClock();
00765 #else
00766         clk = NutGetCpuClock();
00767 #endif
00768         if ((cs & US_CLKS) == US_CLKS_MCK8) {
00769             clk /= 8;
00770         } else if ((cs & US_CLKS) != US_CLKS_MCK) {
00771             clk = 0;
00772         }
00773         *lvp = (clk / (16UL * (inr(USART1_BASE + US_BRGR_OFF) & 0xFFFF)));
00774         break;
00775 
00776     case UART_GETSTATUS:
00777         AhdlcAt91GetStatus(dev, lvp);
00778         break;
00779     case UART_SETSTATUS:
00780         AhdlcAt91SetStatus(dev, *lvp);
00781         break;
00782 
00783     case UART_SETREADTIMEOUT:
00784         dcb->dcb_rtimeout = *lvp;
00785         break;
00786     case UART_GETREADTIMEOUT:
00787         *lvp = dcb->dcb_rtimeout;
00788         break;
00789 
00790     case UART_SETWRITETIMEOUT:
00791         dcb->dcb_wtimeout = *lvp;
00792         break;
00793     case UART_GETWRITETIMEOUT:
00794         *lvp = dcb->dcb_wtimeout;
00795         break;
00796 
00797     case UART_SETLOCALECHO:
00798         bv = (uint8_t) (*lvp);
00799         if (bv)
00800             dcb->dcb_modeflags |= UART_MF_LOCALECHO;
00801         else
00802             dcb->dcb_modeflags &= ~UART_MF_LOCALECHO;
00803         break;
00804     case UART_GETLOCALECHO:
00805         if (dcb->dcb_modeflags & UART_MF_LOCALECHO)
00806             *lvp = 1;
00807         else
00808             *lvp = 0;
00809         break;
00810 
00811     case UART_SETFLOWCONTROL:
00812         bv = (uint8_t) (*lvp);
00813         if (bv)
00814             dcb->dcb_modeflags |= UART_MF_LOCALECHO;
00815         else
00816             dcb->dcb_modeflags &= ~UART_MF_LOCALECHO;
00817         break;
00818     case UART_GETFLOWCONTROL:
00819         break;
00820 
00821     case UART_SETRAWMODE:
00822         bv = (uint8_t) (*lvp);
00823         if (bv)
00824             dcb->dcb_modeflags |= UART_MF_RAWMODE;
00825         else
00826             dcb->dcb_modeflags &= ~UART_MF_RAWMODE;
00827         break;
00828 
00829     case UART_GETRAWMODE:
00830         if (dcb->dcb_modeflags & UART_MF_RAWMODE)
00831             *lvp = 1;
00832         else
00833             *lvp = 0;
00834         break;
00835 
00836     case HDLC_SETIFNET:
00837         if (ppv && (*ppv != 0)) {
00838             dev->dev_icb = *ppv;
00839             dev->dev_type = IFTYP_NET;
00840             NutEventPost(&dcb->dcb_mf_evt);
00841         } else {
00842 
00843             dev->dev_type = IFTYP_CHAR;
00844 
00845             if (dev->dev_icb != 0) {
00846                 dev->dev_icb = 0;
00847 
00848                 /*
00849                  * Signal AHDLC Thread, so it can change it's state instantly
00850                  */
00851                 NutEventPost(&dcb->dcb_rx_rdy);
00852             }
00853         }
00854         break;
00855 
00856     case HDLC_GETIFNET:
00857         *ppv = dev->dev_icb;
00858         break;
00859 
00860     default:
00861         rc = -1;
00862         break;
00863     }
00864     return rc;
00865 }
00866 
00867 
00880 int AhdlcAt91Init(NUTDEVICE * dev)
00881 {
00882     int rc = 0;
00883     AHDLCDCB *dcb;
00884 //    u_long baudrate = 9600;
00885 
00886     /* Disable UART. */
00887     AhdlcAt91Disable(dev->dev_base);
00888 
00889     /* Initialize driver control block. */
00890     dcb = dev->dev_dcb;
00891     memset(dcb, 0, sizeof(AHDLCDCB));
00892     dcb->dcb_base = dev->dev_base;
00893     dcb->dcb_rx_buf = NutHeapAlloc(256);
00894     dcb->dcb_tx_buf = NutHeapAlloc(256);
00895     dcb->dcb_rx_mru = 1500;
00896     dcb->dcb_tx_mru = 1500;
00897     dcb->dcb_tx_accm = 0xFFFFFFFF;
00898 
00899 
00900     if (NutRegisterIrqHandler(&SIG_UART, At91UsartInterrupt, dcb)) {
00901         return -1;
00902     }
00903 
00904     outr(PMC_PCER, _BV(US1_ID));
00905 //      outr(PIOA_PDR, _BV(5) | _BV(6) | _BV(8) | _BV(9));
00906     outr(PIOA_PDR, US_GPIO_PINS);
00907 
00908     /* Reset UART. */
00909     outr(US1_CR, US_RSTRX | US_RSTTX | US_RXDIS | US_TXDIS);
00910     /* Disable all UART interrupts. */
00911     outr(US1_IDR, 0xFFFFFFFF);
00912     /* Clear UART counter registers. */
00913 #if defined (US_RCR_OFF)
00914     outr(US1_RCR, 0);
00915 #endif
00916 #if defined (US_TCR_OFF)
00917     outr(US1_TCR, 0);
00918 #endif
00919     /* Set UART baud rate generator register. */
00920 #if defined(AT91_PLL_MAINCK)
00921     outr(US1_BRGR, (At91GetMasterClock() / (8 * (115200)) + 1) / 2);
00922 #else
00923     outr(US1_BRGR, (NutGetCpuClock() / (8 * (115200)) + 1) / 2);
00924 #endif
00925     /* Set UART mode to 8 data bits, no parity and 1 stop bit, in hw handshake mode */
00926     outr(US1_MR, US_CHMODE_NORMAL | US_CHRL_8 | US_PAR_NO | US_NBSTOP_1 | US_MODE_HWHANDSHAKE);
00927 
00928     // setup DMA controller for receive
00929     outr(USART1_BASE + PERIPH_PTCR_OFF, PDC_RXTDIS);    // disable Rx DMA
00930     outr(USART1_BASE + PERIPH_RPR_OFF, (unsigned int) DMA_RxBuf0);
00931     outr(USART1_BASE + PERIPH_RCR_OFF, NUT_AHDLC_RECV_DMA_SIZE);
00932     outr(USART1_BASE + PERIPH_RNPR_OFF, 0);
00933     outr(USART1_BASE + PERIPH_RNCR_OFF, 0);
00934 
00935     /*
00936      * If we have been successful so far, start the HDLC receiver thread,
00937      * set the initial baudrate and enable the UART.
00938      */
00939     if (rc == 0 && NutThreadCreate("ahdlcrx", AhdlcRx, dev, 
00940         (NUT_THREAD_AHDLCRXSTACK * NUT_THREAD_STACK_MULT) + NUT_THREAD_STACK_ADD)) {
00941 //        AhdlcAvrIOCtl(dev, UART_SETSPEED, &baudrate);
00942         return 0;
00943     }
00944 
00945     /* We failed, clean up. */
00946     if (dcb->dcb_rx_buf)
00947         NutHeapFree((void *) dcb->dcb_rx_buf);
00948     if (dcb->dcb_tx_buf)
00949         NutHeapFree((void *) dcb->dcb_tx_buf);
00950 
00951     return -1;
00952 }
00953 
00954 
00955 
00956 
00983 int AhdlcAt91Read(NUTFILE * fp, void *buffer, int size)
00984 {
00985     int rc = 0;
00986     AHDLCDCB *dcb = fp->nf_dev->dev_dcb;
00987     uint8_t *cp = buffer;
00988 
00989     /*
00990      * Get characters from receive buffer.
00991      */
00992     if (buffer) {
00993         while (rc < size) {
00994             if (dcb->dcb_rd_idx != dcb->dcb_rx_idx) {
00995                 *cp++ = dcb->dcb_rx_buf[dcb->dcb_rd_idx++];
00996                 rc++;
00997             } else if (rc || NutEventWait(&dcb->dcb_rx_rdy, dcb->dcb_rtimeout))
00998                 break;
00999         }
01000     }
01001 
01002     /*
01003      * Call without data buffer discards receive buffer.
01004      */
01005     else
01006         dcb->dcb_rd_idx = dcb->dcb_rx_idx;
01007 
01008     return rc;
01009 }
01010 
01023 int AhdlcAt91Put(NUTDEVICE * dev, CONST void *buffer, int len, int pflg)
01024 {
01025     int rc = 0;
01026     AHDLCDCB *dcb = dev->dev_dcb;
01027     CONST uint8_t *cp = buffer;
01028 
01029     /*
01030      * Put characters in transmit buffer.
01031      */
01032     if (buffer) {
01033         while (rc < len) {
01034             if (SendRawByte(dcb, pflg ? PRG_RDB(cp) : *cp, 0))
01035                 break;
01036             cp++;
01037             rc++;
01038         }
01039     }
01040 
01041     /*
01042      * Call without data pointer starts transmission.
01043      */
01044     else {
01045 
01046         NutEnterCritical();
01047 
01048         outr(US1_IER, US_TXRDY);
01049 
01050         NutExitCritical();
01051     }
01052     return rc;
01053 }
01054 
01074 int AhdlcAt91Write(NUTFILE * fp, CONST void *buffer, int len)
01075 {
01076     return AhdlcAt91Put(fp->nf_dev, buffer, len, 0);
01077 }
01078 
01100 int AhdlcAt91Write_P(NUTFILE * fp, PGM_P buffer, int len)
01101 {
01102     return AhdlcAt91Put(fp->nf_dev, (CONST char *) buffer, len, 1);
01103 }
01104 
01121 NUTFILE *AhdlcAt91Open(NUTDEVICE * dev, CONST char *name, int mode, int acc)
01122 {
01123     NUTFILE *fp;
01124 
01125     if ((fp = NutHeapAlloc(sizeof(NUTFILE))) == 0)
01126         return NUTFILE_EOF;
01127 
01128     fp->nf_next = 0;
01129     fp->nf_dev = dev;
01130     fp->nf_fcb = 0;
01131 
01132     outr(US1_RTOR, UART_RECEIVER_TIMEOUT);
01133     outr(USART1_BASE + PERIPH_PTCR_OFF, PDC_RXTEN);     /* enable rx DMA */
01134     outr(US1_CR, US_TXEN | US_RXEN | US_STTTO); /* Enable UART receiver and transmitter. */
01135 
01136     /* Enable UART receiver and transmitter interrupts. */
01137     outr(US1_IER, US_ENDRX | US_RXBUFF | US_TIMEOUT);
01138 
01139     NutEnterCritical();
01140 
01141     NutIrqEnable(&SIG_UART);
01142 
01143     NutExitCritical();
01144 
01145     return fp;
01146 }
01147 
01161 int AhdlcAt91Close(NUTFILE * fp)
01162 {
01163     if (fp && fp != NUTFILE_EOF) {
01164         NutHeapFree(fp);
01165         return 0;
01166     }
01167     return -1;
01168 }
01169 

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