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