home *** CD-ROM | disk | FTP | other *** search
- #include "drc.h"
- #if NDRC > 0
- /*
- * Cidmac Robot DR11C driver
- *
- * After doing a successful open on this device, the user process
- * must fill in the "drcROBOT" structure (in drc.h) and "write"
- * it to this device. The structure includes Read buffer, count,
- * write buffer (the count is the first word) and the address of
- * a user interrupt routine which gets executed on a Dr11-c interrupt
- * after the buffer is read from the Dr11-c and placed directly
- * in user memory. After executing the user routine, the data in
- * the output buffer is written back to the Dr11-c. Doing ANY syscalls
- * from the user interrupt routine IS PROHIBITED!!! and will crash
- * the system with a "CHM? ERROR". Also the user interrupt routine
- * has full R/W access to kernel memory and any traps, aborts, or
- * other faults will result in a system crash. Care should be
- * taken not to write to any address with bit 31 set (80XXXXXX)
- * since this is the kernel. (The stack is here though, so don't
- * put very much stuff there). No syscalls are used to R/W this
- * device once the initial write is done since they are too slow.
- * The kernel interrupt routine handles it all from previously
- * specified parameters.
- * On any Dr11-c error, a uprintf() is issued to the controlling
- * tty and the console and the user process is sent a SIGHUP signal
- * since there is no means of returning an error.
- *
- * Warning: This driver needs the file close code in sys1.c/exit()
- * moved up before the code to release memory. Also many unorthodox
- * things are used here to gain speed for a realtime environment
- * like running a user routine in kernel mode on the intstk and
- * skipping protection, etc, etc. Anybody who uses this driver
- * must be checked out in ROOT privelidges and system startup/
- * shutdown/realtime procedures. This driver must take an interrupt
- * every 7 milliseconds (1/2 tick) and let the user routine run for
- * 5 milliseconds. This must be used in a single user enivornment.
- * Also any process with this device open, must NOT FORK(), VFORK(),
- * EXEC(), or do anything with raw I/O or which expands the data or
- * stack regions (like break() or growing the stack). Also the "open"
- * of this driver must be followed by a "write(fd, &drcROBOT, sizeof drcROBOT)"
- * to load initial parameters (should have used ioctl instead).
- * None of the parameters is checked (except for the write being done)
- * for validity. Failure to heed the warnings will result in system
- * crashes. Good luck.
- * --ghg 1/14/82.
- *
- */
- int drcdebug = 0;
-
- #include "../h/param.h"
- #include "../h/systm.h"
- #include "../h/tty.h"
- #include "../h/pte.h"
- #include "../h/map.h"
- #include "../h/buf.h"
- #include "../h/ubareg.h"
- #include "../h/ubavar.h"
- #include "../h/conf.h"
- #include "../h/mtpr.h"
- #include "../h/dir.h"
- #include "../h/user.h"
- #include "../h/proc.h"
-
- #include "../h/drc.h"
-
- #define ROBOT 0 /* minor device of robot project */
- #define DRC_DELAY 50000 /* spin loop timeout */
-
- #define DRC_CSR0 01 /* CSR bit 0 (to user dev) */
- #define DRC_CSR1 02 /* CSR bit 1 (to user dev) */
- #define DRC_IEB 040 /* INTER Enable B */
- #define DRC_IEA 0100 /* INTER Enable A */
- #define DRC_REQA 0200 /* REQ A line from user dev */
- #define DRC_REQB 0100000 /* REQ B line from user dev */
-
-
- struct drc_softc {
- int sc_openf;
- struct tty *sc_ttyp;
- int sc_nice;
- struct proc *sc_procp; /* proc with this dev open */
- caddr_t sc_rbuf; /* read buffer address */
- int sc_rcount; /* byte count */
- caddr_t sc_wbuf; /* write buffer address */
- int sc_P0BR; /* This proc's P0BR, P0LR, P1BR, P1LR */
- int sc_P0LR;
- int sc_P1BR;
- int sc_P1LR;
- int sc_setup; /* nz of setup complete */
- int (*sc_routine)();/* address of user interrupt routine */
- int (*sc_routine2)();/* address of user interrupt routine2 */
- int sc_vslocked; /* number of bytes locked down */
- } drc_softc[NDRC];
-
- struct drcdevice {
- u_short drccsr;
- u_short drcobuf;
- u_short drcibuf;
- };
-
- int drcprobe(), drcattach(), drcintr();
- struct uba_device *drcdinfo[NDRC];
- u_short drcstd[] = { 0 };
- struct uba_driver drcdriver =
- { drcprobe, 0, drcattach, 0, drcstd, "drc", drcdinfo };
-
- #define DRCUNIT(dev) (minor(dev))
-
- drcprobe(reg)
- caddr_t reg;
- {
- register int br, cvec;
- register struct drcdevice *drcaddr = (struct drcdevice *)reg;
-
- /*
- drcaddr->drccsr = DRC_IEA|DRC_IEB;
- DELAY(10000);
- drcaddr->drccsr = 0;
- */
- br = 0x16;
- cvec = 0310;
- if (((int)reg & 077) == 070)
- cvec = 0300; /* VOMIT */
- }
-
- /*ARGSUSED*/
- drcattach(ui)
- register struct uba_device *ui;
- {
-
- }
-
- drcopen(dev)
- dev_t dev;
- {
- register struct drc_softc *sc;
- register struct uba_device *ui;
- register struct drcdevice *drcaddr;
-
- if (DRCUNIT(dev) >= NDRC || (ui = drcdinfo[DRCUNIT(dev)]) == 0 ||
- ui->ui_alive == 0 || (sc = &drc_softc[DRCUNIT(dev)])->sc_openf) {
- u.u_error = ENXIO;
- return;
- }
- drcaddr = (struct drcdevice *)ui->ui_addr;
- sc->sc_procp = u.u_procp; /* used for signals later */
- sc->sc_ttyp = u.u_ttyp; /* controlling terminal for error mes */
- sc->sc_nice = u.u_procp->p_nice;
- u.u_procp->p_nice = 1;
- sc->sc_openf = 1;
- sc->sc_setup = 0;
- sc->sc_vslocked = 0;
- drcaddr->drccsr = 0;
- }
-
- drcclose(dev)
- dev_t dev;
- {
- register struct drc_softc *sc = &drc_softc[DRCUNIT(dev)];
- register struct drcdevice *drcaddr =
- (struct drcdevice *)drcdinfo[DRCUNIT(dev)]->ui_addr;
-
-
- drcaddr->drccsr = 0;
- sc->sc_setup = 0;
- if (sc->sc_vslocked)
- vsunlock(0, sc->sc_vslocked);
- u.u_procp->p_flag &= ~SLOCK;
- sc->sc_procp = (struct proc *) 0;
- sc->sc_ttyp = (struct tty *) 0;
- u.u_procp->p_nice = sc->sc_nice;
- drc_softc[DRCUNIT(dev)].sc_openf = 0;
- }
-
- drcread(dev)
- {
-
- u.u_error = ENXIO;
- }
-
- /*
- * For now, the write routine just inits the sc struct from
- * a user supplied drcrobot...
- */
- drcwrite(dev)
- dev_t dev;
- {
- register struct drc_softc *sc = &drc_softc[DRCUNIT(dev)];
- register struct drcdevice *drcaddr =
- (struct drcdevice *)drcdinfo[DRCUNIT(dev)]->ui_addr;
- struct drcROBOT drcROBOT;
-
- if (copyin(u.u_base, &drcROBOT, sizeof (struct drcROBOT))) {
- u.u_error = EFAULT;
- return;
- }
- sc->sc_routine = drcROBOT.R_routine;
- sc->sc_routine2 = drcROBOT.R_routine2;
- sc->sc_rbuf = drcROBOT.R_rbuf;
- sc->sc_rcount = drcROBOT.R_rcount;
- sc->sc_wbuf = drcROBOT.R_wbuf;
-
- /*
- * Lock down all the pages in text + data region
- */
-
-
- sc->sc_vslocked = ctob(u.u_tsize + u.u_dsize);
- if(drcdebug)
- printf("locking down %d bytes\n", sc->sc_vslocked);
- vslock(0, sc->sc_vslocked);
- u.u_procp->p_flag |= SLOCK; /* lock in core */
- sc->sc_P0BR = mfpr(P0BR);
- sc->sc_P0LR = mfpr(P0LR);
- sc->sc_P1BR = mfpr(P1BR);
- sc->sc_P1LR = mfpr(P1LR);
- sc->sc_setup = 1;
- drcaddr->drccsr = DRC_IEA|DRC_IEB;
-
- u.u_base += sizeof (struct drcROBOT);
- u.u_count -= sizeof (struct drcROBOT);
-
- }
- drcWRITE(dev)
- dev_t dev;
- {
- register struct drc_softc *sc = &drc_softc[DRCUNIT(dev)];
- register struct drcdevice *drcaddr =
- (struct drcdevice *)drcdinfo[DRCUNIT(dev)]->ui_addr;
- register short *sp = (short *)sc->sc_wbuf;
- register count = *sp++ / sizeof (short);
- int c;
-
- switch (DRCUNIT(dev)) {
-
- case ROBOT:
-
- while (count--) {
- drcaddr->drcobuf = *sp++;
- drcaddr->drccsr = DRC_CSR0;
- c = DRC_DELAY;
- while ((drcaddr->drccsr & DRC_REQA) == 0) {
- if (--c == 0) {
- drchung(dev,"SET REQA (write)",0);
- goto out;
- }
- }
- drcaddr->drccsr = 0;
- c = DRC_DELAY;
- while (drcaddr->drccsr & DRC_REQA) {
- if (--c == 0) {
- drchung(dev,"CLR REQA (write)",0);
- goto out;
- }
- }
-
- }
- /*
- * Indicate end of transfer
- */
-
- c = DRC_DELAY;
- if (drcdebug)
- uprintf("write done\n");
- drcaddr->drccsr = DRC_CSR0 | DRC_CSR1;
- while ((drcaddr->drccsr & DRC_REQB) == 0) {
- if (--c == 0) {
- drchung(dev,"SET REQB (write)",0);
- goto out;
- }
- }
- drcaddr->drccsr = 0;
- c = DRC_DELAY;
- while (drcaddr->drccsr & DRC_REQB) {
- if (--c == 0) {
- drchung(dev,"CLR REQB (write)",0);
- goto out;
- }
- }
- break;
-
- default:
- /* this is ineffecient and sucks */
- if (drcdebug)
- uprintf("default case\n");
- break;
-
- }
- out: ;
- }
-
- drcREAD(dev)
- register dev_t dev;
- {
- register struct drc_softc *sc = &drc_softc[DRCUNIT(dev)];
- register struct drcdevice *drcaddr =
- (struct drcdevice *)drcdinfo[DRCUNIT(dev)]->ui_addr;
- register short *sp = (short *)sc->sc_rbuf;
- register count = sc->sc_rcount;
- int c;
-
- switch (DRCUNIT(dev)) {
-
- case ROBOT:
-
- count /= sizeof (short);
- count++;
- while (count--) {
- c = DRC_DELAY;
- while ((drcaddr->drccsr & (DRC_REQA|DRC_REQB)) == 0) {
- if (--c == 0) {
- drchung(dev,"SET REQA (read)",0);
- goto out;
- }
- }
- if (drcaddr->drccsr & DRC_REQB) {
- if (drcdebug)
- uprintf("read EOF\n");
- /*
- * End of transfer
- */
- drcaddr->drccsr = DRC_CSR1;
- c = DRC_DELAY;
- while (drcaddr->drccsr & DRC_REQB) {
- if (--c == 0) {
- drchung(dev,"CLR REQB (read)",0);
- goto out;
- }
- }
- drcaddr->drccsr = 0;
- return;
- /* all done */
-
- }
- *sp++ = drcaddr->drcibuf;
- drcaddr->drccsr = DRC_CSR0;
- c = DRC_DELAY;
- while (drcaddr->drccsr & DRC_REQA) {
- if (--c == 0) {
- drchung(dev,"SET REQA (read)",0);
- goto out;
- }
- }
- drcaddr->drccsr = 0;
- }
- break;
-
- default:
- if (drcdebug)
- uprintf("default case2\n");
- break;
-
- }
- out: ;
- drcaddr->drccsr = 0;
- }
-
- drcintr(dev)
- dev_t dev;
- {
- int c;
- register struct drc_softc *sc = &drc_softc[DRCUNIT(dev)];
- register struct drcdevice *drcaddr =
- (struct drcdevice *)drcdinfo[DRCUNIT(dev)]->ui_addr;
- register s;
- int oldP0BR, oldP0LR, oldP1BR, oldP1LR;
-
-
- if(drcdebug)
- printf("I%d\n",dev);
-
- drcaddr->drccsr = DRC_CSR1;
- c = DRC_DELAY;
- while (drcaddr->drccsr & DRC_REQB) {
- if (--c == 0) {
- drchung(dev, "CLR REQB (interrupt)",1);
- }
- }
- drcaddr->drccsr = 0;
- if (!sc->sc_setup) {
- drchung(dev, "Driver not properly setup", 1);
- return;
- }
- s = spl7();
- /*
- * Save current user-page table pointer
- * and switch to user (P0,P1 region) page
- * table mapping for the process running
- * the robot, run his signal routine, and switch
- * back P0BR and P0LR to this proc.
- * This is playing with FIRE !!
- * THIS IS VAX-11/780 MACHINE DEPENDENT !!!!
- * ("Kentucky" process switch)
- */
- oldP0BR = mfpr(P0BR);
- oldP0LR = mfpr(P0LR);
- oldP1BR = mfpr(P1BR);
- oldP1LR = mfpr(P1LR);
- mtpr(P0BR, sc->sc_P0BR);
- mtpr(P0LR, sc->sc_P0LR);
- mtpr(P1BR, sc->sc_P1BR);
- mtpr(P0BR, sc->sc_P0BR);
- mtpr(TBIA, 0); /* Invalidate translation buffer */
- if (sc->sc_routine) {
- drcREAD(dev);
- (*sc->sc_routine)();
- drcWRITE(dev);
- if (sc->sc_routine2)
- (*sc->sc_routine2)();
- drcaddr->drccsr = DRC_IEA|DRC_IEB;
- } else
- uprintf("No user interrupt routine\n");
- mtpr(P0BR, oldP0BR);
- mtpr(P0LR, oldP0LR);
- mtpr(P1BR, oldP1BR);
- mtpr(P1LR, oldP1LR);
- mtpr(TBIA, 0);
- splx(s);
- if (!sc->sc_setup) {
- drcaddr->drccsr = 0; /* Clear IENB */
- if (sc->sc_procp)
- psignal(sc->sc_procp, SIGHUP); /* blow him away */
- }
- }
-
- drcreset()
- {
- }
-
- drcioctl()
- {
- }
-
- drchung(dev, s, interrupt)
- register dev_t dev;
- register char *s;
- int interrupt;
- {
- register struct drc_softc *sc = &drc_softc[DRCUNIT(dev)];
- register struct drcdevice *drcaddr =
- (struct drcdevice *)drcdinfo[DRCUNIT(dev)]->ui_addr;
- register pri;
- struct tty *savettyp;
-
- interrupt = 1; /* for now */
- if (interrupt) {
- pri = spl7();
- savettyp = u.u_ttyp;
- u.u_ttyp = sc->sc_ttyp;
- }
- uprintf("DR11C Hung, Csr: 0%o, Ob: 0%o, Ib: 0%o %s\n",
- drcaddr->drccsr, drcaddr->drcobuf, drcaddr->drcibuf, s);
-
- if (interrupt) {
- u.u_ttyp = savettyp;
- sc->sc_setup = 0; /* abort this device */
- splx(pri);
- } else {
- u.u_error = EIO;
- }
-
- printf("DR11C Hung, Csr: 0%o, Ob: 0%o, Ib: 0%o %s\n",
- drcaddr->drccsr, drcaddr->drcobuf, drcaddr->drcibuf, s);
-
- }
-
- #endif
-