Nut/OS  4.10.3
API Reference
genchar.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2006 by egnite Software GmbH. 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 EGNITE SOFTWARE GMBH 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 EGNITE
00021  * SOFTWARE GMBH 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  * For additional information see http://www.ethernut.de/
00031  *
00032  */
00033 
00051 #include <cfg/os.h>
00052 #include <stdlib.h>
00053 #include <string.h>
00054 #include <sys/file.h>
00055 #include <sys/event.h>
00056 #include <sys/timer.h>
00057 #include <dev/irqreg.h>
00058 #include <dev/genchar.h>
00059 
00064 
00065 /* Sample hardware status port. */
00066 #ifndef GENDEV_SPORT
00067 #define GENDEV_SPORT    0x100
00068 #endif
00069 
00070 /* Sample hardware data port. */
00071 #ifndef GENDEV_DPORT
00072 #define GENDEV_DPORT    0x104
00073 #endif
00074 
00075 /* Sample hardware interrupt. */
00076 #ifndef GENDEV_SIGNAL
00077 #define GENDEV_SIGNAL   sig_INTERRUPT1
00078 #endif
00079 
00083 typedef struct {
00084     HANDLE dcb_rrdy;        
00085     volatile int dcb_rcnt;  
00086     uint8_t dcb_rbuff[16];   
00087     uint32_t dcb_rtimeout;    
00088     HANDLE dcb_trdy;        
00089     int    dcb_tlen;        
00090     volatile int dcb_tcnt;  
00091     uint8_t dcb_tbuff[16];   
00092     uint32_t dcb_ttimeout;    
00093 } DEVDCB;
00094 
00095 static DEVDCB devdcb;
00096 
00102 static void GenCharInterrupt(void *arg)
00103 {
00104     NUTDEVICE *dev = (NUTDEVICE *)arg;
00105     DEVDCB *dcb = dev->dev_dcb;
00106     uint8_t st = inr(GENDEV_SPORT);
00107 
00108     /* Receive interrupt. */
00109     if (st) {
00110         /* Avoid buffer overflow. */
00111         if (dcb->dcb_rcnt < sizeof(dcb->dcb_rbuff)) {
00112             /* Get byte from device and increment receive counter. */
00113             dcb->dcb_rbuff[dcb->dcb_rcnt] = inr(GENDEV_DPORT);
00114             dcb->dcb_rcnt++;
00115         }
00116         /* Send event on first character. */
00117         if (dcb->dcb_rcnt == 1) {
00118             NutEventPostFromIrq(&dcb->dcb_rrdy);
00119         }
00120     }
00121 
00122     /* Transmit interrupt. */
00123     else {
00124         if (dcb->dcb_tcnt < dcb->dcb_tlen) {
00125             /* Send byte to device and increment transmit counter. */
00126             outr(GENDEV_DPORT, dcb->dcb_tbuff[dcb->dcb_tcnt]);
00127             dcb->dcb_tcnt++;
00128         }
00129         /* Transmit buffer empty, send event. */
00130         else {
00131             NutEventPostFromIrq(&dcb->dcb_trdy);
00132             /* Optionally disable further transmit interrupts. */
00133         }
00134     }
00135 }
00136 
00149 static int GenCharIOCtl(NUTDEVICE * dev, int req, void *conf)
00150 {
00151     int rc = 0;
00152     DEVDCB *dcb = dev->dev_dcb;
00153     uint32_t *lvp = (uint32_t *) conf;
00154 
00155     switch (req) {
00156     case DEV_SETREADTIMEOUT:
00157         /* Set read timeout. */
00158         dcb->dcb_rtimeout = *lvp;
00159         break;
00160     case DEV_GETREADTIMEOUT:
00161         /* Query read timeout. */
00162         *lvp = dcb->dcb_rtimeout;
00163         break;
00164 
00165     case DEV_SETWRITETIMEOUT:
00166         /* Set write timeout. */
00167         dcb->dcb_ttimeout = *lvp;
00168         break;
00169     case DEV_GETWRITETIMEOUT:
00170         /* Query write timeout. */
00171         *lvp = dcb->dcb_ttimeout;
00172         break;
00173 
00174         /* Add attional ioctl functions here. */
00175 
00176     default:
00177         /* Unknown function. */
00178         rc = -1;
00179         break;
00180     }
00181     return rc;
00182 }
00183 
00194 static int GenCharInit(NUTDEVICE * dev)
00195 {
00196     /* Add hardware initialization here. */
00197 
00198     /* Register interrupt handler, if required. */
00199     if (NutRegisterIrqHandler(&GENDEV_SIGNAL, GenCharInterrupt, dev)) {
00200         return -1;
00201     }
00202     /* Set interrupt mode and enable interrupts. */
00203     NutIrqSetMode(&GENDEV_SIGNAL, NUT_IRQMODE_LOWLEVEL);
00204     NutIrqEnable(&GENDEV_SIGNAL);
00205 
00206     return 0;
00207 }
00208 
00230 static int GenCharRead(NUTFILE * fp, void *buffer, int size)
00231 {
00232     int rc;
00233     int i;
00234     NUTDEVICE *dev = fp->nf_dev;
00235     DEVDCB *dcb = dev->dev_dcb;
00236 
00237     /* Call without data pointer discards receive buffer. */
00238     if (buffer == 0) {
00239         /* Atomic access to the receive counter. */
00240         NutIrqDisable(&GENDEV_SIGNAL);
00241         dcb->dcb_rcnt = 0;
00242         NutIrqEnable(&GENDEV_SIGNAL);
00243 
00244         return 0;
00245     }
00246 
00247     /*
00248      * Wait until at least one character is buffered or until a read
00249      * timeout occured.
00250      */
00251     for (;;) {
00252         /* Atomic access to the receive counter. */
00253         NutIrqDisable(&GENDEV_SIGNAL);
00254         rc = dcb->dcb_rcnt;
00255         NutIrqEnable(&GENDEV_SIGNAL);
00256         if (rc) {
00257             break;
00258         }
00259 
00260         if (NutEventWait(&dcb->dcb_rrdy, dcb->dcb_rtimeout)) {
00261             return 0; /* Timeout. */
00262         }
00263     }
00264 
00265     if (rc > size) {
00266         rc = size;
00267     }
00268 
00269     if (rc) {
00270         memcpy(buffer, dcb->dcb_rbuff, rc);
00271         /* 
00272          * This sample driver simply moves remaining bytes to the front 
00273          * of the buffer. A more sophisticated driver may use a circular 
00274          * buffer.
00275          */
00276         NutIrqDisable(&GENDEV_SIGNAL);
00277         dcb->dcb_rcnt -= rc;
00278         for (i = 0; i < dcb->dcb_rcnt; i++) {
00279             dcb->dcb_rbuff[i] = dcb->dcb_rbuff[rc + i];
00280         }
00281         NutIrqEnable(&GENDEV_SIGNAL);
00282     }
00283     return rc;
00284 }
00285 
00305 static int GenCharWrite(NUTFILE * fp, CONST void *buffer, int len)
00306 {
00307     int rc = 0;
00308     int cnt;
00309     int pend;
00310     CONST char *cp = buffer;
00311     NUTDEVICE *dev = fp->nf_dev;
00312     DEVDCB *dcb = dev->dev_dcb;
00313 
00314     while (rc < len) {
00315 
00316         /*
00317          * This sample driver waits on each output until all characters 
00318          * had been tranmitted. A more sophisticated driver may add
00319          * new characters as soon as there is room left in the tranmit
00320          * buffer.
00321          */
00322         for (;;) {
00323             /* Atomic access to the transmit counter. */
00324             NutIrqDisable(&GENDEV_SIGNAL);
00325             pend = dcb->dcb_tlen - dcb->dcb_tcnt;
00326             NutIrqEnable(&GENDEV_SIGNAL);
00327             
00328             if (pend == 0) {
00329                 break; /* All characters tranmitted. */
00330             }
00331             if (NutEventWait(&dcb->dcb_trdy, dcb->dcb_ttimeout)) {
00332                 return rc; /* Timeout. */
00333             }
00334         }
00335 
00336         /* Call without data pointer flushes the buffer. */
00337         if (buffer == 0) {
00338             return 0;
00339         }
00340 
00341         /* Determine the number of bytes left to transmit. */
00342         cnt = len - rc;
00343         if (cnt > sizeof(dcb->dcb_tbuff)) {
00344             cnt = sizeof(dcb->dcb_tbuff);
00345         }
00346 
00347         /* Fill the tranmit buffer. */
00348         NutIrqDisable(&GENDEV_SIGNAL);
00349         dcb->dcb_tcnt = cnt;
00350         memcpy(dcb->dcb_tbuff, cp + rc, cnt);
00351         /* Add code here to enable tranmit interrupts. */
00352         NutIrqEnable(&GENDEV_SIGNAL);
00353         rc += cnt;
00354     }
00355     return rc;
00356 }
00357 
00358 #ifdef __HARVARD_ARCH__
00359 
00380 int GenCharWrite_P(NUTFILE * fp, PGM_P buffer, int len)
00381 {
00382     /* Our sample driver doesn't support this. */
00383     return -1;
00384 }
00385 #endif
00386 
00404 static NUTFILE *GenCharOpen(NUTDEVICE * dev, CONST char *name, int mode, int acc)
00405 {
00406     NUTFILE *fp = (NUTFILE *) (dev->dev_dcb);
00407 
00408     if ((fp = malloc(sizeof(NUTFILE))) == 0) {
00409         return NUTFILE_EOF; /* No memory. */
00410     }
00411 
00412     fp->nf_next = 0;
00413     fp->nf_dev = dev;
00414     fp->nf_fcb = 0;
00415 
00416     return fp;
00417 }
00418 
00430 static int GenCharClose(NUTFILE * fp)
00431 {
00432     /* We may optionally flush our output and discard our input buffers. */
00433 
00434     /* Release all resources which we allocated in the open function. */
00435     if (fp) {
00436         free(fp);
00437     }
00438     return 0;
00439 }
00440 
00452 long GenCharSize (NUTFILE *fp)
00453 {
00454     long rc;
00455     NUTDEVICE *dev = fp->nf_dev;
00456     DEVDCB *dcb = dev->dev_dcb;
00457 
00458     /* Atomic access to the receive buffer counter. */
00459     NutIrqDisable(&GENDEV_SIGNAL);
00460     rc = dcb->dcb_rcnt;
00461     NutIrqEnable(&GENDEV_SIGNAL);
00462 
00463     return rc;
00464 }
00465 
00469 NUTDEVICE devGenChar = {
00475     0,
00476 
00486     {'g', 'e', 'n', 'c', 'h', 'a', 'r', 0, 0},
00487 
00503     IFTYP_CHAR,
00504 
00515     0,
00516 
00527     0,
00528 
00540     0,
00541 
00551     &devdcb,
00552 
00559     GenCharInit,
00560 
00566     GenCharIOCtl,
00567 
00572     GenCharRead,
00573 
00578     GenCharWrite,
00579 
00580 #ifdef __HARVARD_ARCH__
00581 
00587     GenCharWrite_P,
00588 #endif
00589 
00593     GenCharOpen,
00594 
00598     GenCharClose,
00599 
00608     GenCharSize
00609 };
00610 
00611