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

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