|
|
coherent
/* $Header: /var/lib/cvsd/repos/coherent/coherent/b/kernel/coh.386/bio.c,v 1.1.1.1 2019/05/29 04:56:37 root Exp $ */
/* (lgl-
* The information contained herein is a trade secret of Mark Williams
* Company, and is confidential information. It is provided under a
* license agreement, and may be copied or disclosed only under the
* terms of that agreement. Any reproduction or disclosure of this
* material without the express written authorization of Mark Williams
* Company or persuant to the license agreement is unlawful.
*
* COHERENT Version 2.3.37
* Copyright (c) 1982, 1983, 1984.
* An unpublished work by Mark Williams Company, Chicago.
* All rights reserved.
-lgl) */
/*
* Coherent.
* Buffered I/O.
*
* $Log: bio.c,v $
* Revision 1.1.1.1 2019/05/29 04:56:37 root
* coherent
*
* Revision 1.8 93/06/14 13:34:10 bin
* Hal: kernel 78 update
*
* Revision 1.9 93/04/14 10:06:14 root
* r75
*
* Revision 1.7 92/10/06 23:48:44 root
* Ker #64
*
* Revision 1.6 92/07/27 18:15:08 hal
* Kernel #59
*
* Revision 1.2 92/01/06 11:58:35 hal
* Compile with cc.mwc.
*
* Revision 1.1 88/03/24 16:13:29 src
* Initial revision
*
* 87/11/05 Allan Cornish /usr/src/sys/coh/bio.c
* New seg struct now used to allow extended addressing.
*
* 87/01/05 Allan Cornish /usr/src/sys/coh/bio.c
* ioreq() now only wakes &stimer if the swap timer is active.
*
* 86/12/12 Allan Cornish /usr/src/sys/coh/bio.c
* Added 3rd arg to dpoll() to specify blocking poll if non-zero.
*
* 86/11/19 Allan Cornish /usr/src/sys/coh/bio.c
* Added dpoll() routine to perform device polls [System V.3 compatible].
*
* 86/07/24 Allan Cornish /usr/src/sys/coh/bio.c
* Added check in devinit() for null dp->d_conp->c_load function pointer.
*/
#include <sys/coherent.h>
#include <sys/buf.h>
#include <sys/con.h>
#include <errno.h>
#include <sys/io.h>
#include <sys/proc.h>
#include <sys/sched.h>
#include <sys/seg.h>
#include <sys/stat.h>
/*
* NIGEL: Whatever a "dold_t" was, there is no such thing now. Strip them
* out sometime soon.
*/
typedef unsigned char dold_t;
static BUF **hasharray; /* pointer to hash buckets */
static BUF *firstbuf; /* pointer to first in LRU chain */
static BUF *lastbuf; /* pointer to last in LRU chain */
/*
* The following hashing algorithm is used by bclaim().
*/
#define HASH(device, blockno) ((device * 257) + blockno)
#if BDEBUG
#include <sys/bufdebug.h>
static BUFDEBUG bufdebug; /* actual counters used in profiling */
/*
* Perform buffer cache debugging ioctl's.
* These will not stay in the production release!
*/
bufioctl(cmd, vec)
BUFDEBUG *vec;
{
switch (cmd) {
case BDINIT: /* clear (init) all counters */
kclear(&bufdebug, sizeof(bufdebug));
bufdebug.nbuf = NBUF;
bufdebug.version = BDVERSION;
break;
case BDGETVAL: /* return current counters to user */
kucopy(&bufdebug, vec, sizeof(bufdebug));
break;
default:
SET_U_ERROR(EINVAL, "bufioctl()");
}
}
#endif
/*
* Allocate and initialize buffer headers.
*/
bufinit()
{
register BUF *bp;
paddr_t p;
caddr_t v;
int i;
p = MAPIO(blockp.sr_segp->s_vmem, 0);
v = blockp.sr_base;
if (NBUF < 32)
panic("NBUF not set correctly");
if (NHASH < 32)
panic("NHASH not set correctly");
bufl = kalloc(NBUF * sizeof(BUF));
hasharray = kalloc(NHASH * sizeof(BUF *));
if (bufl == BNULL || hasharray == BNULL)
panic("bufinit: insufficient memory for %d buffers", NBUF);
for (i = 0; i < NHASH; ++i)
hasharray[i] = BNULL;
/*
* initialize the buffer header array with the physical and
* virtual addresses of the buffers, NULL values for the
* hash chain pointers, and pointers to the successor and
* predecessor of the current node.
*/
firstbuf = &bufl[0];
for (bp = lastbuf = &bufl[NBUF-1]; bp >= bufl; --bp) {
bp->b_dev = NODEV;
bp->b_paddr = p;
bp->b_vaddr = v;
bp->b_hashf = BNULL;
bp->b_hashb = BNULL;
bp->b_LRUf = bp + 1; /* next entry in chain */
bp->b_LRUb = bp - 1; /* prev entry in chain */
p += BSIZE;
v += BSIZE;
}
/*
* the first and last headers are special cases.
*/
bufl[0].b_LRUb = BNULL; /* no predecessor */
bufl[NBUF-1].b_LRUf = BNULL; /* no successor */
}
/*
* Synchronise the buffer cache.
*/
bsync()
{
register BUF *bp;
#if BDEBUG
++bufdebug.bsync;
#endif
for (bp = &bufl[NBUF-1]; bp >= bufl; --bp) {
if ((bp->b_flag&BFMOD) == 0)
continue;
lock(bp->b_gate);
if (bp->b_flag&BFMOD)
bwrite(bp, 1);
unlock(bp->b_gate);
}
}
/*
* Synchronise all block for a particular device in the buffer cache
* and invalidate all references.
*/
bflush(dev)
register dev_t dev;
{
register BUF *bp;
#if BDEBUG
++bufdebug.bflush;
#endif
for (bp = &bufl[NBUF-1]; bp >= bufl; --bp) {
if (bp->b_dev != dev)
continue;
lock(bp->b_gate);
if (bp->b_dev == dev) {
if (bp->b_flag&BFMOD)
bwrite(bp, 1);
bp->b_dev = NODEV;
}
unlock(bp->b_gate);
}
}
/*
* Return a buffer containing the given block from the given device.
* If `sync' is not set, the read is asynchronous and no buffer is returned.
*/
BUF *
bread(dev, bno, sync)
dev_t dev;
daddr_t bno;
register int sync;
{
register BUF *bp;
register int s;
#if BDEBUG
++bufdebug.bread;
#endif
bp = bclaim(dev, bno);
if (bp->b_flag&BFNTP) {
if (sync)
bp->b_flag &= ~BFASY;
else {
bp->b_flag |= BFASY;
bumap(bp);
}
bp->b_req = BREAD;
bp->b_count = BSIZE;
/*
* NIGEL: It is my sincere hope that whoever put this sphi () here (and in the
* corresponding places lower down) was simply having a bad day and that there
* is no real reason for this. Delete this comment and the bad code as soon as
* we have determined that it isn't really important. Look for the sign of the
* good and bad magicians below...
*
* BAD MAGIC s = sphi();
*/
dblock(dev, bp);
if (!sync) {
/* BAD MAGIC spl(s); */
return (NULL);
}
/*
* If buffer is not valid, wait for it.
*/
s = sphi (); /* GOOD MAGIC */
while (bp->b_flag&BFNTP) {
x_sleep((char *)bp, pridisk, slpriNoSig, "bpwait");
/* If buffer is not valid, wait for it. */
}
spl(s);
if (bp->b_flag&BFERR) {
SET_U_ERROR(bp->b_err ? bp->b_err : EIO, "bread()");
brelease(bp);
return (NULL);
}
if (bp->b_resid == BSIZE) {
brelease(bp);
return (NULL);
}
}
if (!sync) {
brelease(bp);
return (NULL);
}
u.u_block++;
return (bp);
}
/*
* Perform an LRU chain update by unlinking the specified buffer
* from it present location in the LRU chain and inserting it
* at the head of the chain, as pointed to by "firstbuf". Handle
* updating "lastbuf" if current buffer is the last buffer on the chain.
*/
static
LRUupdate(bp)
register BUF *bp;
{
if (bp != firstbuf) {
if (bp == lastbuf)
lastbuf = bp->b_LRUb;
if (bp->b_LRUb != BNULL)
bp->b_LRUb->b_LRUf = bp->b_LRUf;
if (bp->b_LRUf != BNULL)
bp->b_LRUf->b_LRUb = bp->b_LRUb;
bp->b_LRUb = BNULL;
bp->b_LRUf = firstbuf;
firstbuf->b_LRUb = bp;
firstbuf = bp;
}
}
/*
* If the requested buffer header is in the hash chain, delete it.
*/
static
HASHdelete(bp)
register BUF *bp;
{
if (bp->b_hashb == BNULL) { /* we're first in the chain */
hasharray[bp->b_hashval] = bp->b_hashf;
if (bp->b_hashf != BNULL)
bp->b_hashf->b_hashb = BNULL;
} else {
bp->b_hashb->b_hashf = bp->b_hashf;
if (bp->b_hashf != BNULL)
bp->b_hashf->b_hashb = bp->b_hashb;
}
bp->b_hashf = BNULL;
bp->b_hashb = BNULL;
}
/*
* Insert the current buffer at the head of the appropriate hash chain.
*/
static
HASHinsert(bp)
register BUF *bp;
{
if (bp->b_hashf != BNULL || bp->b_hashb != BNULL)
panic("HASHinsert");
bp->b_hashf = hasharray[bp->b_hashval];
if (bp->b_hashf != BNULL)
bp->b_hashf->b_hashb = bp;
hasharray[bp->b_hashval] = bp;
}
/*
* If the requested buffer is in the buffer cache, return a pointer to
* it. If not, pick an empty buffer, set it up and return it.
*/
BUF *
bclaim(dev, bno)
dev_t dev;
register daddr_t bno;
{
register BUF *bp;
register int s;
unsigned long hashval;
static GATE bufgate; /* better than sphi()/spl() */
#if BDEBUG
++bufdebug.bclaim;
#endif
hashval = HASH(dev, bno) % NHASH; /* select a hash bucket */
again:
lock(bufgate); /* avoid pointer updates */
for (bp = hasharray[hashval]; bp != BNULL; bp = bp->b_hashf) {
#if BDEBUG
++bufdebug.compares;
#endif
if (bp->b_bno == bno && bp->b_dev == dev) {
lock(bp->b_gate);
if (bp->b_bno != bno || bp->b_dev != dev) {
#if BDEBUG
++bufdebug.fails;
#endif
unlock(bp->b_gate);
unlock(bufgate);
goto again;
}
#if BDEBUG
++bufdebug.hits;
#endif
/*
* Now that we have located the buffer in the cache,
* unlink it from its current location in the
* LRU chain and move it to the front.
*/
LRUupdate(bp);
/*
* If the buffer had an I/O error, mark it as
* invalid. Unlock the buffer gate and return
* the buffer to the requestor.
*/
if (bp->b_flag&BFERR)
bp->b_flag |= BFNTP;
unlock(bufgate);
bsmap(bp);
return (bp);
}
}
unlock(bufgate);
#if BDEBUG
++bufdebug.misses;
#endif
/*
* The requested buffer is not resident in our cache. Locate the
* oldest (least recently used) available buffer. If it's dirty,
* queue up an asynchronous write for it and continue searching
* for the next old candidate. Once a candidate is found, move it
* to the front of the LRU chain, update the hash pointers, mark
* the buffer as invalid, unlock our buffer gate and return the
* buffer to the requestor.
*/
for (;;) { /* loop until successful */
lock(bufgate);
for (bp = lastbuf; bp != BNULL; bp = bp->b_LRUb) {
if (locked(bp->b_gate))
continue; /* not available */
s = sphi();
if (locked(bp->b_gate)) {
spl(s);
continue; /* they snuck in ;-) */
}
lock(bp->b_gate);
spl(s);
if (bp->b_flag&BFMOD)
bwrite(bp, 0); /* flush dirty buffer */
else {
/*
* Update the hash chain for this old
* buffer. Unlink it from it's old location
* fixing up any references. Also, update
* the LRU chain to move the buffer to the head.
*/
HASHdelete(bp);
LRUupdate(bp);
bp->b_flag = BFNTP;
bp->b_dev = dev;
bp->b_bno = bno;
bp->b_hashval = hashval;
HASHinsert(bp);
unlock(bufgate);
bsmap(bp);
return (bp);
}
}
unlock(bufgate);
#if BDEBUG
++bufdebug.needbuf;
#endif
s = sphi();
bufneed = 1;
x_sleep((char *)&bufneed, pridisk, slpriNoSig, "bufneed");
/* There are no buffers available. */
spl(s);
} /* forever */
}
/*
* Write the given buffer out. If `sync' is set, the write is synchronous,
* otherwise asynchronous. This routine must be called with the buffer
* gate locked.
*/
bwrite(bp, sync)
register BUF *bp;
{
register int s;
#if BDEBUG
++bufdebug.bwrite;
#endif
if (sync)
bp->b_flag &= ~BFASY;
else {
bp->b_flag |= BFASY;
bumap(bp);
}
bp->b_flag |= BFNTP;
bp->b_req = BWRITE;
bp->b_count = BSIZE;
/* BAD MAGIC s = sphi(); */
dblock(bp->b_dev, bp);
if (!sync) {
/* BAD MAGIC spl(s); */
return;
}
s = sphi (); /* GOOD MAGIC */
while (bp->b_flag&BFNTP) {
x_sleep((char *)bp, pridisk, slpriNoSig, "bwrite");
/* Waiting for a buffer write to finish. */
}
spl(s);
}
/*
* This is called by the driver when I/O has completed on a buffer.
*/
bdone(bp)
register BUF *bp;
{
#if BDEBUG
++bufdebug.bdone;
#endif
if (bp->b_req == BWRITE)
bp->b_flag &= ~BFMOD;
if (bp->b_req == BREAD) {
if (bp->b_flag&BFERR)
bp->b_dev = NODEV;
}
if (bp->b_flag&BFASY) {
bp->b_flag &= ~BFASY;
brelease(bp);
}
bp->b_flag &= ~BFNTP;
dwakeup((char *)bp);
}
/*
* Release the given buffer.
*/
brelease(bp)
register BUF *bp;
{
#if BDEBUG
++bufdebug.brelease;
#endif
if (bp->b_flag&BFERR) {
bp->b_flag &= ~BFERR;
bp->b_dev = NODEV;
}
bp->b_flag &= ~BFNTP;
bumap(bp);
unlock(bp->b_gate);
if (bufneed) {
bufneed = 0;
wakeup((char *)&bufneed);
}
}
/*
* Map the given buffer.
*/
bsmap(bp)
register BUF *bp;
{
bsave(bp->b_map);
bp->b_flag |= BFMAP;
bmapv(bconv(bp->b_paddr));
}
/*
* Unmap the given buffer.
*/
bumap(bp)
register BUF *bp;
{
if ((bp->b_flag&BFMAP) == 0)
return;
bp->b_flag &= ~BFMAP;
brest(bp->b_map);
}
/*
* Read data from the I/O segment into kernel space.
*
* "v" is the destination virtual address.
* "n" is the number of bytes to read.
*/
ioread(iop, v, n)
register IO *iop;
register char *v;
register unsigned n;
{
#if BDEBUG
++bufdebug.ioread;
#endif
switch (iop->io_seg) {
case IOSYS:
#if BDEBUG
++bufdebug.iosys;
#endif
iop->io.vbase += kkcopy(iop->io.vbase, v, n);
break;
case IOUSR:
#if BDEBUG
++bufdebug.iousr;
#endif
iop->io.vbase += ukcopy(iop->io.vbase, v, n);
break;
case IOPHY:
#if BDEBUG
++bufdebug.iophy;
#endif
dmain(n, iop->io.pbase, v);
iop->io.pbase += n;
break;
}
iop->io_ioc -= n;
}
/*
* Write data from kernel space to the I/O segment.
*/
iowrite(iop, v, n)
register IO *iop;
register char *v;
register unsigned n;
{
#if BDEBUG
++bufdebug.iowrite;
#endif
switch (iop->io_seg) {
case IOSYS:
#if BDEBUG
++bufdebug.iosys;
#endif
iop->io.vbase += kkcopy(v, iop->io.vbase, n);
break;
case IOUSR:
#if BDEBUG
++bufdebug.iousr;
#endif
iop->io.vbase += kucopy(v, iop->io.vbase, n);
break;
case IOPHY:
#if BDEBUG
++bufdebug.iophy;
#endif
dmaout(n, iop->io.pbase, v);
iop->io.pbase += n;
break;
}
iop->io_ioc -= n;
}
/*
* Get a character from the I/O segment.
*/
iogetc(iop)
register IO *iop;
{
register int c;
#if BDEBUG
++bufdebug.iogetc;
#endif
if (iop->io_ioc == 0)
return (-1);
--iop->io_ioc;
if (iop->io_seg == IOSYS)
c = *(char*) iop->io.vbase++ & 0377;
else {
c = getubd(iop->io.vbase++);
if (u.u_error)
return (-1);
}
return (c);
}
/*
* Put a character using the I/O segment.
*/
ioputc(c, iop)
register IO *iop;
{
#if BDEBUG
++bufdebug.ioputc;
#endif
if (iop->io_ioc == 0)
return (-1);
--iop->io_ioc;
if (iop->io_seg == IOSYS)
* (char *)iop->io.vbase++ = c;
else {
putubd(iop->io.vbase++, c);
if (u.u_error)
return (-1);
}
return (c);
}
/*
* Given a buffer pointer, an I/O structure, a device, request type, and
* a flags word, check the I/O structure and perform the I/O request.
*/
ioreq(bp, iop, dev, req, f)
register BUF *bp;
register IO *iop;
dev_t dev;
{
register int n;
register int s;
register CON *cp;
dold_t dold;
#if BDEBUG
++bufdebug.ioreq;
#endif
if ((cp=drvmap(dev, &dold)) == NULL)
return;
lock(bp->b_gate);
n = cp->c_flag; /* n should do something with that flag */
drest(dold);
if (iop) {
if (f&BFBLK) {
if (blocko(iop->io_seek)) {
SET_U_ERROR(EIO, "ioreq()");
goto out;
}
}
if (f&BFIOC) {
if (!iomapvp(iop, bp)) {
SET_U_ERROR(EIO, "ioreq()");
goto out;
}
}
}
bp->b_flag = f|BFNTP;
bp->b_req = req;
bp->b_dev = dev;
if (iop) {
bp->b_bno = blockn(iop->io_seek);
bp->b_count = iop->io_ioc;
}
/*BAD MAGIC s = sphi(); */
dblock(dev, bp);
s = sphi (); /* GOOD MAGIC */
while (bp->b_flag&BFNTP) {
x_sleep((char *)bp, pridisk, slpriNoSig, "ioreq");
/* Ask norm what this sleep means. */
}
spl(s);
if (stimer.t_last)
wakeup((char *)&stimer);
if (bp->b_flag&BFERR) {
SET_U_ERROR(bp->b_err ? bp->b_err : EIO, "ioreq()");
goto out;
}
if (iop) {
n = iop->io_ioc - bp->b_resid;
iop->io_seek += n;
iop->io_ioc -= n;
}
out:
unlock(bp->b_gate);
}
/*
* Given an I/O structure and a buffer header, see if the addresses
* in the I/O structure are valid and set up the buffer header.
*
* Search the u area segment table for a data segment containing
* iop->io.vbase. If one is found, put the corresponding system
* global address into bp->b_paddr and return the corresponding
* SEG pointer, else return NULL.
*/
SEG *
iomapvp(iop, bp)
register IO *iop;
register BUF *bp;
{
register SR *srp;
register SEG *sp;
register caddr_t iobase, base;
unsigned ioc;
int i;
if (iop->io_seg != IOUSR)
panic("Raw I/O from non user");
iobase = iop->io.vbase;
ioc = iop->io_ioc;
for (srp = u.u_segl; srp < &u.u_segl[NUSEG]; srp++) {
if ((sp = srp->sr_segp) == NULL)
continue;
if ((srp->sr_flag&SRFDATA) == 0)
continue;
/*
* The following calculation is because the system represents
* the 'base' of a stack as its upper limit (because it is the
* upper limit that is fixed).
*/
base = srp->sr_base;
if (srp==&u.u_segl[SISTACK])
base -= srp->sr_size;
if (iobase < base)
continue;
if (iobase + ioc > base + sp->s_size)
continue;
bp->b_paddr = MAPIO(sp->s_vmem, iobase - base);
return sp;
}
/* Is the io area in question contained in a shared memory segment? */
if (srp = accShm(iobase, ioc)) {
sp = srp->sr_segp;
base = srp->sr_base;
bp->b_paddr = MAPIO(sp->s_vmem, iobase - base);
return sp;
}
return 0;
}
/*
* Initialise devices.
* Mark all initialized devices as loaded.
*/
devinit()
{
register DRV *dp;
register int mind;
for ( dp = drvl, mind = 0; mind < drvn; mind++, dp++ ) {
if (dp->d_conp && dp->d_conp->c_load) {
(*dp->d_conp->c_load)();
dev_loaded |= (1<<mind);
}
}
/*
* Inform STREAMS that it is time to set up shop.
*/
STREAMS_INIT ();
}
/*
* Open a device.
*
* NIGEL: In order to make it at all possible to support the System V DDI/DDK
* calling conventions for driver entry points, it is necessary for this code
* to pass the *type* of open being made to the underlying device (which is
* passed in the 'f' parameter below).
*/
dopen(dev, m, f)
register dev_t dev;
{
register CON *cp;
dold_t dold;
if ((cp=drvmap(dev, &dold)) == NULL)
return;
if ((cp->c_flag&f) == 0) {
SET_U_ERROR(ENXIO, "dopen()");
return;
}
(*cp->c_open)(dev, m, f); /* NIGEL */
drest(dold);
}
/*
* Close a device.
*
* NIGEL: In order to be able to support the System V DDI/DDK calling
* conventions for driver entry points, this function has to be altered to
* accept a file-mode and character/block mode parameter. Note that the
* Coherent 4.0 driver kit documentation says that the driver close entry
* point is passed the same parameters as the open entry. After this mod,
* this will be true for the first time.
*/
dclose(dev, mode, typ)
register dev_t dev;
{
register CON *cp;
dold_t dold;
if ((cp=drvmap(dev, &dold)) == NULL)
return;
(*cp->c_close)(dev, mode, typ); /* NIGEL */
drest(dold);
}
/*
* Call the block entry point of a device.
*/
dblock(dev, bp)
dev_t dev;
BUF *bp;
{
register CON *cp;
dold_t dold;
if ((cp=drvmap(dev, &dold)) == NULL)
return;
(*cp->c_block)(bp);
drest(dold);
}
/*
* Read from a device.
*/
dread(dev, iop)
register dev_t dev;
register IO *iop;
{
register CON *cp;
dold_t dold;
if ((cp=drvmap(dev, &dold)) == NULL)
return;
(*cp->c_read)(dev, iop);
drest(dold);
}
/*
* Write to a device.
*/
dwrite(dev, iop)
register dev_t dev;
register IO *iop;
{
register CON *cp;
dold_t dold;
if ((cp=drvmap(dev, &dold)) == NULL)
return;
(*cp->c_write)(dev, iop);
drest(dold);
}
/*
* Call the ioctl function for a device.
*
* NIGEL: In order to support the System V DDI/DDK calling conventions for
* device driver entry points, this function needs to pass a "mode" parameter
* indicating the open mode of the file. There are only two calls to this
* function, for uioctl () and in the /dev/tty driver, "io.386/ct.c" which is
* passing its arguments back here (ie, a layered open). The "ct.c" call has
* not been changed.
*/
dioctl(dev, com, vec, mode)
register dev_t dev;
union ioctl *vec;
{
register CON *cp;
dold_t dold;
if ((cp=drvmap(dev, &dold)) == NULL)
return;
if (XMODE_286)
tioc(dev, com, vec, cp->c_ioctl);
else
(*cp->c_ioctl)(dev, com, vec, mode); /* NIGEL */
drest(dold);
}
/*
* Call the powerfail entry point of a device.
*/
dpower(dev)
register dev_t dev;
{
register CON *cp;
dold_t dold;
if ((cp=drvmap(dev, &dold)) == NULL)
return;
(*cp->c_power)(dev);
drest(dold);
}
/*
* Call the timeout entry point of a device.
*/
dtime(dev)
register dev_t dev;
{
register CON *cp;
dold_t dold;
if ((cp=drvmap(dev, &dold)) == NULL)
return;
(*cp->c_timer)(dev);
drest(dold);
}
/*
* Poll a device.
*/
dpoll(dev, ev, msec)
register dev_t dev;
int ev;
int msec;
{
register CON *cp;
dold_t dold;
if ((cp=drvmap(dev, &dold)) == NULL)
return POLLNVAL;
if ( cp->c_flag & DFPOL )
ev = (*cp->c_poll)(dev, ev, msec);
else
ev = POLLNVAL;
drest(dold);
return ev;
}
/*
* Given a device, and a pointer to a driver map save area, save the
* current map in the driver map save area and map in the new device,
* returning a pointer to the configuration entry for that device.
*
* NIGEL: This function is the only code that references drvl [] directly
* other than the bogus code that manages the load and unload entry points,
* which we will also need to "enhance". What we add to this code is a range
* check so that it no longer can index off the end of drvl [], and in the
* case that we would go off the end of drvl [] we vector instead to the
* STREAMS system and ask it to return a kludged-up "CON *". The mapping
* code referred to above is for the i286 and does nothing whatsoever, so
* all this function really does as it stands is a table lookup.
*/
CON *
drvmap(dev, doldp)
dev_t dev;
dold_t *doldp;
{
register DRV *dp;
register unsigned m;
if ((m=major(dev)) >= drvn) {
CON * conp;
/*
* NIGEL: If STREAMS is disabled or there is no device
* corresponding to this (external) major number, flag ENXIO.
*/
if ((conp = STREAMS_GETCON (dev)) != NULL)
return conp;
SET_U_ERROR(ENXIO, "drvmap()");
return (NULL);
}
dp = &drvl[m];
if (locked(dp->d_gate)) {
SET_U_ERROR(ENXIO, "drvmap()");
return (NULL);
}
if (dp->d_conp == NULL) {
SET_U_ERROR(ENXIO, "drvmap()");
return (NULL);
}
dsave(*doldp);
#ifndef _I386
if (dp->d_map)
dmapv(dp->d_map);
#endif
return (dp->d_conp);
}
/*
* Non existant device.
*/
nonedev()
{
SET_U_ERROR(ENXIO, "nonedev()");
}
/*
* Null device.
*/
nulldev()
{
}
#if 0
/* debugging utility. given a system global addr (e.g. iop->io.pbase),
return the first int at the address */
grabDB(paddr)
{
int ret;
int work = workAlloc();
cseg_t * base = sysmem.u.pbase + btocrd(paddr);
ptable1_v[work] = *base | SEG_SRW;
mmuupd();
ret = *(int*)(ctob(work)+(paddr&(NBPC-1)));
workFree(work);
return ret;
}
#endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.