/* * Megatek Whizzard 7200 PE Parallel Interface Driver * * Joel Carter/Dan Ladermann (TWG) */ #ifdef SCCS_ID static char SCCS_ID [] = "%Z%%M% %I% %Y% %U% - %E% "; #endif SCCS_ID #include "../h/param.h" #include "../h/buf.h" #include "../h/dir.h" #include "../h/user.h" #include "../new/xselch.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 #define DO 0x01 /* prog i/o */ /* 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 megxselch; extern char megaddr[]; int megstart(), megscintr(), megstrategy(); #define uliaddr megaddr[0] /* address of the ULI */ struct buf megbuf; struct xselchq megscq = { &megstart, &megscintr, 0,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 */ physio(megstrategy, &megbuf, dev, B_READ); else if (minor(dev) == 1) /* peripheral bus */ percommand(dev,P_READ); } 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; xselchreq(megxselch,&megscq,dev); 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 */ xselchfree(megxselch); } megstrategy (bp) register struct buf *bp; { trace(MGTRACE, "megstrat, bytes=", megbuf.b_bcount); graphaddr = u.u_offset; /* get file location from seek */ xselchreq (megxselch, &megscq,0); /* 0 for graphics memory */ } megstart(dev) dev_t dev; { trace(MGTRACE, "megstart", dev); oc(megxselch,STOP); if( minor(dev) != 0 ) { /* not graphics memory */ return; } oc (uliaddr, ENABLE); /* enable interrupts from ULI */ trace(MGTRACE, "mgst", ss(uliaddr)); oc (uliaddr, WRGRADDR); trace(MGTRACE, "mgst", ss(uliaddr)); /* while (ss(uliaddr) == BUSY); not necessary or wrong because interface is waiting for a write */ wh(uliaddr,graphaddr); trace(MGTRACE, "mgst", ss(uliaddr)); whilebusy(uliaddr); trace(MGTRACE, "mgst", ss(uliaddr)); wdh (megxselch, megbuf.b_un.b_addr); wdh (megxselch, megbuf.b_un.b_addr+megbuf.b_bcount-1); printf("megbuf.st = %d, megbug.cnt = %d\n",megbuf.b_un.b_addr,megbuf.b_bcount); oc (uliaddr,(megbuf.b_flags&B_READ)?(RDGRDATA):(WRGRDATA)); trace(MGTRACE, "uliprog", (megbuf.b_flags&B_READ)); trace(MGTRACE, "mgst", ss(uliaddr)); oc (megxselch, (megbuf.b_flags&B_READ)?READ_GO:GO); trace(MGTRACE, "selprog", (megbuf.b_flags&B_READ)); } /* this routine processes interrupts that are internally generated by the selch */ /* we assume that the selch will always be knocked down when communicating * with the Megatek peripherals * thus the only way we will get an interrupt from the selch controller * is after a graphics memory data transfer */ megscintr(selchdev, selchstat, dev) dev_t selchdev, dev; { register int endadd; trace(MGTRACE, "megscintr", dev); oc (megxselch, STOP); if( minor(dev) != 0 ) { /* not graphics memory */ return; } if (megbuf.b_flags & B_READ) { oc(uliaddr,STOPREAD); } trace(MGTRACE, "megscintr, stat=", ss(uliaddr)); endadd = rh (megxselch); 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); xselchfree (megxselch); } /* 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: oc(uliaddr, PERREAD << 6); /* initiate Peripheral Read */ if ( ss(uliaddr) != IDR) { /* if no data, the * peripheral was * acknowledging a write */ oc (uliaddr, PERPULSE << 6); break; } megbuf.m_data = rh(uliaddr); /* get peripheral * data for users * program */ break; 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; dev_t dev; { trace( MGTRACE, "megioctl", dev); if (cmd == RESET) { xselchreq(megxselch,&megscq,dev); oc(uliaddr,RESET); whilebusy(uliaddr); sleep(2); /* delay to make sure the IPCU has done its job */ xselchfree(megxselch); } else if (cmd == DISABLE) { xselchreq(megxselch,&megscq,dev); oc(uliaddr,DISABLE); whilebusy(uliaddr); xselchfree(megxselch); } else if (cmd == ENABLE) { xselchreq(megxselch,&megscq,dev); oc(uliaddr,ENABLE); whilebusy(uliaddr); xselchfree(megxselch); } else if (cmd == DISARM) { xselchreq(megxselch,&megscq,dev); oc(uliaddr,DISARM); whilebusy(uliaddr); xselchfree(megxselch); } if (cmd == DO) { oc (megxselch, STOP) ; /* knock down the selch */ oc (uliaddr, RESET); trace (MGTRACE, "reset" , ss(uliaddr)); sleep(2); whilebusy(uliaddr); oc (uliaddr, WRGRADDR); wh (uliaddr, 1); whilebusy(uliaddr); oc (uliaddr, WRGRDATA); wh (uliaddr, 0); whilebusy(uliaddr); wh (uliaddr, 0xC000); whilebusy(uliaddr); oc (uliaddr, WRGRADDR); wh (uliaddr, 0xFFF1); whilebusy(uliaddr); oc (uliaddr, WRGRDATA); wh (uliaddr, 0x0057); whilebusy(uliaddr); wh (uliaddr, 0x0000); whilebusy(uliaddr); } } whilebusy(addr) int addr; { trace(MGTRACE, "whilebusy addr = ", addr); while (ss(addr) == BUSY) ; }