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

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