/* * Line Interupt Driver * * This driver supports the PE eight line interupt module. * * The li module has input lines that when asserted, generate * an interupt. The line must be enabled to do this. * * From the UNIX view, each line will be a seperate device. * The minor device code is used to select a specific board * and line. When the device is open, the corresponding line * is enabled. When a process performs a read, it is suspended * if no interupts have occured since the device was open * or the last read. When the li interupts, it wakes any * waiting processes. Finally, when the device is closed, * the line is disabled. */ #include "../h/local.h" #ifdef SCCS_ID static char SCCS_ID [] = "@(#)li.c 1.1 16:17:33 - 83/02/23 "; #endif SCCS_ID #include "../h/param.h" #include "../h/dir.h" #include "../h/user.h" #include "../h/file.h" #define LIPRI 75 /* line interupt wakeup priority */ #define MAXLINES 16 #define LINESPERBOARD 8 extern char liaddr[]; extern int nli; /* Controller Commands */ #define SET 0x00 /* wd's are interupt mask */ #define ENABLE 0x40 /* enable interupts */ /* State bits */ #define LIENABLE 0x01 /* Line is open and enabled */ #define LIWAITING 0x02 /* Process waiting for interupt */ struct litab { char li_state; /* State bits (see above) */ char li_count; /* Interupts since last read */ }; static struct litab litab[MAXLINES]; liopen(dev, flag) dev_t dev; int flag; { int minr; minr = minor(dev); if (0 <= minr && minr < nli) if (!flag) if (!(litab[minr].li_state & LIENABLE)) { litab[minr].li_state = LIENABLE; lienab(); } else u.u_error = EBUSY; else u.u_error = EACCES; else u.u_error = ENXIO; } liclose(dev) dev_t dev; { litab[minor(dev)].li_state = 0; lienab(); } liread(dev) dev_t dev; { register struct litab *li; spl4(); li = &litab[minor(dev)]; while (li->li_count == 0) { li->li_state |= LIWAITING; sleep (li, LIPRI); } li->li_count = 0; spl0(); u.u_base += u.u_count; u.u_offset += u.u_count; u.u_count = 0; } liioctl(dev, cmd, addr, flag) dev_t dev; caddr_t addr; { } lienab() { register board; register line; register i; char mask; line = 0; for (board = 0; board < nli; board += LINESPERBOARD) { mask = 0; for (i = 0; i < LINESPERBOARD; i++) { mask <<= 1; if (litab[line++].li_state & LIENABLE) mask++; } oc (liaddr[board], SET); wd (liaddr[board], mask); oc (liaddr[board], ENABLE); } } liint(dev, status) { register struct litab *li; li = &litab[dev]; li->li_count++; if(li->li_state & LIWAITING) { li->li_state &= ~LIWAITING; wakeup(li); } }