Nut/OS  4.10.3
API Reference
tlc16c550.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2001-2003 by Cyber Integration, LLC. All rights reserved.
00003  *
00004  * Redistribution and use in source and binary forms, with or without
00005  * modification, are permitted provided that the following conditions
00006  * are met:
00007  *
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the copyright holders nor the names of
00014  *    contributors may be used to endorse or promote products derived
00015  *    from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY CYBER INTEGRATION, LLC AND CONTRIBUTORS
00018  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00019  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00020  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CYBER
00021  * INTEGRATION, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00022  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00023  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00024  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00025  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00026  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00027  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00028  * SUCH DAMAGE.
00029  *
00030  *
00031  */
00032 
00033 /*
00034  * $Log$
00035  * Revision 1.4  2009/01/17 11:26:38  haraldkipp
00036  * Getting rid of two remaining BSD types in favor of stdint.
00037  * Replaced 'u_int' by 'unsinged int' and 'uptr_t' by 'uintptr_t'.
00038  *
00039  * Revision 1.3  2008/08/11 06:59:17  haraldkipp
00040  * BSD types replaced by stdint types (feature request #1282721).
00041  *
00042  * Revision 1.2  2007/05/24 07:29:10  haraldkipp
00043  * Update provided by Przemyslaw Rudy.
00044  *
00045  * Revision 1.1  2005/11/24 11:24:06  haraldkipp
00046  * Initial check-in.
00047  * Many thanks to William Basser for this code and also to Przemyslaw Rudy
00048  * for several enhancements.
00049  *
00050  */
00051 
00052 // system include files
00053 #include <string.h>
00054 #include <sys/atom.h>
00055 #include <sys/heap.h>
00056 #include <sys/event.h>
00057 #include <sys/timer.h>
00058 #include <sys/device.h>
00059 #include <dev/irqreg.h>
00060 #include <dev/tlc16c550.h>
00061 #include <fcntl.h>
00062 #include <stdio.h>
00063 
00064 /*
00065  * Not nice because stdio already defined them. But in order to save memory,
00066  * we do the whole buffering and including stdio here would be more weird.
00067  */
00068 #ifndef _IOFBF
00069 #define _IOFBF      0x00
00070 #define _IOLBF      0x01
00071 #define _IONBF      0x02
00072 #endif
00073 
00078 
00079 
00080 // define the register offset
00081 // define the UART Register offsets
00082 #define ACE_RBR_OFS     0
00083 #define ACE_THR_OFS     0
00084 #define ACE_DLL_OFS     0
00085 #define ACE_DLM_OFS     1
00086 #define ACE_IER_OFS     1
00087 #define ACE_FCR_OFS     2
00088 #define ACE_IIR_OFS     2
00089 #define ACE_LCR_OFS     3
00090 #define ACE_MCR_OFS     4
00091 #define ACE_LSR_OFS     5
00092 #define ACE_MSR_OFS     6
00093 #define ACE_SRC_OFS     7
00094 
00095 // define the interrupt enable masks
00096 #define IER_RDA_MSK     0x01    // receiver data avaialbe
00097 #define IER_THE_MSK     0x02    // transmit holding empty
00098 #define IER_LST_MSK     0x04    // line status
00099 #define IER_MST_MSK     0x08    // modem status
00100 
00101 // define the fifo control mask
00102 #define FCR_ENABLE     0x01     //fifo enable
00103 #define FCR_PURGE_I     0x02    //purge all data from input fifo
00104 #define FCR_PURGE_O     0x04    //purge all data from output fifo
00105 #define FCR_LEVEL_1    0x00     //receive trigger level 1
00106 #define FCR_LEVEL_4    0x40     //receive trigger level 4
00107 #define FCR_LEVEL_8    0x80     //receive trigger level 8
00108 #define FCR_LEVEL_14   0xc0     //receive trigger level 14
00109 
00110 // define the interrupt id masks
00111 #define IIR_MST_MSK     0x00    // modem status interrupt
00112 #define IIR_TXE_MSK     0x02    // transmit buffer empty
00113 #define IIR_RDA_MSK     0x04    // receive data available
00114 #define IIR_TDA_MSK     0x0c    // timeout receive data available
00115 #define IIR_LST_MSK     0x06    // line status interrupt
00116 #define IIR_NON_MSK     0x01    // no interrupt
00117 #define IIR_FIFO_MSK   0xc0     // mask to eliminate the fifo status
00118 
00119 // define the line control masks
00120 #define LCR_WS0_MSK     0x01
00121 #define LCR_WS1_MSK     0x02
00122 #define LCR_STB_MSK     0x04
00123 #define LCR_PEN_MSK     0x08
00124 #define LCR_PRE_MSK     0x10
00125 #define LCR_PRS_MSK     0x20
00126 #define LCR_BRK_MSK     0x40
00127 #define LCR_ENB_MSK     0x80
00128 
00129 // define the modem control masks
00130 #define MCR_DTR_MSK     0x01
00131 #define MCR_RTS_MSK     0x02
00132 #define MCR_GP1_MSK     0x04
00133 #define MCR_GP2_MSK     0x08
00134 #define MCR_LOP_MSK     0x10
00135 
00136 // define the line status masks
00137 #define LSR_RDR_MSK     0x01
00138 #define LSR_OVR_MSK     0x02
00139 #define LSR_PER_MSK     0x04
00140 #define LSR_FER_MSK     0x08
00141 #define LSR_BDT_MSK     0x10
00142 #define LSR_THE_MSK     0x20
00143 #define LSR_TXE_MSK     0x40
00144 #define LSR_EIF_MSK     0x80
00145 
00146 // define the modem status masks
00147 #define MSR_DCTS_MSK    0x01
00148 #define MSR_DDSR_MSK    0x02
00149 #define MSR_DRI_MSK     0x04
00150 #define MSR_DDCD_MSK    0x08
00151 #define MSR_CTS_MSK     0x10
00152 #define MSR_DSR_MSK     0x20
00153 #define MSR_RI_MSK              0x40
00154 #define MSR_DCD_MSK     0x80
00155 
00156 // define the irq structure
00157 typedef struct tagIRQDEFS {
00158     IRQ_HANDLER *pvIrq;
00159     volatile uint8_t *pnIrqMskPort;
00160     uint8_t nMask;
00161 } IRQDEFS;
00162 
00163 // define the interrupt handlers
00164 static CONST PROGMEM IRQDEFS atIrqDefs[] = {
00165     {&sig_INTERRUPT0, &EICRA, 0x00},
00166     {&sig_INTERRUPT1, &EICRA, 0x00},
00167     {&sig_INTERRUPT2, &EICRA, 0x00},
00168     {&sig_INTERRUPT3, &EICRA, 0x00},
00169     {&sig_INTERRUPT4, &EICRB, 0x00},
00170     {&sig_INTERRUPT5, &EICRB, 0x00},
00171     {&sig_INTERRUPT6, &EICRB, 0x00},
00172     {&sig_INTERRUPT7, &EICRB, 0x00}
00173 };
00174 
00175 // define the dcb's asigned to the interrupt to have more than one device on the same interrupt
00176 // NUT intrnal irq structure could be used instead but that would be a hack
00177 static NUTDEVICE *pIrqDev[8] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
00178 static uint8_t irqMask = 0;
00179 #ifdef ACE_HDX_LINE
00180 static unsigned int ByteOcrTime(NUTDEVICE * dev);
00181 static void AceTmr3Init(void);
00182 static void AceOutComp3AInt(void *arg);
00183 static void AceAddHdxTime(ACEDCB * dev);
00184 #endif
00185 
00186 /*
00187  * Handle AVR ACE interrupts
00188  */
00189 static void AceIrqHandler(void *arg)
00190 {
00191     NUTDEVICE *dev = (NUTDEVICE *) arg;
00192     IFSTREAM *ifs;
00193     ACEDCB *dcb;
00194     volatile uint8_t event;
00195     uint8_t maxData;
00196 
00197     do {
00198         ifs = dev->dev_icb;
00199         dcb = dev->dev_dcb;
00200 
00201         // get the interrupt source
00202         while (((event = *(uint8_t *) (dev->dev_base + ACE_IIR_OFS)) & ~IIR_FIFO_MSK) != IIR_NON_MSK) {
00203             switch (event & ~IIR_FIFO_MSK) {
00204             case IIR_RDA_MSK:  // receive data available
00205             case IIR_TDA_MSK:  // timeout receive data available
00206                 /* maxData can be avoided but it ensures that for slow system and fast uart we will not get stuck
00207                  * reading incomming data all the time.
00208                  */
00209                 maxData = (dcb->dcb_rfifo == 0) ? 1 : dcb->dcb_rfifo;
00210                 for (; (*(uint8_t *) (dev->dev_base + ACE_LSR_OFS) & LSR_RDR_MSK) && (maxData > 0); --maxData) {
00211                     // get the character and store it
00212                     ifs->if_rx_buf[ifs->if_rx_idx] = *(uint8_t *) (dev->dev_base + ACE_RBR_OFS);
00213                     /* if we have just received a first byte into the empty buffer */
00214                     if (ifs->if_rd_idx == ifs->if_rx_idx) {
00215                         NutEventPostFromIrq(&(dcb->dcb_rx_rdy));
00216                     }
00217                     /* Late increment fixes ICCAVR bug on volatile variables. */
00218                     ifs->if_rx_idx++;
00219                 }
00220                 break;
00221 
00222             case IIR_TXE_MSK:  // transmit buffer empty
00223                 dcb->dcb_wfifo = (event & IIR_FIFO_MSK) ? ACE_FIFO_SIZE : 1;
00224                 if (ifs->if_tx_idx != ifs->if_wr_idx) {
00225                     for (; (ifs->if_tx_idx != ifs->if_wr_idx) && (dcb->dcb_wfifo > 0); ++ifs->if_tx_idx) {
00226                         --dcb->dcb_wfifo;
00227                         // send a character
00228                         *(uint8_t *) (dev->dev_base + ACE_THR_OFS) = ifs->if_tx_buf[ifs->if_tx_idx];
00229                     }
00230                 } else {
00231 #ifdef ACE_HDX_LINE
00232                     if (dcb->dcb_modeflags & ACE_MF_HALFDUPLEX) {
00233                         AceAddHdxTime(dcb);
00234                     }
00235 #endif
00236                     ifs->if_tx_act = 0;
00237                     NutEventPostFromIrq(&(dcb->dcb_tx_rdy));
00238                 }
00239                 break;
00240 
00241             case IIR_MST_MSK:  // modem status interrupt
00242                 break;
00243 
00244             case IIR_LST_MSK:  // line status interrupt
00245                 break;
00246             }
00247         }
00248         /* get the next device assigned to this interrupt */
00249         dev = dcb->dev_next;
00250     } while (dev != NULL);
00251 
00252 }
00253 
00254 #ifdef ACE_HDX_LINE
00255 static unsigned int ByteOcrTime(NUTDEVICE * dev)
00256 {
00257     uint8_t bv;
00258     uint8_t tb = 14;             /* twice of 1 start 5 char min. 1 stop */
00259     unsigned int sv;
00260     uint32_t s, c;
00261 
00262     /* get speed */
00263     *(uint8_t *) (dev->dev_base + ACE_LCR_OFS) |= LCR_ENB_MSK;
00264     sv = *(uint8_t *) (dev->dev_base + ACE_DLL_OFS);
00265     sv |= *(uint8_t *) (dev->dev_base + ACE_DLM_OFS) << 8;
00266     *(uint8_t *) (dev->dev_base + ACE_LCR_OFS) &= (uint8_t) ~ LCR_ENB_MSK;
00267 
00268     bv = *(uint8_t *) (dev->dev_base + ACE_LCR_OFS);
00269 
00270     /* character length *2 */
00271     tb += (bv & (LCR_WS0_MSK | LCR_WS1_MSK)) << 1;
00272 
00273     /* stop bits *2 */
00274     if (bv & LCR_STB_MSK) {
00275         tb += 1 + !!(bv & (LCR_WS0_MSK | LCR_WS1_MSK));
00276     }
00277 
00278     /* parity bit *2 */
00279     tb += (!!(bv & LCR_PEN_MSK)) << 1;
00280 
00281     s = ACE_CLOCK * 8UL;
00282     s = s / (uint32_t) (sv);
00283 
00284     c = NutGetCpuClock();
00285     c = c * (uint32_t) tb;
00286 
00287     sv = ((unsigned int) (c / s) & 0x0000ffff) - 1;
00288 
00289     return sv;
00290 }
00291 #endif
00292 
00305 int AceInput(NUTDEVICE * dev)
00306 {
00307     int rc = 0;
00308     IFSTREAM *ifs = dev->dev_icb;
00309     ACEDCB *dcb = dev->dev_dcb;
00310 
00311     if (ifs->if_rd_idx == ifs->if_rx_idx) {
00312         rc = NutEventWaitNext(&(dcb->dcb_rx_rdy), dcb->dcb_rtimeout);
00313     }
00314     return rc;
00315 }
00316 
00331 int AceOutput(NUTDEVICE * dev)
00332 {
00333     IFSTREAM *ifs = dev->dev_icb;
00334     ACEDCB *dcb = dev->dev_dcb;
00335     volatile uint8_t tmp;
00336 
00337     if ((ifs->if_tx_act == 0) && (ifs->if_tx_idx != ifs->if_wr_idx)) {
00338         ifs->if_tx_act = 1;
00339         --dcb->dcb_wfifo;
00340         tmp = ifs->if_tx_idx;
00341         ++ifs->if_tx_idx;
00342 #ifdef ACE_HDX_LINE
00343         if (dcb->dcb_modeflags & ACE_MF_HALFDUPLEX) {
00344             ACE_HDX_TRANSMIT(dev->dev_base);
00345         }
00346 #endif
00347         // send a character
00348         *(uint8_t *) (dev->dev_base + ACE_THR_OFS) = ifs->if_tx_buf[tmp];
00349         // no need to enable an interrupt here as it should be enabled all the time
00350     }
00351 
00352     return 0;
00353 }
00354 
00365 int AceFlush(NUTDEVICE * dev)
00366 {
00367     IFSTREAM *ifs = dev->dev_icb;
00368     ACEDCB *dcb = dev->dev_dcb;
00369 
00370     /*
00371      * Start any pending output.
00372      */
00373     if (AceOutput(dev))
00374         return -1;
00375 
00376     /*
00377      * Wait until output buffer empty.
00378      */
00379     while (ifs->if_tx_idx != ifs->if_wr_idx) {
00380         NutEventWaitNext(&dcb->dcb_tx_rdy, 100);
00381     }
00382 
00383     return 0;
00384 }
00385 
00386 /*
00387  *
00388  * \param dev Indicates the ACE device.
00389  *
00390  * \return 0 on success, -1 otherwise.
00391  */
00392 static int AceGetStatus(NUTDEVICE * dev, uint32_t * status)
00393 {
00394     IFSTREAM *ifs = dev->dev_icb;
00395     uint8_t us;
00396 
00397     *status = 0;
00398     us = *(uint8_t *) (dev->dev_base + ACE_LSR_OFS);
00399     if (us & LSR_FER_MSK)
00400         *status |= ACE_FRAMINGERROR;
00401     if (us & LSR_OVR_MSK)
00402         *status |= ACE_OVERRUNERROR;
00403     if (ifs->if_tx_idx == ifs->if_wr_idx)
00404         *status |= ACE_TXBUFFEREMPTY;
00405     if (ifs->if_rd_idx == ifs->if_rx_idx)
00406         *status |= ACE_RXBUFFEREMPTY;
00407     return 0;
00408 }
00409 
00410 /*
00411  * Carefully enable ACE functions.
00412  */
00413 static void AceEnable(uint16_t base)
00414 {
00415     /*volatile uint8_t* pnBase = *(volatile uint8_t* )base; */
00416 
00417     /*
00418      * Enable ACE interrupts.
00419      */
00420     NutEnterCritical();
00421     *(uint8_t *) (base + ACE_IER_OFS) = IER_RDA_MSK | IER_THE_MSK;
00422     NutExitCritical();
00423 }
00424 
00425 /*
00426  * Carefully disable ACE functions.
00427  */
00428 static void AceDisable(uint16_t base)
00429 {
00430     /*volatile uint8_t* pnBase = *(volatile uint8_t* )base; */
00431 
00432     /*
00433      * Disable ACE interrupts.
00434      */
00435     NutEnterCritical();
00436     *(uint8_t *) (base + ACE_IER_OFS) &= (uint8_t) ~ (IER_RDA_MSK);
00437     NutExitCritical();
00438 
00439     /*
00440      * Allow incoming or outgoing character to finish.
00441      */
00442     NutDelay(10);
00443 }
00444 
00484 int AceIOCtl(NUTDEVICE * dev, int req, void *conf)
00485 {
00486     int rc = 0;
00487     ACEDCB *dcb;
00488     IFSTREAM *ifs;
00489     uint32_t *lvp = (uint32_t *) conf;
00490     uint32_t lv = *lvp;
00491     uint8_t bv = (uint8_t) lv;
00492     uint16_t sv;
00493     uint16_t devnum;
00494     uint8_t tv;
00495 
00496     if (dev == 0) {
00497         return -1;
00498     }
00499 
00500     devnum = dev->dev_base;
00501     dcb = dev->dev_dcb;
00502 
00503     switch (req) {
00504     case ACE_SETSPEED:
00505         AceDisable(devnum);
00506         sv = (uint16_t) (ACE_CLOCK / (lv * 16UL));
00507         *(uint8_t *) (dev->dev_base + ACE_LCR_OFS) |= LCR_ENB_MSK;
00508         *(uint8_t *) (dev->dev_base + ACE_DLL_OFS) = (uint8_t) (sv & 0xFF);
00509         *(uint8_t *) (dev->dev_base + ACE_DLM_OFS) = (uint8_t) (sv >> 8);
00510         *(uint8_t *) (dev->dev_base + ACE_LCR_OFS) &= (uint8_t) ~ LCR_ENB_MSK;
00511 #ifdef ACE_HDX_LINE
00512         dcb->hdxByteTime = ByteOcrTime(dev);
00513 #endif
00514         AceEnable(devnum);
00515         break;
00516 
00517     case ACE_GETSPEED:
00518         *(uint8_t *) (dev->dev_base + ACE_LCR_OFS) |= LCR_ENB_MSK;
00519         sv = *(uint8_t *) (dev->dev_base + ACE_DLL_OFS);
00520         sv |= *(uint8_t *) (dev->dev_base + ACE_DLM_OFS) << 8;
00521         *(uint8_t *) (dev->dev_base + ACE_LCR_OFS) &= (uint8_t) ~ LCR_ENB_MSK;
00522         *lvp = ACE_CLOCK / (16UL * (uint32_t) (sv));
00523         break;
00524 
00525     case ACE_SETDATABITS:
00526         AceDisable(devnum);
00527         if ((bv >= 5) && (bv <= 8)) {
00528             bv -= 5;
00529             tv = *(uint8_t *) (dev->dev_base + ACE_LCR_OFS);
00530             tv &= (uint8_t) ~ (LCR_WS0_MSK | LCR_WS1_MSK);
00531             tv |= (bv & (LCR_WS0_MSK | LCR_WS1_MSK));
00532             *(uint8_t *) (dev->dev_base + ACE_LCR_OFS) = tv;
00533 #ifdef ACE_HDX_LINE
00534             dcb->hdxByteTime = ByteOcrTime(dev);
00535 #endif
00536         }
00537         AceEnable(devnum);
00538         break;
00539 
00540     case ACE_GETDATABITS:
00541         *lvp = *(uint8_t *) (dev->dev_base + ACE_LCR_OFS) & (LCR_WS0_MSK | LCR_WS1_MSK);
00542         break;
00543 
00544     case ACE_SETPARITY:
00545         AceDisable(devnum);
00546         if (bv <= 4) {
00547             switch (bv) {
00548             case 1:            // odd parity
00549                 bv = LCR_PEN_MSK;
00550                 break;
00551 
00552             case 2:            // event parity
00553                 bv = LCR_PEN_MSK | LCR_PRE_MSK;
00554                 break;
00555 
00556             case 3:            // space
00557                 bv = LCR_PEN_MSK;
00558                 break;
00559 
00560             case 4:            // mark
00561                 bv = LCR_PEN_MSK | LCR_PRS_MSK;
00562 
00563             default:           // no parity
00564                 bv = 0;
00565                 break;
00566             }
00567 
00568             tv = *(uint8_t *) (dev->dev_base + ACE_LCR_OFS);
00569             tv &= (uint8_t) ~ (LCR_PEN_MSK | LCR_PRE_MSK | LCR_PRS_MSK);
00570             tv |= bv;
00571             *(uint8_t *) (dev->dev_base + ACE_LCR_OFS) = tv;
00572 #ifdef ACE_HDX_LINE
00573             dcb->hdxByteTime = ByteOcrTime(dev);
00574 #endif
00575         }
00576         AceEnable(devnum);
00577         break;
00578 
00579     case ACE_GETPARITY:
00580         tv = *(uint8_t *) (dev->dev_base + ACE_LCR_OFS) & (LCR_PEN_MSK | LCR_PRE_MSK | LCR_PRS_MSK);
00581         switch (tv) {
00582         case 0:
00583             *lvp = 0;           // no parity
00584             break;
00585 
00586         case LCR_PEN_MSK:
00587             *lvp = 1;           // odd parity
00588             break;
00589 
00590         case LCR_PEN_MSK | LCR_PRE_MSK:
00591             *lvp = 2;           // event parity
00592             break;
00593 
00594         case LCR_PEN_MSK | LCR_PRS_MSK:
00595             *lvp = 4;           // mark parity
00596             break;
00597         }
00598         break;
00599 
00600     case ACE_SETSTOPBITS:
00601         AceDisable(devnum);
00602         if (bv == 1 || bv == 2) {
00603             tv = *(uint8_t *) (dev->dev_base + ACE_LCR_OFS);
00604             tv &= (uint8_t) ~ (LCR_STB_MSK);
00605             tv |= (bv == 2) ? LCR_STB_MSK : 0;
00606             *(uint8_t *) (dev->dev_base + ACE_LCR_OFS) = tv;
00607 #ifdef ACE_HDX_LINE
00608             dcb->hdxByteTime = ByteOcrTime(dev);
00609 #endif
00610         }
00611         AceEnable(devnum);
00612         break;
00613 
00614     case ACE_GETSTOPBITS:
00615         tv = *(uint8_t *) (dev->dev_base + ACE_LCR_OFS);
00616         *lvp = (tv & LCR_STB_MSK) ? 2 : 1;
00617         break;
00618 
00619     case ACE_SETFIFO:
00620         AceDisable(devnum);
00621         dcb->dcb_wfifo = ACE_FIFO_SIZE;
00622         switch (bv) {
00623         case 1:
00624             tv = FCR_ENABLE | FCR_LEVEL_1 | FCR_PURGE_I | FCR_PURGE_O;
00625             break;
00626 
00627         case 4:
00628             tv = FCR_ENABLE | FCR_LEVEL_4 | FCR_PURGE_I | FCR_PURGE_O;
00629             break;
00630 
00631         case 8:
00632             tv = FCR_ENABLE | FCR_LEVEL_8 | FCR_PURGE_I | FCR_PURGE_O;
00633             break;
00634 
00635         case 14:
00636             tv = FCR_ENABLE | FCR_LEVEL_14 | FCR_PURGE_I | FCR_PURGE_O;
00637             break;
00638 
00639         default:
00640             bv = 0;
00641             tv = 0;
00642             dcb->dcb_wfifo = 1;
00643             break;
00644         }
00645         *(uint8_t *) (dev->dev_base + ACE_FCR_OFS) = tv;
00646         /* if enabling then must write the level after */
00647         *(uint8_t *) (dev->dev_base + ACE_FCR_OFS) = tv;
00648         dcb->dcb_rfifo = bv;
00649 
00650         /* must signal any active and waiting writer, discard pending data */
00651         ifs = dev->dev_icb;
00652 
00653         ifs->if_tx_act = 0;
00654         ifs->if_tx_idx = ifs->if_wr_idx;
00655         NutEventPostAsync(&(dcb->dcb_tx_rdy));
00656 
00657         AceEnable(devnum);
00658         break;
00659 
00660     case ACE_GETFIFO:
00661         *lvp = (uint32_t) (dcb->dcb_rfifo);
00662         break;
00663 
00664     case ACE_GETSTATUS:
00665         AceGetStatus(dev, lvp);
00666         break;
00667 
00668     case ACE_SETSTATUS:
00669         rc = -1;
00670         break;
00671 
00672     case ACE_SETREADTIMEOUT:
00673         dcb->dcb_rtimeout = lv;
00674         break;
00675     case ACE_GETREADTIMEOUT:
00676         *lvp = dcb->dcb_rtimeout;
00677         break;
00678 
00679     case ACE_SETWRITETIMEOUT:
00680         dcb->dcb_wtimeout = lv;
00681         break;
00682     case ACE_GETWRITETIMEOUT:
00683         *lvp = dcb->dcb_wtimeout;
00684         break;
00685 
00686     case ACE_SETLOCALECHO:
00687         if (bv)
00688             dcb->dcb_modeflags |= ACE_MF_LOCALECHO;
00689         else
00690             dcb->dcb_modeflags &= ~ACE_MF_LOCALECHO;
00691         break;
00692     case ACE_GETLOCALECHO:
00693         *lvp = (dcb->dcb_modeflags & ACE_MF_LOCALECHO) ? 1 : 0;
00694         break;
00695 
00696     case ACE_SETFLOWCONTROL:
00697 #ifdef ACE_HDX_LINE
00698         if (lv & ACE_MF_HALFDUPLEX) {
00699             /* next transmission will use HDX pin */
00700             dcb->dcb_modeflags |= ACE_MF_HALFDUPLEX;
00701         } else {
00702             dcb->dcb_modeflags &= ~ACE_MF_HALFDUPLEX;
00703         }
00704         dcb->hdxOcrTime = 0;
00705         /* switch HDX pin off */
00706         ACE_HDX_RECEIVE(dev->dev_base);
00707 #endif
00708         break;
00709 
00710     case ACE_GETFLOWCONTROL:
00711 #ifdef ACE_HDX_LINE
00712         *lvp = (uint32_t) (dcb->dcb_modeflags & ACE_MF_HALFDUPLEX);
00713 #endif
00714         break;
00715 
00716     case ACE_SETCOOKEDMODE:
00717         if (bv)
00718             dcb->dcb_modeflags |= ACE_MF_COOKEDMODE;
00719         else
00720             dcb->dcb_modeflags &= ~ACE_MF_COOKEDMODE;
00721         break;
00722     case ACE_GETCOOKEDMODE:
00723         *lvp = (dcb->dcb_modeflags & ACE_MF_COOKEDMODE) ? 1 : 0;
00724         break;
00725 
00726     default:
00727         rc = -1;
00728         break;
00729     }
00730     return rc;
00731 }
00732 
00743 int AceInit(NUTDEVICE * dev)
00744 {
00745     IFSTREAM *ifs;
00746     ACEDCB *dcb, *pFirstDcb;
00747     uint32_t baudrate = 9600;
00748     uint32_t databits = 8;
00749     uint32_t parity = 0;
00750     uint32_t stopbits = 1;
00751     IRQ_HANDLER *irq;
00752     uint8_t *pnPort;
00753     uint8_t nMask;
00754 #ifdef ACE_HDX_LINE
00755     uint32_t flowcontrol = 0;
00756 #endif
00757     /*
00758      * We only support character devices for on-chip ACEs.
00759      */
00760     if (dev->dev_type != IFTYP_STREAM) {
00761         return -1;
00762     }
00763 
00764     /*
00765      * Initialize interface control block.
00766      */
00767     ifs = dev->dev_icb;
00768     memset(ifs, 0, sizeof(IFSTREAM));
00769     ifs->if_input = AceInput;
00770     ifs->if_output = AceOutput;
00771     ifs->if_flush = AceFlush;
00772 
00773     /*
00774      * Initialize driver control block.
00775      */
00776     dcb = dev->dev_dcb;
00777     memset(dcb, 0, sizeof(ACEDCB));
00778     dcb->dcb_modeflags = ACE_MF_NOBUFFER;
00779     dcb->dcb_rfifo = 0;
00780     dcb->dcb_wfifo = 1;
00781     dcb->dev_next = NULL;
00782 #ifdef ACE_HDX_LINE
00783     dcb->hdxOcrTime = 0;
00784 #endif
00785 
00786     /*
00787      * Register interrupt handler.
00788      */
00789     if (dev->dev_base) {
00790         /* if any ACE is already assigned to this interrupt */
00791         if (pIrqDev[dev->dev_irq] != NULL) {
00792             pFirstDcb = pIrqDev[dev->dev_irq]->dev_dcb;
00793             dcb->dev_next = pFirstDcb->dev_next;
00794             pFirstDcb->dev_next = dev;
00795         } else {
00796 #ifdef ACE_HDX_LINE
00797             if (irqMask == 0) {
00798                 /* Register interrupt handlers */
00799                 if (NutRegisterIrqHandler(&sig_OUTPUT_COMPARE3A, AceOutComp3AInt, NULL)) {
00800                     return -1;
00801                 }
00802                 AceTmr3Init();
00803             }
00804 #endif
00805             // get the appropriate irq handler
00806             irq = (IRQ_HANDLER *) pgm_read_word(&(atIrqDefs[dev->dev_irq].pvIrq));
00807 
00808             if (NutRegisterIrqHandler(irq, AceIrqHandler, dev)) {
00809                 return -1;
00810             }
00811             // enable the interrupts
00812             pnPort = (uint8_t *) pgm_read_word(&(atIrqDefs[dev->dev_irq].pnIrqMskPort));
00813             nMask = pgm_read_byte(&(atIrqDefs[dev->dev_irq].nMask));
00814             *pnPort |= nMask;
00815             /* remember dcb of the recently initialized device */
00816             pIrqDev[dev->dev_irq] = dev;
00817             irqMask |= 0x01 << dev->dev_irq;
00818         }
00819     }
00820 
00821     /*
00822      * Set baudrate and handshake default. This will also
00823      * enable the ACE functions.
00824      */
00825     AceIOCtl(dev, ACE_SETSPEED, (void *) &baudrate);
00826     AceIOCtl(dev, ACE_SETDATABITS, (void *) &databits);
00827     AceIOCtl(dev, ACE_SETPARITY, (void *) &parity);
00828     AceIOCtl(dev, ACE_SETSTOPBITS, (void *) &stopbits);
00829 #ifdef ACE_HDX_LINE
00830     /* set HDX pin off by defalt */
00831     AceIOCtl(dev, ACE_SETFLOWCONTROL, (void *) &flowcontrol);
00832 #endif
00833     sbi(EIMSK, dev->dev_irq);   /* dev->dev_irq to IRQ_INTx map should be used for a clean implementation but it looks like an overhead */
00834 
00835     AceEnable(dev->dev_base);
00836 
00837     return 0;
00838 }
00839 
00843 int AceRead(NUTFILE * fp, void *buffer, int size)
00844 {
00845     int rc;
00846     NUTDEVICE *dev;
00847     IFSTREAM *ifs;
00848     ACEDCB *dcb;
00849     uint8_t elmode;
00850     uint8_t ch;
00851     uint8_t *cp = buffer;
00852 
00853     dev = fp->nf_dev;
00854     ifs = (IFSTREAM *) dev->dev_icb;
00855     dcb = dev->dev_dcb;
00856 
00857     if (dcb->dcb_modeflags & ACE_MF_COOKEDMODE)
00858         elmode = 1;
00859     else
00860         elmode = 0;
00861 
00862     /*
00863      * Call without data pointer discards receive buffer.
00864      */
00865     if (buffer == 0) {
00866         ifs->if_rd_idx = ifs->if_rx_idx;
00867         return 0;
00868     }
00869 
00870     /*
00871      * Get characters from receive buffer.
00872      */
00873     for (rc = 0; rc < size;) {
00874         /* if nothing has been received yet */
00875         if (ifs->if_rd_idx == ifs->if_rx_idx) {
00876             /* while incomming buffer is empty */
00877             while (ifs->if_rd_idx == ifs->if_rx_idx) {
00878                 /* wait (timeout) for incomming data */
00879                 if (AceInput(dev)) {
00880                     /* if a timeout */
00881                     return 0;
00882                 }
00883             }
00884         }
00885         ch = ifs->if_rx_buf[ifs->if_rd_idx++];
00886         if (elmode && (ch == '\r' || ch == '\n')) {
00887             if ((ifs->if_last_eol == 0) || (ifs->if_last_eol == ch)) {
00888                 ifs->if_last_eol = ch;
00889                 *cp++ = '\n';
00890                 rc++;
00891             }
00892         } else {
00893             ifs->if_last_eol = 0;
00894             *cp++ = ch;
00895             rc++;
00896         }
00897     }
00898     return rc;
00899 }
00900 
00904 int AcePut(NUTDEVICE * dev, CONST void *buffer, int len, int pflg)
00905 {
00906     int rc;
00907     IFSTREAM *ifs;
00908     ACEDCB *dcb;
00909     CONST uint8_t *cp;
00910     uint8_t lbmode;
00911     uint8_t elmode;
00912     uint8_t ch;
00913 
00914     ifs = dev->dev_icb;
00915     dcb = dev->dev_dcb;
00916 
00917     if (dcb->dcb_modeflags & ACE_MF_LINEBUFFER)
00918         lbmode = 1;
00919     else
00920         lbmode = 0;
00921 
00922     if (dcb->dcb_modeflags & ACE_MF_COOKEDMODE)
00923         elmode = 1;
00924     else
00925         elmode = 0;
00926 
00927     /*
00928      * Call without data pointer starts transmission.
00929      */
00930     if (buffer == 0) {
00931         rc = AceFlush(dev);
00932         return rc;
00933     }
00934 
00935     /*
00936      * Put characters in transmit buffer.
00937      */
00938     cp = buffer;
00939     for (rc = 0; rc < len;) {
00940         if ((uint8_t) (ifs->if_wr_idx + 1) == ifs->if_tx_idx) {
00941             if (AceFlush(dev)) {
00942                 return -1;
00943             }
00944         }
00945         ch = pflg ? PRG_RDB(cp) : *cp;
00946         if (elmode == 1 && ch == '\n') {
00947             elmode = 2;
00948             if (lbmode == 1)
00949                 lbmode = 2;
00950             ch = '\r';
00951         } else {
00952             if (elmode == 2)
00953                 elmode = 1;
00954             cp++;
00955             rc++;
00956         }
00957         ifs->if_tx_buf[ifs->if_wr_idx++] = ch;
00958     }
00959 
00960     if (lbmode > 1 || (dcb->dcb_modeflags & ACE_MF_NOBUFFER) != 0) {
00961         if (AceFlush(dev))
00962             rc = -1;
00963     }
00964     return rc;
00965 }
00966 
00967 int AceWrite(NUTFILE * fp, CONST void *buffer, int len)
00968 {
00969     return AcePut(fp->nf_dev, buffer, len, 0);
00970 }
00971 
00972 int AceWrite_P(NUTFILE * fp, PGM_P buffer, int len)
00973 {
00974     return AcePut(fp->nf_dev, (CONST char *) buffer, len, 1);
00975 }
00976 
00977 
00981 NUTFILE *AceOpen(NUTDEVICE * dev, CONST char *name, int mode, int acc)
00982 {
00983     NUTFILE *fp = NutHeapAlloc(sizeof(NUTFILE));
00984     ACEDCB *dcb;
00985 
00986     if (fp == 0)
00987         return NUTFILE_EOF;
00988 
00989     dcb = dev->dev_dcb;
00990     if (mode & _O_BINARY)
00991         dcb->dcb_modeflags &= ~ACE_MF_COOKEDMODE;
00992     else
00993         dcb->dcb_modeflags |= ACE_MF_COOKEDMODE;
00994 
00995     fp->nf_next = 0;
00996     fp->nf_dev = dev;
00997     fp->nf_fcb = 0;
00998 
00999     return fp;
01000 }
01001 
01005 int AceClose(NUTFILE * fp)
01006 {
01007     NutHeapFree(fp);
01008 
01009     return 0;
01010 }
01011 
01015 long AceSize(NUTFILE * fp)
01016 {
01017     NUTDEVICE *dev;
01018     IFSTREAM *ifs;
01019 
01020     dev = fp->nf_dev;
01021     ifs = (IFSTREAM *) dev->dev_icb;
01022     return ((uint8_t) (ifs->if_rx_idx - ifs->if_rd_idx));
01023 }
01024 
01025 #ifdef ACE_HDX_LINE
01026 static void AceTmr3Init(void)
01027 {
01028     /* TMR3 also runs in normal mode */
01029     TCCR3A &= ~(_BV(COM3A1) | _BV(COM3A0) | _BV(WGM31) | _BV(WGM30));   /* normal mode */
01030 
01031     TCCR3B &= ~(_BV(WGM33) | _BV(WGM32) | _BV(CS32) | _BV(CS31) | _BV(CS30));
01032     TCCR3B |= _BV(CS31) | _BV(CS30);    /* f/64 (155200Hz - 1.75Hz) */
01033 
01034     /* TMR3 output compare A match interrupt disable */
01035     ETIMSK &= ~_BV(OCIE3A);
01036 }
01037 
01038 static void AceOutComp3AInt(void *arg)
01039 {
01040     NUTDEVICE *dev;
01041     ACEDCB *dcb;
01042     int i;
01043     unsigned int nextOcr = 0xffff, ocr;
01044     unsigned int timerOcrDiff;
01045 
01046     /* TMR3 stop counting */
01047     TCCR3B &= ~(_BV(CS31) | _BV(CS30));
01048 
01049     timerOcrDiff = (unsigned int /* modulo max */ )((unsigned int /* modulo max */ )TCNT3 - (unsigned int /* modulo max */ )OCR3A);
01050 
01051     /* Due to interrupt nesting and as TL interrupts are higher priority - disable them.
01052      * This routine cannot be interrupted by a cal to the AceAddHdxTime()
01053      */
01054     EIMSK &= ~irqMask;
01055 
01056     for (i = 0; i < 8; ++i) {
01057         for (dev = pIrqDev[i]; dev != NULL; dev = dcb->dev_next) {
01058             dcb = dev->dev_dcb;
01059             /* only if enabled */
01060             if (dcb->hdxOcrTime != 0) {
01061                 if ((unsigned int /* modulo max */ )(dcb->hdxOcrTime - (unsigned int /* modulo max */ )OCR3A) <= timerOcrDiff) {
01062                     dcb->hdxOcrTime = 0;
01063                     ACE_HDX_RECEIVE(dev->dev_base);
01064                 } else {
01065                     ocr = (unsigned int /* modulo max */ )(dcb->hdxOcrTime - (unsigned int /* modulo max */ )TCNT3);
01066                     if (ocr < nextOcr) {
01067                         nextOcr = ocr;
01068                     }
01069                 }
01070             }
01071         }
01072     }
01073 
01074     if (nextOcr == 0xffff) {
01075         /* TMR3 output compare A match interrupt disable */
01076         ETIMSK &= ~_BV(OCIE3A);
01077     } else {
01078         OCR3A = nextOcr;
01079         /* start timer */
01080         TCCR3B |= _BV(CS31) | _BV(CS30);        /* f/64 (155200Hz - 1.75Hz) */
01081     }
01082 
01083     /* Re-enable TL interrupt. */
01084     EIMSK |= irqMask;
01085 }
01086 
01087 static void AceAddHdxTime(ACEDCB * dcb)
01088 {
01089     /* TMR3 stop counting */
01090     TCCR3B &= ~(_BV(CS31) | _BV(CS30));
01091 
01092     /* if disabled */
01093     if ((ETIMSK & _BV(OCIE3A)) == 0) {
01094         /* initialize */
01095         OCR3A = 0;
01096         TCNT3 = 1;
01097     }
01098 
01099     /* set offset from current counter value */
01100     dcb->hdxOcrTime = (unsigned int /* modulo max */ )((unsigned int /* modulo max */ )TCNT3 + dcb->hdxByteTime);
01101 
01102     if (dcb->hdxOcrTime == 0) {
01103         dcb->hdxOcrTime = 1;    /* 0 means disabled, one bit delay is not a problem as there is interrupt latency anyway */
01104     }
01105 
01106     if (dcb->hdxByteTime < (unsigned int /* modulo max */ )((unsigned int /* modulo max */ )OCR3A - (unsigned int /* modulo max */ )TCNT3)) {
01107         OCR3A = dcb->hdxOcrTime;
01108     }
01109     /* TMR3 output compare A match interrupt enable */
01110     ETIMSK |= _BV(OCIE3A);
01111 
01112     /* start timer */
01113     TCCR3B |= _BV(CS31) | _BV(CS30);    /* f/64 (155200Hz - 1.75Hz) */
01114 }
01115 #endif
01116