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
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
00063 #ifndef GENDEV_SPORT
00064 #define GENDEV_SPORT 0x100
00065 #endif
00066
00067
00068 #ifndef GENDEV_DPORT
00069 #define GENDEV_DPORT 0x104
00070 #endif
00071
00072
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
00106 if (st) {
00107
00108 if (dcb->dcb_rcnt < sizeof(dcb->dcb_rbuff)) {
00109
00110 dcb->dcb_rbuff[dcb->dcb_rcnt] = inr(GENDEV_DPORT);
00111 dcb->dcb_rcnt++;
00112 }
00113
00114 if (dcb->dcb_rcnt == 1) {
00115 NutEventPostFromIrq(&dcb->dcb_rrdy);
00116 }
00117 }
00118
00119
00120 else {
00121 if (dcb->dcb_tcnt < dcb->dcb_tlen) {
00122
00123 outr(GENDEV_DPORT, dcb->dcb_tbuff[dcb->dcb_tcnt]);
00124 dcb->dcb_tcnt++;
00125 }
00126
00127 else {
00128 NutEventPostFromIrq(&dcb->dcb_trdy);
00129
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
00155 dcb->dcb_rtimeout = *lvp;
00156 break;
00157 case DEV_GETREADTIMEOUT:
00158
00159 *lvp = dcb->dcb_rtimeout;
00160 break;
00161
00162 case DEV_SETWRITETIMEOUT:
00163
00164 dcb->dcb_ttimeout = *lvp;
00165 break;
00166 case DEV_GETWRITETIMEOUT:
00167
00168 *lvp = dcb->dcb_ttimeout;
00169 break;
00170
00171
00172
00173 default:
00174
00175 rc = -1;
00176 break;
00177 }
00178 return rc;
00179 }
00180
00191 static int GenCharInit(NUTDEVICE * dev)
00192 {
00193
00194
00195
00196 if (NutRegisterIrqHandler(&GENDEV_SIGNAL, GenCharInterrupt, dev)) {
00197 return -1;
00198 }
00199
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
00235 if (buffer == 0) {
00236
00237 NutIrqDisable(&GENDEV_SIGNAL);
00238 dcb->dcb_rcnt = 0;
00239 NutIrqEnable(&GENDEV_SIGNAL);
00240
00241 return 0;
00242 }
00243
00244
00245
00246
00247
00248 for (;;) {
00249
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;
00259 }
00260 }
00261
00262 if (rc > size) {
00263 rc = size;
00264 }
00265
00266 if (rc) {
00267 memcpy(buffer, dcb->dcb_rbuff, rc);
00268
00269
00270
00271
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
00315
00316
00317
00318
00319 for (;;) {
00320
00321 NutIrqDisable(&GENDEV_SIGNAL);
00322 pend = dcb->dcb_tlen - dcb->dcb_tcnt;
00323 NutIrqEnable(&GENDEV_SIGNAL);
00324
00325 if (pend == 0) {
00326 break;
00327 }
00328 if (NutEventWait(&dcb->dcb_trdy, dcb->dcb_ttimeout)) {
00329 return rc;
00330 }
00331 }
00332
00333
00334 if (buffer == 0) {
00335 return 0;
00336 }
00337
00338
00339 cnt = len - rc;
00340 if (cnt > sizeof(dcb->dcb_tbuff)) {
00341 cnt = sizeof(dcb->dcb_tbuff);
00342 }
00343
00344
00345 NutIrqDisable(&GENDEV_SIGNAL);
00346 dcb->dcb_tcnt = cnt;
00347 memcpy(dcb->dcb_tbuff, cp + rc, cnt);
00348
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
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;
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
00430
00431
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
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