📄 ik.c
字号:
/* * Copyright (c) 1986 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)ik.c 7.7 (Berkeley) 12/16/90 */#include "ik.h"#if NIK > 0/* * PS300/IKON DR-11W Device Driver. */#include "sys/param.h"#include "sys/buf.h"#include "sys/cmap.h"#include "sys/conf.h"#include "sys/dkstat.h"#include "sys/map.h"#include "sys/systm.h"#include "sys/user.h"#include "sys/vmmac.h"#include "sys/proc.h"#include "sys/kernel.h"#include "sys/syslog.h"#include "../include/mtpr.h"#include "../include/pte.h"#include "../vba/vbavar.h"#include "../vba/ikreg.h"#include "../vba/psreg.h"#include "../vba/psproto.h"int ikprobe(), ikattach(), iktimer();struct vba_device *ikinfo[NIK];long ikstd[] = { 0 };struct vba_driver ikdriver = { ikprobe, 0, ikattach, 0, ikstd, "ik", ikinfo };#define splik() spl4()/* * Devices are organized in pairs with the odd valued * device being used for ``diagnostic'' purposes. That * is diagnostic devices don't get auto-attach'd and * detach'd on open-close. */#define IKUNIT(dev) (minor(dev) >> 1)#define IKDIAG(dev) (minor(dev) & 01) /* is a diagnostic unit */struct ik_softc { uid_t is_uid; /* uid of open processes */ u_short is_timeout; /* current timeout (seconds) */ u_short is_error; /* internal error codes */ u_short is_flags;#define IKF_ATTACHED 0x1 /* unit is attached (not used yet) */ union { u_short w[2]; u_long l; } is_nameaddr; /* address of last symbol lookup */ caddr_t is_buf[PS_MAXDMA];/* i/o buffer XXX */} ik_softc[NIK];struct buf iktab[NIK]; /* unit command queue headers */struct buf rikbuf[NIK]; /* buffers for read/write operations */struct buf cikbuf[NIK]; /* buffers for control operations *//* buf overlay definitions */#define b_command b_residint ikdiotimo = PS_DIOTIMO; /* dio polling timeout */int iktimeout = PS_TIMEOUT; /* attention/dma timeout (in hz) */ikprobe(reg, vi) caddr_t reg; struct vba_device *vi;{ register int br, cvec; /* r12, r11 */ register struct ikdevice *ik;#ifdef lint br = 0; cvec = br; br = cvec; ikintr(0);#endif if (badaddr(reg, 2)) return (0); ik = (struct ikdevice *)reg; ik->ik_vec = --vi->ui_hd->vh_lastiv; /* * Use extended non-privileged address modifier * to avoid address overlap with 24-bit devices. */ ik->ik_mod = 0xf1; /* address modifier */ /* * Try and reset the PS300. Since this * won't work if it's powered off, we * can't use sucess/failure to decide * if the device is present. */ br = 0; (void) psreset(ik, IKCSR_IENA); if (br == 0) /* XXX */ br = 0x18, cvec = ik->ik_vec; /* XXX */ return (sizeof (struct ikdevice));}/* * Perform a ``hard'' reset. */psreset(ik, iena) register struct ikdevice *ik;{ ik->ik_csr = IKCSR_MCLR|iena; DELAY(10000); ik->ik_csr = IKCSR_FNC3|iena; if (!iena) return (dioread(ik) == PS_RESET); return (1);}ikattach(vi) struct vba_device *vi;{ ik_softc[vi->ui_unit].is_uid = -1;}/* * Open a PS300 and attach. We allow multiple * processes with the same uid to share a unit. *//*ARGSUSED*/ikopen(dev, flag) dev_t dev; int flag;{ register int unit = IKUNIT(dev); register struct ik_softc *sc; struct vba_device *vi; struct ikdevice *ik; int reset; if (unit >= NIK || (vi = ikinfo[unit]) == 0 || vi->ui_alive == 0) return (ENXIO); sc = &ik_softc[unit]; if (sc->is_uid != (uid_t)-1 && sc->is_uid != u.u_uid) return (EBUSY); if (sc->is_uid == (uid_t)-1) { sc->is_timeout = 0; timeout(iktimer, (caddr_t)unit, hz); /* * Perform PS300 attach for first process. */ if (!IKDIAG(dev)) { reset = 0; again: if (ikcommand(dev, PS_ATTACH, 1)) { /* * If attach fails, perform a hard * reset once, then retry the command. */ ik = (struct ikdevice *)ikinfo[unit]->ui_addr; if (!reset++ && psreset(ik, 0)) goto again; untimeout(iktimer, (caddr_t)unit); return (EIO); } } sc->is_uid = u.u_uid; } return (0);}/*ARGSUSED*/ikclose(dev, flag) dev_t dev; int flag;{ int unit = IKUNIT(dev); register struct ik_softc *sc = &ik_softc[unit]; if (!IKDIAG(dev)) (void) ikcommand(dev, PS_DETACH, 1); /* auto detach */ sc->is_uid = -1; untimeout(iktimer, (caddr_t)unit); return (0);}ikread(dev, uio) dev_t dev; struct uio *uio;{ return (ikrw(dev, uio, B_READ));}ikwrite(dev, uio) dev_t dev; struct uio *uio;{ return (ikrw(dev, uio, B_WRITE));}/* * Take read/write request and perform physical i/o * transaction with PS300. This involves constructing * a physical i/o request vector based on the uio * vector, performing the dma, and, finally, moving * the data to it's final destination (because of CCI * VERSAbus bogosities). */ikrw(dev, uio, rw) dev_t dev; register struct uio *uio; int rw;{ int error, unit = IKUNIT(dev), s, wrcmd; register struct buf *bp; register struct iovec *iov; register struct psalist *ap; struct ik_softc *sc = &ik_softc[unit]; if (unit >= NIK) return (ENXIO); bp = &rikbuf[unit]; error = 0, iov = uio->uio_iov, wrcmd = PS_WRPHY; for (; !error && uio->uio_iovcnt; iov++, uio->uio_iovcnt--) { /* * Hack way to set PS300 address w/o doing an lseek * and specify write physical w/ refresh synchronization. */ if (iov->iov_len == 0) { if ((int)iov->iov_base&PSIO_SYNC) wrcmd = PS_WRPHY_SYNC; uio->uio_offset = (int)iov->iov_base & ~PSIO_SYNC; continue; } if (iov->iov_len > PS_MAXDMA) { sc->is_error = PSERROR_INVALBC, error = EINVAL; continue; } if ((int)uio->uio_offset&01) { sc->is_error = PSERROR_BADADDR, error = EINVAL; continue; } s = splbio(); while (bp->b_flags&B_BUSY) { bp->b_flags |= B_WANTED; sleep((caddr_t)bp, PRIBIO+1); } splx(s); bp->b_flags = B_BUSY | rw; /* * Construct address descriptor in buffer. */ ap = (struct psalist *)sc->is_buf; ap->nblocks = 1; /* work-around dr300 word swapping */ ap->addr[0] = uio->uio_offset & 0xffff; ap->addr[1] = uio->uio_offset >> 16; ap->wc = (iov->iov_len + 1) >> 1; if (rw == B_WRITE) { error = copyin(iov->iov_base, (caddr_t)&ap[1], (unsigned)iov->iov_len); if (!error) error = ikcommand(dev, wrcmd, iov->iov_len + sizeof (*ap)); } else { caddr_t cp; int len; error = ikcommand(dev, PS_RDPHY, sizeof (*ap)); cp = (caddr_t)&ap[1], len = iov->iov_len; for (; len > 0; len -= NBPG, cp += NBPG) mtpr(P1DC, cp); if (!error) error = copyout((caddr_t)&ap[1], iov->iov_base, (unsigned)iov->iov_len); } (void) splbio(); if (bp->b_flags&B_WANTED) wakeup((caddr_t)bp); splx(s); uio->uio_resid -= iov->iov_len; uio->uio_offset += iov->iov_len; bp->b_flags &= ~(B_BUSY|B_WANTED); } return (error);}/* * Perform a PS300 command. */ikcommand(dev, com, count) dev_t dev; int com, count;{ register struct buf *bp; register int s; int error; bp = &cikbuf[IKUNIT(dev)]; s = splik(); while (bp->b_flags&B_BUSY) { if (bp->b_flags&B_DONE) break; bp->b_flags |= B_WANTED; sleep((caddr_t)bp, PRIBIO); } bp->b_flags = B_BUSY|B_READ; splx(s); bp->b_dev = dev; bp->b_command = com; bp->b_bcount = count; ikstrategy(bp); error = biowait(bp); if (bp->b_flags&B_WANTED) wakeup((caddr_t)bp); bp->b_flags &= B_ERROR; return (error);}/* * Physio strategy routine */ikstrategy(bp) register struct buf *bp;{ register struct buf *dp; /* * Put request at end of controller queue. */ dp = &iktab[IKUNIT(bp->b_dev)]; bp->av_forw = NULL; (void) splik(); if (dp->b_actf != NULL) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -