/* * Megatek Whizzard 7200 PE Parallel Interface Driver * * Joel Carter/Dan Ladermann (TWG) */ #include "../h/param.h" #include "../h/buf.h" #include "../h/dir.h" #include "../h/user.h" #include "../h/selch.h" #include "../h/meg.h" #undef trace /* Various manifests */ #define MAXMG 2 /* leave it at 2 for now */ #define MGTRACE (01<<31) /* Status bit definitions */ #define BTO 0x04 /* Bus Timeout- Graphics Bus Interrupt */ #define BUSY 0x08 #define PREQ 0x10 /* Peripheral Request- Peripheral Bus Interrupt */ #define SIN02 0x20 #define IFBT0 0x40 #define IDR 0x80 /* ULI commands */ /* All data transfers with these commands are halfword transfers */ #define RESETB 0x2A #define STOPREAD 0x29 #define RESET 0x28 #define WRPERDATA 0x27 #define WRPERADDR 0x26 #define WRGRDATA 0x25 #define WRGRADDR 0x24 #define RDPERDATA 0x23 #define RDPERADDR 0x22 #define RDGRDATA 0x21 #define RDGRADD 0x20 /* Condition Codes for Peripheral Address */ /* Peripheral Address is of the form CCPPPPPP * where PPPPPP is the address and CC is one * of the following: */ #define LOADADD 00 #define INTACK 01 #define PERREAD 02 #define PERPULSE 03 /* ULI Interrupt Control definitions */ #define DISABLE 0x80 #define ENABLE 0x40 #define DISARM 0xC0 /* Peripheral Command Flags */ #define P_READ 0 #define P_WRITE 1 /* Peripheral Interrupt Codes */ #define IPCU 0x34 #define FSCD 0x18 #define PICK 0x10 #define RASTER 0x08 /* Vector Memory Reserved Locations */ #define INTMASK 0x0E typedef int Ulicommand; int nmeg = 1; extern char periaddr[]; extern int megselch; extern char megaddr[]; int megstart(), megscintr(), megstrategy(); #define uliaddr megaddr[0] /* address of the ULI */ struct buf megbuf; struct selchq megscq { &megstart, &megscintr, 0 }; /* State bits for software model */ #define MGISOPEN 0x01 struct megtab { char m_state; unsigned short m_data; /* data returned from device */ unsigned short m_bto_data[2]; /* data returned from interrupt */ } megtab[MAXMG]; struct buf meghead; /* header of queue of activation records */ unsigned short graphaddr; /* address into 64K graphics memory */ /* I assume that an assignment of an off_t into an unsigned short * gives me the least significant 16 bits */ megopen (dev, flag) dev_t dev; int flag; { register int min; trace(MGTRACE, "megopen", dev); min = minor(dev); if(0 <= min && min < nmeg) if (flag) if (! (megtab[min].m_state & MGISOPEN) ) { /* initialize (maybe) */ megtab[min].m_state = MGISOPEN; } else u.u_error = EACCES; else u.u_error = EPERM; else u.u_error = ENXIO; } megclose(dev) dev_t dev; { trace(MGTRACE, "megclose", dev); megtab[minor(dev)].m_state = 0; } megread(dev) dev_t dev; { trace(MGTRACE,"megread",dev); if (minor(dev) == 0) /* graphics memory */ { trace(MGTRACE,"bpio",dev); physio(megstrategy, &megbuf, dev, B_READ); trace(MGTRACE,"apio",dev); } else if (minor(dev) == 1) /* peripheral bus */ { trace(MGTRACE,"bpcm",dev); percommand(dev,P_READ); trace(MGTRACE,"apcm",dev); } } megwrite(dev) dev_t dev; { trace(MGTRACE, "megwrite", dev); if (minor(dev) == 0) /* graphics memory */ physio (megstrategy, &megbuf, dev, B_WRITE); else if (minor(dev) == 1) /* peripheral bus */ percommand(dev,P_WRITE); } percommand(dev,cmd) dev_t dev; { short addr; trace(MGTRACE,"percom",dev); selchreq(megselch,&megscq); addr = periaddr[minor(dev)]; oc(uliaddr,WRPERADDR); /* give ULI the peripheral address */ whilebusy(uliaddr); wh(uliaddr,addr); /* write the peripheral address */ oc(uliaddr, cmd? RDPERDATA : WRPERDATA); whilebusy(uliaddr); if (cmd == P_READ) megtab[minor(dev)].m_data = rdh(uliaddr); /* get peripeheral value for user */ } megstrategy (bp) register struct buf *bp; { trace(MGTRACE, "megstrat, bytes=", megbuf.b_bcount); graphaddr = u.u_offset; /* get file location from seek */ selchreq (megselch, &megscq); } megstart() { trace(MGTRACE, "megstart", 0); oc(megselch,STOP); oc (uliaddr, WRGRADDR); /* while (ss(uliaddr) == BUSY); not necessary or wrong because interface is waiting for a write */ wh(uliaddr,graphaddr); while (ss(uliaddr) == BUSY); wdh (megselch, megbuf.b_un.b_addr); wdh (megselch, megbuf.b_un.b_addr+megbuf.b_bcount-1); oc (uliaddr,(megbuf.b_flags&B_READ)?(RDGRDATA):(WRGRDATA)); oc (megselch, (megbuf.b_flags&B_READ)?READ_GO:GO); } /* this routine processes interrupts that are internally generated by the selch */ megscintr() { register int endadd; trace(MGTRACE, "megscintr", 0); oc (megselch, STOP); if (megbuf.b_flags & B_READ) { oc(uliaddr,STOPREAD); } selchfree (megselch); trace(MGTRACE, "megscintr, stat=", ss(uliaddr)); endadd = rh (megselch); if (endadd < megbuf.b_un.b_addr+megbuf.b_bcount-1) megbuf.b_flags |= B_ERROR; else megbuf.b_resid = 0; trace(MGTRACE, "megscintr1, stat=", ss(uliaddr)); iodone (&megbuf); } /* this routine processes interrupts from the ULI * there are two types of possible interrupts from the ULI * one is a peripheral bus interrupt signalled by PREQ in the ULI * status register * the other is a graphics bus interrupt signalled by BTO in the ULI * status register * BTO is automatically reset by the next command to the ULI * megintr is guaranteed to have the selch ( otherwise the interrupt ) * would never have been seen * this code will run to completion */ megintr(dev) int dev; /* from devmap[] in c.c */ { trace(MGTRACE, "megintr", dev); /* handle peripheral interrupts */ if (ss(uliaddr) == PREQ) /* peripheral request*/ { register int peraddr; oc (uliaddr, (INTACK << 6) ); /* acknowledge interrupt */ while (ss(uliaddr) != IDR); /* wait for the peripheral's address to be latched */ peraddr = rh(uliaddr); /* read the address */ switch (peraddr) { case IPCU: megtab[minor(dev)].m_data = rh(IPCU); /* return data half * word to user */ case FSCD: case PICK: case RASTER: default: break; } } else if (ss(uliaddr) == BTO) /* graphics bus interrupt */ { trace(MGTRACE, "megbtointr", 0); oc(uliaddr,WRGRADDR); wh(uliaddr,INTMASK); whilebusy(uliaddr); oc(uliaddr, RDGRDATA); megbuf.m_bto_data[1] = rh(uliaddr); /* least sign. 16 bits */ megbuf.m_bto_data[2] = rh(uliaddr); /* most sign. 16 bits */ /* A valid read from Vector Memory clears the BTO bit */ /* megbuf.b_flags |= B_ERROR; /* return an error to user program * can't use u.u_error */ } else printf("spurious int %d\n",dev); /* spurious interrupt */ } megioctl(dev,cmd,addr,flag) caddr_t addr; { trace(MGTRACE,"megioctl",cmd); if (cmd = RESET) { selchreq(megselch,&megscq); oc(uliaddr,RESET); whilebusy(uliaddr); sleep(2); /* delay to make sure the IPCU has done its job */ selchfree(megselch); } else if (cmd = DISABLE) { selchreq(megselch,&megscq); oc(uliaddr,DISABLE); whilebusy(uliaddr); selchfree(megselch); } else if (cmd = ENABLE) { selchreq(megselch,&megscq); oc(uliaddr,ENABLE); whilebusy(uliaddr); selchfree(megselch); } else if (cmd = DISARM) { selchreq(megselch,&megscq); oc(uliaddr,DISARM); whilebusy(uliaddr); selchfree(megselch); } } whilebusy(addr) int addr; { trace(MGTRACE, "bwhilebusy addr = ", addr); while (ss(addr) == BUSY) ; trace(MGTRACE, "awhilebusy addr = ", addr); }