Go to the documentation of this file.00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
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 
00066 #ifndef GENDEV_SPORT
00067 #define GENDEV_SPORT    0x100
00068 #endif
00069 
00070 
00071 #ifndef GENDEV_DPORT
00072 #define GENDEV_DPORT    0x104
00073 #endif
00074 
00075 
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     
00109     if (st) {
00110         
00111         if (dcb->dcb_rcnt < sizeof(dcb->dcb_rbuff)) {
00112             
00113             dcb->dcb_rbuff[dcb->dcb_rcnt] = inr(GENDEV_DPORT);
00114             dcb->dcb_rcnt++;
00115         }
00116         
00117         if (dcb->dcb_rcnt == 1) {
00118             NutEventPostFromIrq(&dcb->dcb_rrdy);
00119         }
00120     }
00121 
00122     
00123     else {
00124         if (dcb->dcb_tcnt < dcb->dcb_tlen) {
00125             
00126             outr(GENDEV_DPORT, dcb->dcb_tbuff[dcb->dcb_tcnt]);
00127             dcb->dcb_tcnt++;
00128         }
00129         
00130         else {
00131             NutEventPostFromIrq(&dcb->dcb_trdy);
00132             
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         
00158         dcb->dcb_rtimeout = *lvp;
00159         break;
00160     case DEV_GETREADTIMEOUT:
00161         
00162         *lvp = dcb->dcb_rtimeout;
00163         break;
00164 
00165     case DEV_SETWRITETIMEOUT:
00166         
00167         dcb->dcb_ttimeout = *lvp;
00168         break;
00169     case DEV_GETWRITETIMEOUT:
00170         
00171         *lvp = dcb->dcb_ttimeout;
00172         break;
00173 
00174         
00175 
00176     default:
00177         
00178         rc = -1;
00179         break;
00180     }
00181     return rc;
00182 }
00183 
00194 static int GenCharInit(NUTDEVICE * dev)
00195 {
00196     
00197 
00198     
00199     if (NutRegisterIrqHandler(&GENDEV_SIGNAL, GenCharInterrupt, dev)) {
00200         return -1;
00201     }
00202     
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     
00238     if (buffer == 0) {
00239         
00240         NutIrqDisable(&GENDEV_SIGNAL);
00241         dcb->dcb_rcnt = 0;
00242         NutIrqEnable(&GENDEV_SIGNAL);
00243 
00244         return 0;
00245     }
00246 
00247     
00248 
00249 
00250 
00251     for (;;) {
00252         
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; 
00262         }
00263     }
00264 
00265     if (rc > size) {
00266         rc = size;
00267     }
00268 
00269     if (rc) {
00270         memcpy(buffer, dcb->dcb_rbuff, rc);
00271         
00272 
00273 
00274 
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 
00318 
00319 
00320 
00321 
00322         for (;;) {
00323             
00324             NutIrqDisable(&GENDEV_SIGNAL);
00325             pend = dcb->dcb_tlen - dcb->dcb_tcnt;
00326             NutIrqEnable(&GENDEV_SIGNAL);
00327             
00328             if (pend == 0) {
00329                 break; 
00330             }
00331             if (NutEventWait(&dcb->dcb_trdy, dcb->dcb_ttimeout)) {
00332                 return rc; 
00333             }
00334         }
00335 
00336         
00337         if (buffer == 0) {
00338             return 0;
00339         }
00340 
00341         
00342         cnt = len - rc;
00343         if (cnt > sizeof(dcb->dcb_tbuff)) {
00344             cnt = sizeof(dcb->dcb_tbuff);
00345         }
00346 
00347         
00348         NutIrqDisable(&GENDEV_SIGNAL);
00349         dcb->dcb_tcnt = cnt;
00350         memcpy(dcb->dcb_tbuff, cp + rc, cnt);
00351         
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     
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; 
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     
00433 
00434     
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     
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