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 
00048 #include <cfg/os.h>
00049 #include <stdlib.h>
00050 #include <string.h>
00051 #include <sys/file.h>
00052 #include <sys/event.h>
00053 #include <sys/timer.h>
00054 #include <dev/irqreg.h>
00055 #include <dev/genchar.h>
00056 
00061 
00062 /* Sample hardware status port. */
00063 #ifndef GENDEV_SPORT
00064 #define GENDEV_SPORT    0x100
00065 #endif
00066 
00067 /* Sample hardware data port. */
00068 #ifndef GENDEV_DPORT
00069 #define GENDEV_DPORT    0x104
00070 #endif
00071 
00072 /* Sample hardware interrupt. */
00073 #ifndef GENDEV_SIGNAL
00074 #define GENDEV_SIGNAL   sig_INTERRUPT1
00075 #endif
00076 
00080 typedef struct {
00081     HANDLE dcb_rrdy;        
00082     volatile int dcb_rcnt;  
00083     u_char dcb_rbuff[16];   
00084     u_long dcb_rtimeout;    
00085     HANDLE dcb_trdy;        
00086     int    dcb_tlen;        
00087     volatile int dcb_tcnt;  
00088     u_char dcb_tbuff[16];   
00089     u_long dcb_ttimeout;    
00090 } DEVDCB;
00091 
00092 static DEVDCB devdcb;
00093 
00099 static void GenCharInterrupt(void *arg)
00100 {
00101     NUTDEVICE *dev = (NUTDEVICE *)arg;
00102     DEVDCB *dcb = dev->dev_dcb;
00103     u_char st = inr(GENDEV_SPORT);
00104 
00105     /* Receive interrupt. */
00106     if (st) {
00107         /* Avoid buffer overflow. */
00108         if (dcb->dcb_rcnt < sizeof(dcb->dcb_rbuff)) {
00109             /* Get byte from device and increment receive counter. */
00110             dcb->dcb_rbuff[dcb->dcb_rcnt] = inr(GENDEV_DPORT);
00111             dcb->dcb_rcnt++;
00112         }
00113         /* Send event on first character. */
00114         if (dcb->dcb_rcnt == 1) {
00115             NutEventPostFromIrq(&dcb->dcb_rrdy);
00116         }
00117     }
00118 
00119     /* Transmit interrupt. */
00120     else {
00121         if (dcb->dcb_tcnt < dcb->dcb_tlen) {
00122             /* Send byte to device and increment transmit counter. */
00123             outr(GENDEV_DPORT, dcb->dcb_tbuff[dcb->dcb_tcnt]);
00124             dcb->dcb_tcnt++;
00125         }
00126         /* Transmit buffer empty, send event. */
00127         else {
00128             NutEventPostFromIrq(&dcb->dcb_trdy);
00129             /* Optionally disable further transmit interrupts. */
00130         }
00131     }
00132 }
00133 
00146 static int GenCharIOCtl(NUTDEVICE * dev, int req, void *conf)
00147 {
00148     int rc = 0;
00149     DEVDCB *dcb = dev->dev_dcb;
00150     u_long *lvp = (u_long *) conf;
00151 
00152     switch (req) {
00153     case DEV_SETREADTIMEOUT:
00154         /* Set read timeout. */
00155         dcb->dcb_rtimeout = *lvp;
00156         break;
00157     case DEV_GETREADTIMEOUT:
00158         /* Query read timeout. */
00159         *lvp = dcb->dcb_rtimeout;
00160         break;
00161 
00162     case DEV_SETWRITETIMEOUT:
00163         /* Set write timeout. */
00164         dcb->dcb_ttimeout = *lvp;
00165         break;
00166     case DEV_GETWRITETIMEOUT:
00167         /* Query write timeout. */
00168         *lvp = dcb->dcb_ttimeout;
00169         break;
00170 
00171         /* Add attional ioctl functions here. */
00172 
00173     default:
00174         /* Unknown function. */
00175         rc = -1;
00176         break;
00177     }
00178     return rc;
00179 }
00180 
00191 static int GenCharInit(NUTDEVICE * dev)
00192 {
00193     /* Add hardware initialization here. */
00194 
00195     /* Register interrupt handler, if required. */
00196     if (NutRegisterIrqHandler(&GENDEV_SIGNAL, GenCharInterrupt, dev)) {
00197         return -1;
00198     }
00199     /* Set interrupt mode and enable interrupts. */
00200     NutIrqSetMode(&GENDEV_SIGNAL, NUT_IRQMODE_LOWLEVEL);
00201     NutIrqEnable(&GENDEV_SIGNAL);
00202 
00203     return 0;
00204 }
00205 
00227 static int GenCharRead(NUTFILE * fp, void *buffer, int size)
00228 {
00229     int rc;
00230     int i;
00231     NUTDEVICE *dev = fp->nf_dev;
00232     DEVDCB *dcb = dev->dev_dcb;
00233 
00234     /* Call without data pointer discards receive buffer. */
00235     if (buffer == 0) {
00236         /* Atomic access to the receive counter. */
00237         NutIrqDisable(&GENDEV_SIGNAL);
00238         dcb->dcb_rcnt = 0;
00239         NutIrqEnable(&GENDEV_SIGNAL);
00240 
00241         return 0;
00242     }
00243 
00244     /*
00245      * Wait until at least one character is buffered or until a read
00246      * timeout occured.
00247      */
00248     for (;;) {
00249         /* Atomic access to the receive counter. */
00250         NutIrqDisable(&GENDEV_SIGNAL);
00251         rc = dcb->dcb_rcnt;
00252         NutIrqEnable(&GENDEV_SIGNAL);
00253         if (rc) {
00254             break;
00255         }
00256 
00257         if (NutEventWait(&dcb->dcb_rrdy, dcb->dcb_rtimeout)) {
00258             return 0; /* Timeout. */
00259         }
00260     }
00261 
00262     if (rc > size) {
00263         rc = size;
00264     }
00265 
00266     if (rc) {
00267         memcpy(buffer, dcb->dcb_rbuff, rc);
00268         /* 
00269          * This sample driver simply moves remaining bytes to the front 
00270          * of the buffer. A more sophisticated driver may use a circular 
00271          * buffer.
00272          */
00273         NutIrqDisable(&GENDEV_SIGNAL);
00274         dcb->dcb_rcnt -= rc;
00275         for (i = 0; i < dcb->dcb_rcnt; i++) {
00276             dcb->dcb_rbuff[i] = dcb->dcb_rbuff[rc + i];
00277         }
00278         NutIrqEnable(&GENDEV_SIGNAL);
00279     }
00280     return rc;
00281 }
00282 
00302 static int GenCharWrite(NUTFILE * fp, CONST void *buffer, int len)
00303 {
00304     int rc = 0;
00305     int cnt;
00306     int pend;
00307     CONST char *cp = buffer;
00308     NUTDEVICE *dev = fp->nf_dev;
00309     DEVDCB *dcb = dev->dev_dcb;
00310 
00311     while (rc < len) {
00312 
00313         /*
00314          * This sample driver waits on each output until all characters 
00315          * had been tranmitted. A more sophisticated driver may add
00316          * new characters as soon as there is room left in the tranmit
00317          * buffer.
00318          */
00319         for (;;) {
00320             /* Atomic access to the transmit counter. */
00321             NutIrqDisable(&GENDEV_SIGNAL);
00322             pend = dcb->dcb_tlen - dcb->dcb_tcnt;
00323             NutIrqEnable(&GENDEV_SIGNAL);
00324             
00325             if (pend == 0) {
00326                 break; /* All characters tranmitted. */
00327             }
00328             if (NutEventWait(&dcb->dcb_trdy, dcb->dcb_ttimeout)) {
00329                 return rc; /* Timeout. */
00330             }
00331         }
00332 
00333         /* Call without data pointer flushes the buffer. */
00334         if (buffer == 0) {
00335             return 0;
00336         }
00337 
00338         /* Determine the number of bytes left to transmit. */
00339         cnt = len - rc;
00340         if (cnt > sizeof(dcb->dcb_tbuff)) {
00341             cnt = sizeof(dcb->dcb_tbuff);
00342         }
00343 
00344         /* Fill the tranmit buffer. */
00345         NutIrqDisable(&GENDEV_SIGNAL);
00346         dcb->dcb_tcnt = cnt;
00347         memcpy(dcb->dcb_tbuff, cp + rc, cnt);
00348         /* Add code here to enable tranmit interrupts. */
00349         NutIrqEnable(&GENDEV_SIGNAL);
00350         rc += cnt;
00351     }
00352     return rc;
00353 }
00354 
00355 #ifdef __HARVARD_ARCH__
00356 
00377 int GenCharWrite_P(NUTFILE * fp, PGM_P buffer, int len)
00378 {
00379     /* Our sample driver doesn't support this. */
00380     return -1;
00381 }
00382 #endif
00383 
00401 static NUTFILE *GenCharOpen(NUTDEVICE * dev, CONST char *name, int mode, int acc)
00402 {
00403     NUTFILE *fp = (NUTFILE *) (dev->dev_dcb);
00404 
00405     if ((fp = malloc(sizeof(NUTFILE))) == 0) {
00406         return NUTFILE_EOF; /* No memory. */
00407     }
00408 
00409     fp->nf_next = 0;
00410     fp->nf_dev = dev;
00411     fp->nf_fcb = 0;
00412 
00413     return fp;
00414 }
00415 
00427 static int GenCharClose(NUTFILE * fp)
00428 {
00429     /* We may optionally flush our output and discard our input buffers. */
00430 
00431     /* Release all resources which we allocated in the open function. */
00432     if (fp) {
00433         free(fp);
00434     }
00435     return 0;
00436 }
00437 
00449 long GenCharSize (NUTFILE *fp)
00450 {
00451     long rc;
00452     NUTDEVICE *dev = fp->nf_dev;
00453     DEVDCB *dcb = dev->dev_dcb;
00454 
00455     /* Atomic access to the receive buffer counter. */
00456     NutIrqDisable(&GENDEV_SIGNAL);
00457     rc = dcb->dcb_rcnt;
00458     NutIrqEnable(&GENDEV_SIGNAL);
00459 
00460     return rc;
00461 }
00462 
00466 NUTDEVICE devGenChar = {
00472     0,
00473 
00483     {'g', 'e', 'n', 'c', 'h', 'a', 'r', 0, 0},
00484 
00500     IFTYP_CHAR,
00501 
00512     0,
00513 
00524     0,
00525 
00537     0,
00538 
00548     &devdcb,
00549 
00556     GenCharInit,
00557 
00563     GenCharIOCtl,
00564 
00569     GenCharRead,
00570 
00575     GenCharWrite,
00576 
00577 #ifdef __HARVARD_ARCH__
00578 
00584     GenCharWrite_P,
00585 #endif
00586 
00590     GenCharOpen,
00591 
00595     GenCharClose,
00596 
00605     GenCharSize
00606 };
00607 
00608 

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