home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Between Heaven & Hell 2
/
BetweenHeavenHell.cdr
/
500
/
471
/
rccl141
< prev
next >
Wrap
Text File
|
1987-03-02
|
11KB
|
378 lines
#include "drc.h"
#if NDRC > 0
/*
* Cidmac Robot FIFO 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.
*
* added minor device number for stanford arm 30 Oct 84 BUCK
*/
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 PUMA
#ifdef PUMA
#define ROBOT 0 /* minor device of Puma robot */
#endif
#ifdef STAN
#define ROBOT 1 /* minor device of Stanford robot */
#endif
#define DRC_DELAY 50000 /* spin loop timeout */
#define DRC_CSR0 010000 /* bit 0 (to user dev) */
#define DRC_CSR1 020000 /* bit 1 (to user dev) */
#define DRC_INT 01 /* INTER other cpu */
#define DRC_IEA 0100 /* INTER Enable A */
#define DRC_REQA 040000 /* REQ A line from user dev */
#define DRC_REQB 0100000 /* REQ B line from user dev */
#define FIFO_EMPTY 0200
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 drcbuf;
};
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 = 0140;
}
/*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;
register i, junk;
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;
/*
* Suck the FIFO dry first... Give up after 1024 since
* it will be a hardware problem.
*/
i = 0;
while ((drcaddr->drccsr & FIFO_EMPTY) == 0) {
junk = drcaddr->drcbuf;
if (i++ > 1024) {
uprintf("Robot FIFO hung full -- hardware problems\n");
drcclose(dev);
u.u_error = EIO;
break;
}
}
}
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_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;
u.u_base += sizeof (struct drcROBOT);
u.u_count -= sizeof (struct drcROBOT);
}
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 count;
register short *fp = (short *)&drcaddr->drcbuf;
register short *sp = (short *)sc->sc_rbuf;
int oldP0BR, oldP0LR, oldP1BR, oldP1LR;
if(drcdebug)
printf("I%d\n",dev);
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 (drcaddr->drccsr&FIFO_EMPTY) { /* spur intr */
uprintf("Spur Robot interrupt\n");
sc->sc_setup = 0; /* blow him away */
goto out;
}
if (sc->sc_routine) {
count = (int) (short) *fp;
if (count < 0 || count > 63) {
int i, junk;
uprintf("Bad robot count: 0%o\n", count);
while ((drcaddr->drccsr & FIFO_EMPTY) == 0) {
junk = drcaddr->drcbuf;
if (i++ > 1024) {
uprintf("Robot FIFO hung full -- hardware problems\n");
sc->sc_setup = 0;/* blow him away */
goto out;
}
}
sc->sc_setup = 0; /* blow him away */
goto out;
}
*sp++ = count;
while (count--)
*sp++ = *fp; /* suck it all out */
if ((drcaddr->drccsr & FIFO_EMPTY) == 0) {
uprintf("drcintr: FIFO not empty\n");
sc->sc_setup = 0; /* blow him away */
}
(*sc->sc_routine)();
sp = (short *) sc->sc_wbuf;
*fp = count = *sp++;
while (count--)
*fp = *sp++;
if (sc->sc_routine2)
(*sc->sc_routine2)();
} else
uprintf("No user interrupt routine\n");
out:
mtpr(P0BR, oldP0BR);
mtpr(P0LR, oldP0LR);
mtpr(P1BR, oldP1BR);
mtpr(P1LR, oldP1LR);
mtpr(TBIA, 0);
if (!sc->sc_setup) {
drcaddr->drccsr = 0; /* Clear IENB */
if (sc->sc_procp)
psignal(sc->sc_procp, SIGHUP); /* blow him away */
}
}
drcreset()
{
}
drcioctl()
{
}
#ifdef notdef
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
#endif