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

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