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

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