summaryrefslogtreecommitdiffstats
path: root/sys/dev/ppbus
diff options
context:
space:
mode:
authormsmith <msmith@FreeBSD.org>1997-08-14 13:57:45 +0000
committermsmith <msmith@FreeBSD.org>1997-08-14 13:57:45 +0000
commit4cab4fbe44c163678dcf49eff0f7c26780af5748 (patch)
tree0e0fb58db68b41fb5f2f7cf944e37dbcee0948b6 /sys/dev/ppbus
parent08ef2a797164241d584a77ec4b88ef78325433d7 (diff)
downloadFreeBSD-src-4cab4fbe44c163678dcf49eff0f7c26780af5748.zip
FreeBSD-src-4cab4fbe44c163678dcf49eff0f7c26780af5748.tar.gz
New directory and drivers for Parallel Port Bus devices.
Submitted by: Nicolas Souchu <Nicolas.Souchu@prism.uvsq.fr>
Diffstat (limited to 'sys/dev/ppbus')
-rw-r--r--sys/dev/ppbus/nlpt.c765
-rw-r--r--sys/dev/ppbus/nlpt.h74
-rw-r--r--sys/dev/ppbus/ppbconf.c339
-rw-r--r--sys/dev/ppbus/ppbconf.h239
-rw-r--r--sys/dev/ppbus/ppi.c172
-rw-r--r--sys/dev/ppbus/ppi.h39
-rw-r--r--sys/dev/ppbus/vpo.c860
-rw-r--r--sys/dev/ppbus/vpo.h109
8 files changed, 2597 insertions, 0 deletions
diff --git a/sys/dev/ppbus/nlpt.c b/sys/dev/ppbus/nlpt.c
new file mode 100644
index 0000000..6e35a12
--- /dev/null
+++ b/sys/dev/ppbus/nlpt.c
@@ -0,0 +1,765 @@
+/*
+ * Copyright (c) 1990 William F. Jolitz, TeleMuse
+ * 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 software is a component of "386BSD" developed by
+ * William F. Jolitz, TeleMuse.
+ * 4. Neither the name of the developer nor the name "386BSD"
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS A COMPONENT OF 386BSD DEVELOPED BY WILLIAM F. JOLITZ
+ * AND IS INTENDED FOR RESEARCH AND EDUCATIONAL PURPOSES ONLY. THIS
+ * SOFTWARE SHOULD NOT BE CONSIDERED TO BE A COMMERCIAL PRODUCT.
+ * THE DEVELOPER URGES THAT USERS WHO REQUIRE A COMMERCIAL PRODUCT
+ * NOT MAKE USE OF THIS WORK.
+ *
+ * FOR USERS WHO WISH TO UNDERSTAND THE 386BSD SYSTEM DEVELOPED
+ * BY WILLIAM F. JOLITZ, WE RECOMMEND THE USER STUDY WRITTEN
+ * REFERENCES SUCH AS THE "PORTING UNIX TO THE 386" SERIES
+ * (BEGINNING JANUARY 1991 "DR. DOBBS JOURNAL", USA AND BEGINNING
+ * JUNE 1991 "UNIX MAGAZIN", GERMANY) BY WILLIAM F. JOLITZ AND
+ * LYNNE GREER JOLITZ, AS WELL AS OTHER BOOKS ON UNIX AND THE
+ * ON-LINE 386BSD USER MANUAL BEFORE USE. A BOOK DISCUSSING THE INTERNALS
+ * OF 386BSD ENTITLED "386BSD FROM THE INSIDE OUT" WILL BE AVAILABLE LATE 1992.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``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 DEVELOPER 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.
+ *
+ * from: unknown origin, 386BSD 0.1
+ * From Id: lpt.c,v 1.55.2.1 1996/11/12 09:08:38 phk Exp
+ * $Id$
+ */
+
+/*
+ * Device Driver for AT parallel printer port
+ * Written by William Jolitz 12/18/90
+ */
+
+/*
+ * Updated for ppbus by Nicolas Souchu
+ * [Mon Jul 28 1997]
+ */
+
+#include <sys/types.h>
+
+#ifdef KERNEL
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/proc.h>
+#include <sys/buf.h>
+#include <sys/kernel.h>
+#include <sys/uio.h>
+#include <sys/syslog.h>
+#include <sys/malloc.h>
+
+#include <machine/stdarg.h>
+#include <machine/clock.h>
+#include <machine/lpt.h>
+
+#include <i386/isa/isa.h>
+#include <i386/isa/isa_device.h>
+
+#include <sys/kernel.h>
+#endif /*KERNEL */
+
+#include <dev/ppbus/ppbconf.h>
+#include <dev/ppbus/nlpt.h>
+
+#ifndef DEBUG
+#define nlprintf (void)
+#else
+#define nlprintf if (nlptflag) printf
+static int volatile nlptflag = 1;
+#endif
+
+#define LPINITRDY 4 /* wait up to 4 seconds for a ready */
+#define LPTOUTINITIAL 10 /* initial timeout to wait for ready 1/10 s */
+#define LPTOUTMAX 1 /* maximal timeout 1 s */
+#define LPPRI (PZERO+8)
+#define BUFSIZE 1024
+
+#define LPTUNIT(s) ((s)&0x03)
+#define LPTFLAGS(s) ((s)&0xfc)
+
+static int nlpt = 0;
+#define MAXLPT 8 /* XXX not much better! */
+static struct lpt_data *lptdata[MAXLPT];
+
+/*
+ * Make ourselves visible as a ppbus driver
+ */
+
+static struct ppb_device *nlptprobe(struct ppb_data *ppb);
+static int nlptattach(struct ppb_device *dev);
+static void nlptintr(int unit);
+
+#ifdef KERNEL
+
+static struct ppb_driver nlptdriver = {
+ nlptprobe, nlptattach, "nlpt"
+};
+DATA_SET(ppbdriver_set, nlptdriver);
+
+#endif /* KERNEL */
+
+/* bits for state */
+#define OPEN (1<<0) /* device is open */
+#define ASLP (1<<1) /* awaiting draining of printer */
+#define EERROR (1<<2) /* error was received from printer */
+#define OBUSY (1<<3) /* printer is busy doing output */
+#define LPTOUT (1<<4) /* timeout while not selected */
+#define TOUT (1<<5) /* timeout while not selected */
+#define INIT (1<<6) /* waiting to initialize for open */
+#define INTERRUPTED (1<<7) /* write call was interrupted */
+
+
+/* status masks to interrogate printer status */
+#define RDY_MASK (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR) /* ready ? */
+#define LP_READY (LPS_SEL|LPS_NBSY|LPS_NERR)
+
+/* Printer Ready condition - from lpa.c */
+/* Only used in polling code */
+#define LPS_INVERT (LPS_NBSY | LPS_NACK | LPS_SEL | LPS_NERR)
+#define LPS_MASK (LPS_NBSY | LPS_NACK | LPS_OUT | LPS_SEL | LPS_NERR)
+#define NOT_READY(lpt) ((ppb_rstr(&(lpt)->lpt_dev)^LPS_INVERT)&LPS_MASK)
+
+#define MAX_SLEEP (hz*5) /* Timeout while waiting for device ready */
+#define MAX_SPIN 20 /* Max delay for device ready in usecs */
+
+static d_open_t nlptopen;
+static d_close_t nlptclose;
+static d_write_t nlptwrite;
+static d_ioctl_t nlptioctl;
+
+#define CDEV_MAJOR 16
+static struct cdevsw nlpt_cdevsw =
+ { nlptopen, nlptclose, noread, nlptwrite, /*16*/
+ nlptioctl, nullstop, nullreset, nodevtotty,/* lpt */
+ seltrue, nommap, nostrat, "nlpt", NULL, -1 };
+
+/*
+ * Internal routine to nlptprobe to do port tests of one byte value
+ */
+static int
+nlpt_port_test(struct lpt_data *lpt, u_char data, u_char mask)
+{
+ int temp, timeout;
+
+ data = data & mask;
+ ppb_wdtr(&lpt->lpt_dev, data);
+ timeout = 10000;
+ do {
+ DELAY(10);
+ temp = ppb_rdtr(&lpt->lpt_dev) & mask;
+ }
+ while (temp != data && --timeout);
+ nlprintf("out=%x\tin=%x\ttout=%d\n", data, temp, timeout);
+ return (temp == data);
+}
+
+/*
+ * New lpt port probe Geoff Rehmet - Rhodes University - 14/2/94
+ * Based partially on Rod Grimes' printer probe
+ *
+ * Logic:
+ * 1) If no port address was given, use the bios detected ports
+ * and autodetect what ports the printers are on.
+ * 2) Otherwise, probe the data port at the address given,
+ * using the method in Rod Grimes' port probe.
+ * (Much code ripped off directly from Rod's probe.)
+ *
+ * Comments from Rod's probe:
+ * Logic:
+ * 1) You should be able to write to and read back the same value
+ * to the data port. Do an alternating zeros, alternating ones,
+ * walking zero, and walking one test to check for stuck bits.
+ *
+ * 2) You should be able to write to and read back the same value
+ * to the control port lower 5 bits, the upper 3 bits are reserved
+ * per the IBM PC technical reference manauls and different boards
+ * do different things with them. Do an alternating zeros, alternating
+ * ones, walking zero, and walking one test to check for stuck bits.
+ *
+ * Some printers drag the strobe line down when the are powered off
+ * so this bit has been masked out of the control port test.
+ *
+ * XXX Some printers may not like a fast pulse on init or strobe, I
+ * don't know at this point, if that becomes a problem these bits
+ * should be turned off in the mask byte for the control port test.
+ *
+ * We are finally left with a mask of 0x14, due to some printers
+ * being adamant about holding other bits high ........
+ *
+ * Before probing the control port, we write a 0 to the data port -
+ * If not, some printers chuck out garbage when the strobe line
+ * gets toggled.
+ *
+ * 3) Set the data and control ports to a value of 0
+ *
+ * This probe routine has been tested on Epson Lx-800, HP LJ3P,
+ * Epson FX-1170 and C.Itoh 8510RM
+ * printers.
+ * Quick exit on fail added.
+ */
+static int
+nlpt_detect(struct lpt_data *lpt)
+{
+ int status;
+ u_char data;
+ u_char mask;
+ int i;
+
+ status = IO_LPTSIZE;
+
+ if (ppb_request_bus(&lpt->lpt_dev, PPB_DONTWAIT)) {
+ printf("nlpt: cannot alloc ppbus!\n");
+ status = 0 ; goto end_probe ;
+ }
+
+ mask = 0xff;
+ data = 0x55; /* Alternating zeros */
+ if (!nlpt_port_test(lpt, data, mask))
+ { status = 0 ; goto end_probe ; }
+
+ data = 0xaa; /* Alternating ones */
+ if (!nlpt_port_test(lpt, data, mask))
+ { status = 0 ; goto end_probe ; }
+
+ for (i = 0; i < 8; i++) { /* Walking zero */
+ data = ~(1 << i);
+ if (!nlpt_port_test(lpt, data, mask))
+ { status = 0 ; goto end_probe ; }
+ }
+
+ for (i = 0; i < 8; i++) { /* Walking one */
+ data = (1 << i);
+ if (!nlpt_port_test(lpt, data, mask))
+ { status = 0 ; goto end_probe ; }
+ }
+
+end_probe:
+ /* write 0's to control and data ports */
+ ppb_wdtr(&lpt->lpt_dev, 0);
+ ppb_wctr(&lpt->lpt_dev, 0);
+
+ ppb_release_bus(&lpt->lpt_dev);
+
+ return (status);
+}
+
+/*
+ * nlptprobe()
+ */
+static struct ppb_device *
+nlptprobe(struct ppb_data *ppb)
+{
+ struct lpt_data *lpt;
+
+ lpt = (struct lpt_data *) malloc(sizeof(struct lpt_data),
+ M_TEMP, M_NOWAIT);
+ if (!lpt) {
+ printf("nlpt: cannot malloc!\n");
+ return (0);
+ }
+ bzero(lpt, sizeof(struct lpt_data));
+
+ lptdata[nlpt] = lpt;
+
+ /*
+ * lpt dependent initialisation.
+ */
+ lpt->lpt_unit = nlpt;
+
+ /*
+ * ppbus dependent initialisation.
+ */
+ lpt->lpt_dev.id_unit = lpt->lpt_unit;
+ lpt->lpt_dev.ppb = ppb;
+ lpt->lpt_dev.intr = nlptintr;
+
+ /*
+ * Now, try to detect the printer.
+ */
+ if (!nlpt_detect(lpt)) {
+ free(lpt, M_TEMP);
+ return (0);
+ }
+
+ /* Ok, go to next device on next probe */
+ nlpt ++;
+
+ return (&lpt->lpt_dev);
+}
+
+static int
+nlptattach(struct ppb_device *dev)
+{
+ struct lpt_data *lpt = lptdata[dev->id_unit];
+
+ /*
+ * Report ourselves
+ */
+ printf("nlpt%d: <generic printer> on ppbus %d\n",
+ dev->id_unit, dev->ppb->ppb_link->adapter_unit);
+
+ lpt->sc_primed = 0; /* not primed yet */
+
+ if (ppb_request_bus(&lpt->lpt_dev, PPB_DONTWAIT)) {
+ printf("nlpt: cannot alloc ppbus!\n");
+ return (0);
+ }
+
+ ppb_wctr(&lpt->lpt_dev, LPC_NINIT);
+
+ /* check if we can use interrupt, should be done by ppc stuff */
+ nlprintf("oldirq %x\n", lpt->sc_irq);
+ if (ppb_get_irq(&lpt->lpt_dev)) {
+ lpt->sc_irq = LP_HAS_IRQ | LP_USE_IRQ | LP_ENABLE_IRQ;
+ printf("nlpt%d: Interrupt-driven port\n", dev->id_unit);
+ } else {
+ lpt->sc_irq = 0;
+ nlprintf("nlpt%d: Polled port\n", dev->id_unit);
+ }
+ nlprintf("irq %x\n", lpt->sc_irq);
+
+ ppb_release_bus(&lpt->lpt_dev);
+
+ return (1);
+}
+
+static void
+nlptout(struct lpt_data *lpt)
+{ int pl;
+
+ nlprintf ("T %x ", ppb_rstr(&lpt->lpt_dev));
+ if (lpt->sc_state & OPEN) {
+ lpt->sc_backoff++;
+ if (lpt->sc_backoff > hz/LPTOUTMAX)
+ lpt->sc_backoff = lpt->sc_backoff > hz/LPTOUTMAX;
+ timeout((timeout_func_t)nlptout, (caddr_t)lpt, lpt->sc_backoff);
+ } else
+ lpt->sc_state &= ~TOUT;
+
+ if (lpt->sc_state & EERROR)
+ lpt->sc_state &= ~EERROR;
+
+ /*
+ * Avoid possible hangs do to missed interrupts
+ */
+ if (lpt->sc_xfercnt) {
+ pl = spltty();
+ nlptintr(lpt->lpt_unit);
+ splx(pl);
+ } else {
+ lpt->sc_state &= ~OBUSY;
+ wakeup((caddr_t)lpt);
+ }
+
+ ppb_release_bus(&lpt->lpt_dev);
+}
+
+/*
+ * nlptopen -- reset the printer, then wait until it's selected and not busy.
+ * If LP_BYPASS flag is selected, then we do not try to select the
+ * printer -- this is just used for passing ioctls.
+ */
+
+static int
+nlptopen(dev_t dev, int flags, int fmt, struct proc *p)
+{
+ struct lpt_data *lpt;
+
+ int s;
+ int trys;
+ u_int unit = LPTUNIT(minor(dev));
+
+ if ((unit >= nlpt))
+ return (ENXIO);
+
+ lpt = lptdata[unit];
+
+ if (ppb_request_bus(&lpt->lpt_dev, PPB_WAIT|PPB_INTR))
+ return (EINTR);
+
+ if (lpt->sc_state) {
+ nlprintf("nlpt: still open %x\n", lpt->sc_state);
+ return(EBUSY);
+ } else
+ lpt->sc_state |= INIT;
+
+ lpt->sc_flags = LPTFLAGS(minor(dev));
+
+ /* Check for open with BYPASS flag set. */
+ if (lpt->sc_flags & LP_BYPASS) {
+ lpt->sc_state = OPEN;
+ return(0);
+ }
+
+ s = spltty();
+ nlprintf("nlpt flags 0x%x\n", lpt->sc_flags);
+
+ /* set IRQ status according to ENABLE_IRQ flag */
+ if (lpt->sc_irq & LP_ENABLE_IRQ)
+ lpt->sc_irq |= LP_USE_IRQ;
+ else
+ lpt->sc_irq &= ~LP_USE_IRQ;
+
+ /* init printer */
+ if ((lpt->sc_flags & LP_NO_PRIME) == 0) {
+ if((lpt->sc_flags & LP_PRIMEOPEN) || lpt->sc_primed == 0) {
+ ppb_wctr(&lpt->lpt_dev, 0);
+ lpt->sc_primed++;
+ DELAY(500);
+ }
+ }
+
+ ppb_wctr(&lpt->lpt_dev, LPC_SEL|LPC_NINIT);
+
+ /* wait till ready (printer running diagnostics) */
+ trys = 0;
+ do {
+ /* ran out of waiting for the printer */
+ if (trys++ >= LPINITRDY*4) {
+ splx(s);
+ lpt->sc_state = 0;
+ nlprintf ("status %x\n", ppb_rstr(&lpt->lpt_dev) );
+
+ ppb_release_bus(&lpt->lpt_dev);
+ return (EBUSY);
+ }
+
+ /* wait 1/4 second, give up if we get a signal */
+ if (tsleep((caddr_t)lpt, LPPRI|PCATCH, "lptinit", hz/4) !=
+ EWOULDBLOCK) {
+ lpt->sc_state = 0;
+ splx(s);
+
+ ppb_release_bus(&lpt->lpt_dev);
+ return (EBUSY);
+ }
+
+ /* is printer online and ready for output */
+ } while ((ppb_rstr(&lpt->lpt_dev) &
+ (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR)) !=
+ (LPS_SEL|LPS_NBSY|LPS_NERR));
+
+ lpt->sc_control = LPC_SEL|LPC_NINIT;
+ if (lpt->sc_flags & LP_AUTOLF)
+ lpt->sc_control |= LPC_AUTOL;
+
+ /* enable interrupt if interrupt-driven */
+ if (lpt->sc_irq & LP_USE_IRQ)
+ lpt->sc_control |= LPC_ENA;
+
+ ppb_wctr(&lpt->lpt_dev, lpt->sc_control);
+
+ lpt->sc_state = OPEN;
+ lpt->sc_inbuf = geteblk(BUFSIZE);
+ lpt->sc_xfercnt = 0;
+ splx(s);
+
+ /* only use timeout if using interrupt */
+ nlprintf("irq %x\n", lpt->sc_irq);
+ if (lpt->sc_irq & LP_USE_IRQ) {
+ lpt->sc_state |= TOUT;
+ timeout((timeout_func_t)nlptout, (caddr_t)lpt,
+ (lpt->sc_backoff = hz/LPTOUTINITIAL));
+ } else
+ ppb_release_bus(&lpt->lpt_dev);
+
+ nlprintf("opened.\n");
+ return(0);
+}
+
+/*
+ * nlptclose -- close the device, free the local line buffer.
+ *
+ * Check for interrupted write call added.
+ */
+
+static int
+nlptclose(dev_t dev, int flags, int fmt, struct proc *p)
+{
+ struct lpt_data *lpt = lptdata[LPTUNIT(minor(dev))];
+
+ if(lpt->sc_flags & LP_BYPASS)
+ goto end_close;
+
+ if (ppb_request_bus(&lpt->lpt_dev, PPB_WAIT|PPB_INTR))
+ return (EINTR);
+
+ lpt->sc_state &= ~OPEN;
+
+ /* if the last write was interrupted, don't complete it */
+ if((!(lpt->sc_state & INTERRUPTED)) && (lpt->sc_irq & LP_USE_IRQ))
+ while ((ppb_rstr(&lpt->lpt_dev) &
+ (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR)) !=
+ (LPS_SEL|LPS_NBSY|LPS_NERR) || lpt->sc_xfercnt)
+ /* wait 1/4 second, give up if we get a signal */
+ if (tsleep((caddr_t)lpt, LPPRI|PCATCH,
+ "lpclose", hz) != EWOULDBLOCK)
+ break;
+
+ ppb_wctr(&lpt->lpt_dev, LPC_NINIT);
+ brelse(lpt->sc_inbuf);
+
+ ppb_release_bus(&lpt->lpt_dev);
+
+end_close:
+ lpt->sc_state = 0;
+ lpt->sc_xfercnt = 0;
+ nlprintf("closed.\n");
+ return(0);
+}
+
+/*
+ * nlpt_pushbytes()
+ * Workhorse for actually spinning and writing bytes to printer
+ * Derived from lpa.c
+ * Originally by ?
+ *
+ * This code is only used when we are polling the port
+ */
+static int
+nlpt_pushbytes(struct lpt_data *lpt)
+{
+ int spin, err, tic;
+ char ch;
+
+ nlprintf("p");
+ /* loop for every character .. */
+ while (lpt->sc_xfercnt > 0) {
+ /* printer data */
+ ch = *(lpt->sc_cp);
+ lpt->sc_cp++;
+ lpt->sc_xfercnt--;
+
+ /*
+ * Wait for printer ready.
+ * Loop 20 usecs testing BUSY bit, then sleep
+ * for exponentially increasing timeout. (vak)
+ */
+ for (spin = 0; NOT_READY(lpt) && spin < MAX_SPIN; ++spin)
+ DELAY(1); /* XXX delay is NOT this accurate! */
+ if (spin >= MAX_SPIN) {
+ tic = 0;
+ while (NOT_READY(lpt)) {
+ /*
+ * Now sleep, every cycle a
+ * little longer ..
+ */
+ tic = tic + tic + 1;
+ /*
+ * But no more than 10 seconds. (vak)
+ */
+ if (tic > MAX_SLEEP)
+ tic = MAX_SLEEP;
+ err = tsleep((caddr_t)lpt, LPPRI,
+ "lptpoll", tic);
+ if (err != EWOULDBLOCK) {
+ return (err);
+ }
+ }
+ }
+
+ /* output data */
+ ppb_wdtr(&lpt->lpt_dev, ch);
+ /* strobe */
+ ppb_wctr(&lpt->lpt_dev, lpt->sc_control|LPC_STB);
+ ppb_wctr(&lpt->lpt_dev, lpt->sc_control);
+
+ }
+ return(0);
+}
+
+/*
+ * nlptwrite --copy a line from user space to a local buffer, then call
+ * putc to get the chars moved to the output queue.
+ *
+ * Flagging of interrupted write added.
+ */
+
+static int
+nlptwrite(dev_t dev, struct uio *uio, int ioflag)
+{
+ register unsigned n;
+ int pl, err;
+ struct lpt_data *lpt = lptdata[LPTUNIT(minor(dev))];
+
+ if(lpt->sc_flags & LP_BYPASS) {
+ /* we can't do writes in bypass mode */
+ return(EPERM);
+ }
+
+ if (ppb_request_bus(&lpt->lpt_dev, PPB_WAIT|PPB_INTR))
+ return (EINTR);
+
+ lpt->sc_state &= ~INTERRUPTED;
+ while ((n = min(BUFSIZE, uio->uio_resid)) != 0) {
+ lpt->sc_cp = lpt->sc_inbuf->b_un.b_addr ;
+ uiomove(lpt->sc_cp, n, uio);
+ lpt->sc_xfercnt = n ;
+ while ((lpt->sc_xfercnt > 0)&&(lpt->sc_irq & LP_USE_IRQ)) {
+ nlprintf("i");
+ /* if the printer is ready for a char, */
+ /* give it one */
+ if ((lpt->sc_state & OBUSY) == 0){
+ nlprintf("\nC %d. ", lpt->sc_xfercnt);
+ pl = spltty();
+ nlptintr(lpt->lpt_unit);
+ (void) splx(pl);
+ }
+ nlprintf("W ");
+ if (lpt->sc_state & OBUSY)
+ if ((err = tsleep((caddr_t)lpt,
+ LPPRI|PCATCH, "lpwrite", 0))) {
+ lpt->sc_state |= INTERRUPTED;
+ return(err);
+ }
+ }
+ /* check to see if we must do a polled write */
+ if(!(lpt->sc_irq & LP_USE_IRQ) && (lpt->sc_xfercnt)) {
+ nlprintf("p");
+ if((err = nlpt_pushbytes(lpt)))
+ return(err);
+ }
+
+ ppb_release_bus(&lpt->lpt_dev);
+ }
+ return(0);
+}
+
+/*
+ * nlptintr -- handle printer interrupts which occur when the printer is
+ * ready to accept another char.
+ *
+ * do checking for interrupted write call.
+ */
+
+void
+nlptintr(int unit)
+{
+ struct lpt_data *lpt = lptdata[unit];
+ int sts;
+ int i;
+
+ /*
+ * Is printer online and ready for output?
+ *
+ * Avoid falling back to nlptout() too quickly. First spin-loop
+ * to see if the printer will become ready ``really soon now''.
+ */
+ for (i = 0; i < 100 &&
+ ((sts=ppb_rstr(&lpt->lpt_dev)) & RDY_MASK) != LP_READY; i++) ;
+
+ if ((sts & RDY_MASK) == LP_READY) {
+ lpt->sc_state = (lpt->sc_state | OBUSY) & ~EERROR;
+ lpt->sc_backoff = hz/LPTOUTINITIAL;
+
+ if (lpt->sc_xfercnt) {
+ /* send char */
+ /*nlprintf("%x ", *lpt->sc_cp); */
+ ppb_wdtr(&lpt->lpt_dev, *lpt->sc_cp++) ;
+ ppb_wctr(&lpt->lpt_dev, lpt->sc_control|LPC_STB);
+ /* DELAY(X) */
+ ppb_wctr(&lpt->lpt_dev, lpt->sc_control);
+
+ /* any more data for printer */
+ if(--(lpt->sc_xfercnt) > 0) return;
+ }
+
+ /*
+ * No more data waiting for printer.
+ * Wakeup is not done if write call was interrupted.
+ */
+ lpt->sc_state &= ~OBUSY;
+ if(!(lpt->sc_state & INTERRUPTED))
+ wakeup((caddr_t)lpt);
+ nlprintf("w ");
+ return;
+ } else { /* check for error */
+ if(((sts & (LPS_NERR | LPS_OUT) ) != LPS_NERR) &&
+ (lpt->sc_state & OPEN))
+ lpt->sc_state |= EERROR;
+ /* nlptout() will jump in and try to restart. */
+ }
+ nlprintf("sts %x ", sts);
+}
+
+static int
+nlptioctl(dev_t dev, int cmd, caddr_t data, int flags, struct proc *p)
+{
+ int error = 0;
+ struct lpt_data *lpt;
+ u_int unit = LPTUNIT(minor(dev));
+ u_char old_sc_irq; /* old printer IRQ status */
+
+ lpt = lptdata[unit];
+
+ switch (cmd) {
+ case LPT_IRQ :
+ if(lpt->sc_irq & LP_HAS_IRQ) {
+ /*
+ * NOTE:
+ * If the IRQ status is changed,
+ * this will only be visible on the
+ * next open.
+ *
+ * If interrupt status changes,
+ * this gets syslog'd.
+ */
+ old_sc_irq = lpt->sc_irq;
+ if(*(int*)data == 0)
+ lpt->sc_irq &= (~LP_ENABLE_IRQ);
+ else
+ lpt->sc_irq |= LP_ENABLE_IRQ;
+ if (old_sc_irq != lpt->sc_irq )
+ log(LOG_NOTICE, "lpt%c switched to %s mode\n",
+ (char)unit+'0',
+ (lpt->sc_irq & LP_ENABLE_IRQ)?
+ "interrupt-driven":"polled");
+ } else /* polled port */
+ error = EOPNOTSUPP;
+ break;
+ default:
+ error = ENODEV;
+ }
+
+ return(error);
+}
+
+static nlpt_devsw_installed = 0;
+
+static void nlpt_drvinit(void *unused)
+{
+ dev_t dev;
+
+ if( ! nlpt_devsw_installed ) {
+ dev = makedev(CDEV_MAJOR, 0);
+ cdevsw_add(&dev,&nlpt_cdevsw, NULL);
+ nlpt_devsw_installed = 1;
+ }
+}
+
+SYSINIT(nlptdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,nlpt_drvinit,NULL)
diff --git a/sys/dev/ppbus/nlpt.h b/sys/dev/ppbus/nlpt.h
new file mode 100644
index 0000000..85f3dce
--- /dev/null
+++ b/sys/dev/ppbus/nlpt.h
@@ -0,0 +1,74 @@
+/*-
+ * Copyright (c) 1997 Nicolas Souchu
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * Distantly from :
+ * @(#)lptreg.h 1.1 (Berkeley) 12/19/90
+ * Id: lptreg.h,v 1.6 1997/02/22 09:36:52 peter Exp
+ *
+ * $Id$
+ */
+#ifndef __NLPT_H
+#define __NLPT_H
+
+#define LPS_NERR 0x08 /* printer no error */
+#define LPS_SEL 0x10 /* printer selected */
+#define LPS_OUT 0x20 /* printer out of paper */
+#define LPS_NACK 0x40 /* printer no ack of data */
+#define LPS_NBSY 0x80 /* printer no ack of data */
+
+#define LPC_STB 0x01 /* strobe data to printer */
+#define LPC_AUTOL 0x02 /* automatic linefeed */
+#define LPC_NINIT 0x04 /* initialize printer */
+#define LPC_SEL 0x08 /* printer selected */
+#define LPC_ENA 0x10 /* enable IRQ */
+
+struct lpt_data {
+ unsigned short lpt_unit;
+
+ struct ppb_device lpt_dev;
+
+ short sc_state;
+ /* default case: negative prime, negative ack, handshake strobe,
+ prime once */
+ u_char sc_control;
+ char sc_flags;
+#define LP_POS_INIT 0x04 /* if we are a postive init signal */
+#define LP_POS_ACK 0x08 /* if we are a positive going ack */
+#define LP_NO_PRIME 0x10 /* don't prime the printer at all */
+#define LP_PRIMEOPEN 0x20 /* prime on every open */
+#define LP_AUTOLF 0x40 /* tell printer to do an automatic lf */
+#define LP_BYPASS 0x80 /* bypass printer ready checks */
+ struct buf *sc_inbuf;
+ short sc_xfercnt ;
+ char sc_primed;
+ char *sc_cp ;
+ u_char sc_irq ; /* IRQ status of port */
+#define LP_HAS_IRQ 0x01 /* we have an irq available */
+#define LP_USE_IRQ 0x02 /* we are using our irq */
+#define LP_ENABLE_IRQ 0x04 /* enable IRQ on open */
+ u_char sc_backoff ; /* time to call lptout() again */
+};
+
+#endif
diff --git a/sys/dev/ppbus/ppbconf.c b/sys/dev/ppbus/ppbconf.c
new file mode 100644
index 0000000..5d2bc45
--- /dev/null
+++ b/sys/dev/ppbus/ppbconf.c
@@ -0,0 +1,339 @@
+/*-
+ * Copyright (c) 1997 Nicolas Souchu
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $Id$
+ *
+ */
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/conf.h>
+#include <sys/proc.h>
+#include <sys/buf.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/uio.h>
+#include <sys/syslog.h>
+
+#include <machine/clock.h>
+#include <machine/lpt.h>
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/pmap.h>
+
+#include <i386/isa/isa.h>
+#include <i386/isa/isa_device.h>
+
+#include <dev/ppbus/ppbconf.h>
+
+LIST_HEAD(, ppb_data) ppbdata; /* list of existing ppbus */
+
+/*
+ * Add a null driver so that the linker set always exists.
+ */
+
+static struct ppb_driver nulldriver = {
+ NULL, NULL, "null"
+};
+DATA_SET(ppbdriver_set, nulldriver);
+
+
+/*
+ * Parallel Port Bus sleep/wakeup queue.
+ */
+#define PRIPPB 28 /* PSOCK < PRIPPB < PWAIT XXX */
+
+/*
+ * ppb_alloc_bus()
+ *
+ * Allocate area to store the ppbus description.
+ * This function is called by ppcattach().
+ */
+struct ppb_data *
+ppb_alloc_bus(void)
+{
+ struct ppb_data *ppb;
+ static int ppbdata_initted = 0; /* done-init flag */
+
+ ppb = (struct ppb_data *) malloc(sizeof(struct ppb_data),
+ M_TEMP, M_NOWAIT);
+
+ /*
+ * Add the new parallel port bus to the list of existing ppbus.
+ */
+ if (ppb) {
+ bzero(ppb, sizeof(struct ppb_data));
+
+ if (!ppbdata_initted) { /* list not initialised */
+ LIST_INIT(&ppbdata);
+ ppbdata_initted = 1;
+ }
+ LIST_INSERT_HEAD(&ppbdata, ppb, ppb_chain);
+ } else {
+ printf("ppb_alloc_bus: cannot malloc!\n");
+ }
+ return(ppb);
+}
+
+/*
+ * ppb_attachdevs()
+ *
+ * Called by ppcattach(), this function probes the ppbus and
+ * attaches found devices.
+ */
+int
+ppb_attachdevs(struct ppb_data *ppb)
+{
+ int error;
+ struct ppb_device *dev;
+ struct ppb_driver **p_drvpp, *p_drvp;
+
+ LIST_INIT(&ppb->ppb_devs); /* initialise device/driver list */
+ p_drvpp = (struct ppb_driver **)ppbdriver_set.ls_items;
+
+ /*
+ * Blindly try all probes here. Later we should look at
+ * the parallel-port PnP standard, and intelligently seek
+ * drivers based on configuration first.
+ */
+ while ((p_drvp = *p_drvpp++) != NULL) {
+ if (p_drvp->probe && (dev = (p_drvp->probe(ppb))) != NULL) {
+ /*
+ * Add the device to the list of probed devices.
+ */
+ LIST_INSERT_HEAD(&ppb->ppb_devs, dev, chain);
+
+ /* Call the device's attach routine */
+ (void)p_drvp->attach(dev);
+ }
+ }
+ return (0);
+}
+
+/*
+ * ppb_request_bus()
+ *
+ * Allocate the device to perform transfers.
+ *
+ * how : PPB_WAIT or PPB_DONTWAIT
+ */
+int
+ppb_request_bus(struct ppb_device *dev, int how)
+{
+ int s, error = 0;
+ struct ppb_data *ppb = dev->ppb;
+
+ /*
+ * During initialisation, ppb is null.
+ */
+ if (!ppb)
+ return (0);
+
+ while (error != EINTR) {
+ s = splhigh();
+ if (ppb->ppb_owner) {
+ splx(s);
+
+ switch (how) {
+ case (PPB_WAIT | PPB_INTR):
+
+ error = tsleep(ppb, PRIPPB | PCATCH,
+ "ppbreq", 0);
+ break;
+ case (PPB_WAIT):
+ error = tsleep(ppb, PRIPPB, "ppbreq", 0);
+ break;
+ default:
+ return EWOULDBLOCK;
+ break;
+ }
+
+ } else {
+ ppb->ppb_owner = dev;
+
+ splx(s);
+ return (0);
+ }
+ }
+
+ return (EINTR);
+}
+
+/*
+ * ppb_release_bus()
+ *
+ * Release the device allocated with ppb_request_dev()
+ */
+int
+ppb_release_bus(struct ppb_device *dev)
+{
+ int s;
+ struct ppb_data *ppb = dev->ppb;
+
+ /*
+ * During initialisation, ppb is null.
+ */
+ if (!ppb)
+ return (0);
+
+ s = splhigh();
+ if (ppb->ppb_owner != dev) {
+ splx(s);
+ return (EACCES);
+ }
+
+ ppb->ppb_owner = 0;
+ splx(s);
+
+ /*
+ * Wakeup waiting processes.
+ */
+ wakeup(ppb);
+
+ return (0);
+}
+
+/*
+ * ppb_intr()
+ *
+ * Function called by ppcintr() when an intr occurs.
+ */
+void
+ppb_intr(struct ppb_link *pl)
+{
+ struct ppb_data *ppb = pl->ppbus;
+
+ /*
+ * Call chipset dependent code.
+ * Should be filled at chipset initialisation if needed.
+ */
+ if (pl->adapter->intr_handler)
+ (*pl->adapter->intr_handler)(pl->adapter_unit);
+
+ /*
+ * Call upper handler iff the bus is owned by a device and
+ * this device has specified an interrupt handler.
+ */
+ if (ppb->ppb_owner && ppb->ppb_owner->intr)
+ (*ppb->ppb_owner->intr)(ppb->ppb_owner->id_unit);
+
+ return;
+}
+
+/*
+ * ppb_reset_epp_timeout()
+ *
+ * Reset the EPP timeout bit in the status register.
+ */
+int
+ppb_reset_epp_timeout(struct ppb_device *dev)
+{
+ struct ppb_data *ppb = dev->ppb;
+
+ if (ppb->ppb_owner != dev)
+ return (EACCES);
+
+ (*ppb->ppb_link->adapter->reset_epp_timeout)(dev->id_unit);
+
+ return (0);
+}
+
+/*
+ * ppb_ecp_sync()
+ *
+ * Wait for the ECP FIFO to be empty.
+ */
+int
+ppb_ecp_sync(struct ppb_device *dev)
+{
+ struct ppb_data *ppb = dev->ppb;
+
+ if (ppb->ppb_owner != dev)
+ return (EACCES);
+
+ (*ppb->ppb_link->adapter->ecp_sync)(dev->id_unit);
+
+ return (0);
+}
+
+/*
+ * ppb_get_mode()
+ *
+ * Read the mode (SPP, EPP...) of the chipset.
+ */
+int
+ppb_get_mode(struct ppb_device *dev)
+{
+ return (dev->ppb->ppb_link->mode);
+}
+
+/*
+ * ppb_get_epp_protocol()
+ *
+ * Read the EPP protocol (1.9 or 1.7).
+ */
+int
+ppb_get_epp_protocol(struct ppb_device *dev)
+{
+ return (dev->ppb->ppb_link->epp_protocol);
+}
+
+/*
+ * ppb_get_irq()
+ *
+ * Return the irq, 0 if none.
+ */
+int
+ppb_get_irq(struct ppb_device *dev)
+{
+ return (dev->ppb->ppb_link->id_irq);
+}
+
+/*
+ * ppb_get_status()
+ *
+ * Read the status register and update the status info.
+ */
+int
+ppb_get_status(struct ppb_device *dev, struct ppb_status *status)
+{
+ struct ppb_data *ppb = dev->ppb;
+ register char r;
+
+ if (ppb->ppb_owner != dev)
+ return (EACCES);
+
+ r = status->status = ppb_rstr(dev);
+
+ status->timeout = r & TIMEOUT;
+ status->error = !(r & nFAULT);
+ status->select = r & SELECT;
+ status->paper_end = r & ERROR;
+ status->ack = !(r & nACK);
+ status->busy = !(r & nBUSY);
+
+ return (0);
+}
diff --git a/sys/dev/ppbus/ppbconf.h b/sys/dev/ppbus/ppbconf.h
new file mode 100644
index 0000000..b10df44
--- /dev/null
+++ b/sys/dev/ppbus/ppbconf.h
@@ -0,0 +1,239 @@
+/*-
+ * Copyright (c) 1997 Nicolas Souchu
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $Id$
+ *
+ */
+#ifndef __PPBCONF_H
+#define __PPBCONF_H
+
+/*
+ * Parallel Port Chipset modes.
+ */
+#define PPB_AUTODETECT 0x0 /* autodetect */
+#define PPB_NIBBLE 0x1 /* standard 4 bit mode */
+#define PPB_PS2 0x2 /* PS/2 byte mode */
+#define PPB_EPP 0x3 /* EPP mode, 32 bit */
+#define PPB_ECP_EPP 0x4 /* ECP in EPP mode */
+#define PPB_ECP_PS2 0x5 /* ECP in PS/2 mode */
+#define PPB_ECP 0x6 /* ECP mode */
+#define PPB_UNKNOWN 0x7 /* the last one */
+
+#define PPB_IS_EPP(mode) (mode == PPB_EPP || mode == PPB_ECP_EPP)
+
+#define PPB_IN_EPP_MODE(dev) (PPB_IS_EPP (ppb_get_mode (dev)))
+
+/*
+ * Parallel Port Chipset control bits.
+ */
+#define STROBE 0x01
+#define AUTOFEED 0x02
+#define nINIT 0x04
+#define SELECTIN 0x08
+#define PCD 0x20
+
+/*
+ * Parallel Port Chipset status bits.
+ */
+#define TIMEOUT 0x01
+#define nFAULT 0x08
+#define SELECT 0x10
+#define ERROR 0x20
+#define nACK 0x40
+#define nBUSY 0x80
+
+/*
+ * Structure to store status information.
+ */
+struct ppb_status {
+ unsigned char status;
+
+ unsigned int timeout:1;
+ unsigned int error:1;
+ unsigned int select:1;
+ unsigned int paper_end:1;
+ unsigned int ack:1;
+ unsigned int busy:1;
+};
+
+/*
+ * How tsleep () is called in ppb_request_bus ().
+ */
+#define PPB_DONTWAIT 0
+#define PPB_NOINTR 0
+#define PPB_WAIT 0x1
+#define PPB_INTR 0x2
+
+struct ppb_data; /* see below */
+
+/*
+ * Parallel Port Bus Device structure.
+ */
+struct ppb_device {
+
+ int id_unit; /* unit of the device */
+
+ void (*intr)(int); /* interrupt handler */
+
+ struct ppb_data *ppb; /* link to the ppbus */
+
+ LIST_ENTRY(ppb_device) chain; /* list of devices on the bus */
+};
+
+/*
+ * Parallel Port Bus Adapter structure.
+ */
+struct ppb_adapter {
+
+ void (*intr_handler)(int);
+ void (*reset_epp_timeout)(int);
+ void (*ecp_sync)(int);
+
+ void (*outsb_epp)(int, char *, int);
+ void (*outsw_epp)(int, char *, int);
+ void (*outsl_epp)(int, char *, int);
+ void (*insb_epp)(int, char *, int);
+ void (*insw_epp)(int, char *, int);
+ void (*insl_epp)(int, char *, int);
+
+ char (*r_dtr)(int);
+ char (*r_str)(int);
+ char (*r_ctr)(int);
+ char (*r_epp)(int);
+ char (*r_ecr)(int);
+ char (*r_fifo)(int);
+
+ void (*w_dtr)(int, char);
+ void (*w_str)(int, char);
+ void (*w_ctr)(int, char);
+ void (*w_epp)(int, char);
+ void (*w_ecr)(int, char);
+ void (*w_fifo)(int, char);
+};
+
+/*
+ * ppb_link structure.
+ */
+struct ppb_link {
+
+ int adapter_unit; /* unit of the adapter */
+
+ int id_irq; /* != 0 if irq enabled */
+ int mode; /* NIBBLE, PS2, EPP, ECP */
+
+#define EPP_1_9 0x0 /* default */
+#define EPP_1_7 0x1
+
+ int epp_protocol; /* EPP protocol: 0=1.9, 1=1.7 */
+
+ struct ppb_adapter *adapter; /* link to the ppc adapter */
+ struct ppb_data *ppbus; /* link to the ppbus */
+};
+
+/*
+ * Parallel Port Bus structure.
+ */
+struct ppb_data {
+
+ struct ppb_link *ppb_link; /* link to the adapter */
+ struct ppb_device *ppb_owner; /* device which owns the bus */
+ LIST_HEAD(, ppb_device) ppb_devs; /* list of devices on the bus */
+ LIST_ENTRY(ppb_data) ppb_chain; /* list of busses */
+};
+
+/*
+ * Parallel Port Bus driver structure.
+ */
+struct ppb_driver
+{
+ struct ppb_device *(*probe)(struct ppb_data *ppb);
+ int (*attach)(struct ppb_device *pdp);
+ char *name;
+};
+
+extern struct linker_set ppbdriver_set;
+
+extern struct ppb_data *ppb_alloc_bus(void);
+extern int ppb_attachdevs(struct ppb_data *);
+extern int ppb_request_bus(struct ppb_device *, int);
+extern int ppb_release_bus(struct ppb_device *);
+extern void ppb_intr(struct ppb_link *);
+
+extern int ppb_reset_epp_timeout(struct ppb_device *);
+extern int ppb_ecp_sync(struct ppb_device *);
+extern int ppb_get_status(struct ppb_device *, struct ppb_status *);
+extern int ppb_get_mode(struct ppb_device *);
+extern int ppb_get_epp_protocol(struct ppb_device *);
+extern int ppb_get_irq(struct ppb_device *);
+
+/*
+ * These are defined as macros for speedup.
+ */
+#define ppb_outsb_epp(dev,buf,cnt) \
+ (*(dev)->ppb->ppb_link->adapter->outsb_epp) \
+ ((dev)->ppb->ppb_link->adapter_unit, buf, cnt)
+#define ppb_outsw_epp(dev,buf,cnt) \
+ (*(dev)->ppb->ppb_link->adapter->outsw_epp) \
+ ((dev)->ppb->ppb_link->adapter_unit, buf, cnt)
+#define ppb_outsl_epp(dev,buf,cnt) \
+ (*(dev)->ppb->ppb_link->adapter->outsl_epp) \
+ ((dev)->ppb->ppb_link->adapter_unit, buf, cnt)
+#define ppb_insb_epp(dev,buf,cnt) \
+ (*(dev)->ppb->ppb_link->adapter->insb_epp) \
+ ((dev)->ppb->ppb_link->adapter_unit, buf, cnt)
+#define ppb_insw_epp(dev,buf,cnt) \
+ (*(dev)->ppb->ppb_link->adapter->insw_epp) \
+ ((dev)->ppb->ppb_link->adapter_unit, buf, cnt)
+#define ppb_insl_epp(dev,buf,cnt) \
+ (*(dev)->ppb->ppb_link->adapter->insl_epp) \
+ ((dev)->ppb->ppb_link->adapter_unit, buf, cnt)
+
+#define ppb_rdtr(dev) (*(dev)->ppb->ppb_link->adapter->r_dtr) \
+ ((dev)->ppb->ppb_link->adapter_unit)
+#define ppb_rstr(dev) (*(dev)->ppb->ppb_link->adapter->r_str) \
+ ((dev)->ppb->ppb_link->adapter_unit)
+#define ppb_rctr(dev) (*(dev)->ppb->ppb_link->adapter->r_ctr) \
+ ((dev)->ppb->ppb_link->adapter_unit)
+#define ppb_repp(dev) (*(dev)->ppb->ppb_link->adapter->r_epp) \
+ ((dev)->ppb->ppb_link->adapter_unit)
+#define ppb_recr(dev) (*(dev)->ppb->ppb_link->adapter->r_ecr) \
+ ((dev)->ppb->ppb_link->adapter_unit)
+#define ppb_rfifo(dev) (*(dev)->ppb->ppb_link->adapter->r_fifo) \
+ ((dev)->ppb->ppb_link->adapter_unit)
+
+#define ppb_wdtr(dev,byte) (*(dev)->ppb->ppb_link->adapter->w_dtr) \
+ ((dev)->ppb->ppb_link->adapter_unit, byte)
+#define ppb_wstr(dev,byte) (*(dev)->ppb->ppb_link->adapter->w_str) \
+ ((dev)->ppb->ppb_link->adapter_unit, byte)
+#define ppb_wctr(dev,byte) (*(dev)->ppb->ppb_link->adapter->w_ctr) \
+ ((dev)->ppb->ppb_link->adapter_unit, byte)
+#define ppb_wepp(dev,byte) (*(dev)->ppb->ppb_link->adapter->w_epp) \
+ ((dev)->ppb->ppb_link->adapter_unit, byte)
+#define ppb_wecr(dev,byte) (*(dev)->ppb->ppb_link->adapter->w_ecr) \
+ ((dev)->ppb->ppb_link->adapter_unit, byte)
+#define ppb_wfifo(dev,byte) (*(dev)->ppb->ppb_link->adapter->w_fifo) \
+ ((dev)->ppb->ppb_link->adapter_unit, byte)
+
+#endif
diff --git a/sys/dev/ppbus/ppi.c b/sys/dev/ppbus/ppi.c
new file mode 100644
index 0000000..79df5b5
--- /dev/null
+++ b/sys/dev/ppbus/ppi.c
@@ -0,0 +1,172 @@
+/*-
+ * Copyright (c) 1997 Nicolas Souchu
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $Id$
+ *
+ */
+#include <sys/types.h>
+
+#ifdef KERNEL
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/proc.h>
+#include <sys/buf.h>
+#include <sys/kernel.h>
+#include <sys/uio.h>
+#include <sys/syslog.h>
+#include <sys/malloc.h>
+
+#include <machine/stdarg.h>
+#include <machine/clock.h>
+
+#include <i386/isa/isa.h>
+#include <i386/isa/isa_device.h>
+
+#include <sys/kernel.h>
+#endif /*KERNEL */
+
+#include <dev/ppbus/ppbconf.h>
+#include <dev/ppbus/ppi.h>
+
+static int nppi = 0;
+#define MAXPPI 8 /* XXX not much better! */
+static struct ppi_data *ppidata[MAXPPI];
+
+/*
+ * Make ourselves visible as a ppbus driver
+ */
+
+static struct ppb_device *ppiprobe(struct ppb_data *ppb);
+static int ppiattach(struct ppb_device *dev);
+static void ppiintr(int unit);
+
+#ifdef KERNEL
+
+static struct ppb_driver ppidriver = {
+ ppiprobe, ppiattach, "ppi"
+};
+DATA_SET(ppbdriver_set, ppidriver);
+
+#endif /* KERNEL */
+
+static d_open_t ppiopen;
+static d_close_t ppiclose;
+static d_ioctl_t ppiioctl;
+
+#define CDEV_MAJOR 14 /* XXX */
+static struct cdevsw ppi_cdevsw =
+ { ppiopen, ppiclose, noread, nowrite,
+ ppiioctl, nullstop, nullreset, nodevtotty,
+ seltrue, nommap, nostrat, "ppi", NULL, -1 };
+
+/*
+ * ppiprobe()
+ */
+static struct ppb_device *
+ppiprobe(struct ppb_data *ppb)
+{
+ struct ppi_data *ppi;
+
+ ppi = (struct ppi_data *) malloc(sizeof(struct ppi_data),
+ M_TEMP, M_NOWAIT);
+ if (!ppi) {
+ printf("ppi: cannot malloc!\n");
+ return 0;
+ }
+ bzero(ppi, sizeof(struct ppi_data));
+
+ ppidata[nppi] = ppi;
+
+ /*
+ * ppi dependent initialisation.
+ */
+ ppi->ppi_unit = nppi;
+
+ /*
+ * ppbus dependent initialisation.
+ */
+ ppi->ppi_dev.id_unit = ppi->ppi_unit;
+ ppi->ppi_dev.ppb = ppb;
+ ppi->ppi_dev.intr = ppiintr;
+
+ /* Ok, go to next device on next probe */
+ nppi ++;
+
+ return &ppi->ppi_dev;
+}
+
+static int
+ppiattach(struct ppb_device *dev)
+{
+ struct ppi_data *ppi = ppidata[dev->id_unit];
+
+ /*
+ * Report ourselves
+ */
+ printf("ppi%d: <generic parallel i/o> on ppbus %d\n",
+ dev->id_unit, dev->ppb->ppb_link->adapter_unit);
+
+ return (1);
+}
+
+static void
+ppiintr(int unit)
+{
+ return;
+}
+
+static int
+ppiopen(dev_t dev, int flags, int fmt, struct proc *p)
+{
+ return (EOPNOTSUPP);
+}
+
+static int
+ppiclose(dev_t dev, int flags, int fmt, struct proc *p)
+{
+ return (EOPNOTSUPP);
+}
+
+static int
+ppiioctl(dev_t dev, int cmd, caddr_t data, int flags, struct proc *p)
+{
+ return (EOPNOTSUPP);
+}
+
+static ppi_devsw_installed = 0;
+
+static void ppi_drvinit(void *unused)
+{
+ dev_t dev;
+
+ if( ! ppi_devsw_installed ) {
+ dev = makedev(CDEV_MAJOR, 0);
+ cdevsw_add(&dev, &ppi_cdevsw, NULL);
+ ppi_devsw_installed = 1;
+ }
+}
+
+SYSINIT(ppidev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE + CDEV_MAJOR, ppi_drvinit, NULL)
diff --git a/sys/dev/ppbus/ppi.h b/sys/dev/ppbus/ppi.h
new file mode 100644
index 0000000..d1a2e1d
--- /dev/null
+++ b/sys/dev/ppbus/ppi.h
@@ -0,0 +1,39 @@
+/*-
+ * Copyright (c) 1997 Nicolas Souchu
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $Id$
+ *
+ */
+#ifndef __PPI_H
+#define __PPI_H
+
+struct ppi_data {
+
+ int ppi_unit;
+
+ struct ppb_device ppi_dev;
+};
+
+#endif
diff --git a/sys/dev/ppbus/vpo.c b/sys/dev/ppbus/vpo.c
new file mode 100644
index 0000000..1cd69be
--- /dev/null
+++ b/sys/dev/ppbus/vpo.c
@@ -0,0 +1,860 @@
+/*-
+ * Copyright (c) 1997 Nicolas Souchu
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $Id$
+ *
+ */
+#include <sys/types.h>
+
+#ifdef KERNEL
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/malloc.h>
+#include <sys/buf.h>
+#include <sys/proc.h>
+#include <sys/syslog.h>
+
+#include <machine/stdarg.h>
+#include <machine/clock.h>
+
+#include <i386/isa/isa_device.h>
+#endif /* KERNEL */
+#include <scsi/scsi_all.h>
+#include <scsi/scsi_disk.h>
+#include <scsi/scsiconf.h>
+
+#ifdef KERNEL
+#include <sys/kernel.h>
+#endif /*KERNEL */
+
+#include <dev/ppbus/ppbconf.h>
+#include <dev/ppbus/vpo.h>
+
+/* --------------------------------------------------------------------
+ * HERE ARE THINGS YOU MAY HAVE/WANT TO CHANGE
+ */
+
+/*
+ * XXX
+ * We may add a timeout queue to avoid active polling on nACK.
+ */
+#define VP0_SELTMO 5000 /* select timeout */
+#define VP0_FAST_SPINTMO 500000 /* wait status timeout */
+#define VP0_LOW_SPINTMO 5000000 /* wait status timeout */
+
+/* XXX
+ * This is ALPHA/BETA code, warnings are mandatory.
+ */
+#ifndef VP0_WARNING
+ #define VP0_WARNING /* defined to get warnings about timeouts,
+ * except select timeouts */
+#endif
+
+/*
+ * DO NOT MODIFY ANYTHING UNDER THIS LINE
+ * --------------------------------------------------------------------
+ */
+
+static inline int vpoio_do_scsi(struct vpo_data *, int, int, char *, int,
+ char *, int, int *, int *);
+
+static int32_t vpo_scsi_cmd(struct scsi_xfer *);
+static void vpominphys(struct buf *);
+static u_int32_t vpo_adapter_info(int);
+
+static int vpo_detect(struct vpo_data *vpo);
+
+static int nvpo = 0;
+#define MAXVP0 8 /* XXX not much better! */
+static struct vpo_data *vpodata[MAXVP0];
+
+#ifdef KERNEL
+static struct scsi_adapter vpo_switch =
+{
+ vpo_scsi_cmd,
+ vpominphys,
+ 0,
+ 0,
+ vpo_adapter_info,
+ "vpo",
+ { 0, 0 }
+};
+
+/*
+ * The below structure is so we have a default dev struct
+ * for out link struct.
+ */
+static struct scsi_device vpo_dev =
+{
+ NULL, /* Use default error handler */
+ NULL, /* have a queue, served by this */
+ NULL, /* have no async handler */
+ NULL, /* Use default 'done' routine */
+ "vpo",
+ 0,
+ { 0, 0 }
+};
+
+
+/*
+ * Make ourselves visible as a ppbus driver
+ */
+
+static struct ppb_device *vpoprobe(struct ppb_data *ppb);
+static int vpoattach(struct ppb_device *dev);
+
+static struct ppb_driver vpodriver = {
+ vpoprobe, vpoattach, "vpo"
+};
+DATA_SET(ppbdriver_set, vpodriver);
+
+
+#endif /* KERNEL */
+
+static u_int32_t
+vpo_adapter_info(int unit)
+{
+
+ return 1;
+}
+
+/*
+ * vpoprobe()
+ *
+ * Called by ppb_attachdevs().
+ */
+static struct ppb_device *
+vpoprobe(struct ppb_data *ppb)
+{
+
+ struct vpo_data *vpo;
+
+ if (nvpo >= MAXVP0) {
+ printf("vpo: Too many devices (max %d)\n", MAXVP0);
+ return(NULL);
+ }
+
+ vpo = (struct vpo_data *)malloc(sizeof(struct vpo_data),
+ M_DEVBUF, M_NOWAIT);
+ if (!vpo) {
+ printf("vpo: cannot malloc!\n");
+ return(NULL);
+ }
+ bzero(vpo, sizeof(struct vpo_data));
+
+ vpodata[nvpo] = vpo;
+
+ /* vpo dependent initialisation */
+ vpo->vpo_unit = nvpo;
+
+ /* ppbus dependent initialisation */
+ vpo->vpo_dev.id_unit = vpo->vpo_unit;
+ vpo->vpo_dev.ppb = ppb;
+
+ /* now, try to initialise the drive */
+ if (vpo_detect(vpo) != 0) {
+ free(vpo, M_DEVBUF);
+ return(NULL);
+ }
+
+ /* ok, go to next device on next probe */
+ nvpo ++;
+
+ return (&vpo->vpo_dev);
+}
+
+/*
+ * vpoattach()
+ *
+ * Called by ppb_attachdevs().
+ */
+static int
+vpoattach(struct ppb_device *dev)
+{
+
+ struct scsibus_data *scbus;
+ struct vpo_data *vpo = vpodata[dev->id_unit];
+
+ vpo->sc_link.adapter_unit = vpo->vpo_unit;
+ vpo->sc_link.adapter_targ = VP0_INITIATOR;
+ vpo->sc_link.adapter = &vpo_switch;
+ vpo->sc_link.device = &vpo_dev;
+ vpo->sc_link.opennings = VP0_OPENNINGS;
+
+ /*
+ * Report ourselves
+ */
+ printf("vpo%d: <Adaptec aic7110 scsi> on ppbus %d\n",
+ dev->id_unit, dev->ppb->ppb_link->adapter_unit);
+
+ /*
+ * Prepare the scsibus_data area for the upperlevel
+ * scsi code.
+ */
+ scbus = scsi_alloc_bus();
+ if(!scbus)
+ return (0);
+ scbus->adapter_link = &vpo->sc_link;
+
+ scsi_attachdevs(scbus);
+
+ return (1);
+}
+
+static void
+vpominphys(struct buf *bp)
+{
+
+ if (bp->b_bcount > VP0_BUFFER_SIZE)
+ bp->b_bcount = VP0_BUFFER_SIZE;
+
+ return;
+}
+
+#ifdef VP0_WARNING
+static inline void
+vpo_warning(struct vpo_data *vpo, struct scsi_xfer *xs, int timeout)
+{
+
+ switch (timeout) {
+ case 0:
+ case VP0_ESELECT_TIMEOUT:
+ /* log(LOG_WARNING,
+ "vpo%d: select timeout\n", vpo->vpo_unit); */
+ break;
+ case VP0_EDISCONNECT:
+ log(LOG_WARNING,
+ "vpo%d: can't get printer state\n", vpo->vpo_unit);
+ break;
+ case VP0_ECONNECT:
+ log(LOG_WARNING,
+ "vpo%d: can't get disk state\n", vpo->vpo_unit);
+ break;
+ case VP0_ECMD_TIMEOUT:
+ log(LOG_WARNING,
+ "vpo%d: command timeout\n", vpo->vpo_unit);
+ break;
+ case VP0_EPPDATA_TIMEOUT:
+ log(LOG_WARNING,
+ "vpo%d: EPP data timeout\n", vpo->vpo_unit);
+ break;
+ case VP0_ESTATUS_TIMEOUT:
+ log(LOG_WARNING,
+ "vpo%d: status timeout\n", vpo->vpo_unit);
+ break;
+ case VP0_EDATA_OVERFLOW:
+ log(LOG_WARNING,
+ "vpo%d: data overflow\n", vpo->vpo_unit);
+ break;
+ case VP0_EINTR:
+ log(LOG_WARNING,
+ "vpo%d: ppb request interrupted\n", vpo->vpo_unit);
+ break;
+ default:
+ log(LOG_WARNING,
+ "vpo%d: timeout = %d\n", vpo->vpo_unit, timeout);
+ break;
+ }
+}
+#endif /* VP0_WARNING */
+
+/*
+ * vpointr()
+ */
+static inline void
+vpointr(struct vpo_data *vpo, struct scsi_xfer *xs)
+{
+
+ register int timeout;
+
+ if (xs->datalen && !(xs->flags & SCSI_DATA_IN))
+ bcopy(xs->data, vpo->vpo_buffer, xs->datalen);
+
+ timeout = vpoio_do_scsi(vpo, VP0_INITIATOR,
+ xs->sc_link->target,
+ (char *)xs->cmd, xs->cmdlen,
+ vpo->vpo_buffer, xs->datalen,
+ &vpo->vpo_stat, &vpo->vpo_count);
+
+#ifdef VP0_WARNING
+ vpo_warning(vpo, xs, timeout);
+#endif
+
+#ifdef VP03_DEBUG
+ printf("vpo_do_scsi = %d, status = 0x%x, count = %d\n",
+ timeout, vpo->vpo_stat, vpo->vpo_count);
+#endif
+
+#define RESERVED_BITS_MASK 0x3e /* 00111110b */
+#define NO_SENSE 0x0
+#define CHECK_CONDITION 0x02
+
+ switch (vpo->vpo_stat & RESERVED_BITS_MASK) {
+ case NO_SENSE:
+ break;
+
+ case CHECK_CONDITION:
+ default:
+ vpo->vpo_sense.cmd.op_code = REQUEST_SENSE;
+ vpo->vpo_sense.cmd.length = sizeof(xs->sense);
+ vpo->vpo_sense.cmd.control = 0;
+
+ timeout = vpoio_do_scsi(vpo, VP0_INITIATOR,
+ xs->sc_link->target,
+ (char *)&vpo->vpo_sense.cmd,
+ sizeof(vpo->vpo_sense.cmd),
+ (char *)&xs->sense, sizeof(xs->sense),
+ &vpo->vpo_sense.stat, &vpo->vpo_sense.count);
+
+ xs->error = XS_SENSE;
+ goto error;
+ }
+
+ if (timeout) {
+ xs->error = XS_TIMEOUT;
+ goto error;
+ }
+
+ if (xs->datalen && (xs->flags & SCSI_DATA_IN))
+ bcopy(vpo->vpo_buffer, xs->data, xs->datalen);
+
+done:
+ xs->resid = 0;
+ xs->error = XS_NOERROR;
+
+error:
+ xs->flags |= ITSDONE;
+ scsi_done(xs);
+
+ return;
+}
+
+static int32_t
+vpo_scsi_cmd(struct scsi_xfer *xs)
+{
+
+ int s;
+
+ if (xs->sc_link->lun > 0) {
+ xs->error = XS_DRIVER_STUFFUP;
+ return TRY_AGAIN_LATER;
+ }
+
+ if (xs->flags & SCSI_DATA_UIO) {
+ printf("UIO not supported by vpo_driver !\n");
+ xs->error = XS_DRIVER_STUFFUP;
+ return TRY_AGAIN_LATER;
+ }
+
+#ifdef VP03_DEBUG
+ printf("vpo_scsi_cmd(): xs->flags = 0x%x, "\
+ "xs->data = 0x%x, xs->datalen = %d\ncommand : %*D\n",
+ xs->flags, xs->data, xs->datalen,
+ xs->cmdlen, xs->cmd, " " );
+#endif
+
+ if (xs->flags & SCSI_NOMASK) {
+ vpointr(vpodata[xs->sc_link->adapter_unit], xs);
+ return COMPLETE;
+ }
+
+ s = VP0_SPL();
+
+ vpointr(vpodata[xs->sc_link->adapter_unit], xs);
+
+ splx(s);
+ return SUCCESSFULLY_QUEUED;
+}
+
+#define vpoio_d_pulse(vpo,b) { \
+ ppb_wdtr(&(vpo)->vpo_dev, b); \
+ ppb_wctr(&(vpo)->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE); \
+ ppb_wctr(&(vpo)->vpo_dev, H_nAUTO | H_nSELIN | H_INIT | H_STROBE); \
+ ppb_wctr(&(vpo)->vpo_dev, H_nAUTO | H_nSELIN | H_INIT | H_STROBE); \
+ ppb_wctr(&(vpo)->vpo_dev, H_nAUTO | H_nSELIN | H_INIT | H_STROBE); \
+ ppb_wctr(&(vpo)->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE); \
+ ppb_wctr(&(vpo)->vpo_dev, H_AUTO | H_SELIN | H_INIT | H_STROBE); \
+ ppb_wctr(&(vpo)->vpo_dev, H_AUTO | H_SELIN | H_INIT | H_STROBE); \
+ ppb_wctr(&(vpo)->vpo_dev, H_AUTO | H_SELIN | H_INIT | H_STROBE); \
+ ppb_wctr(&(vpo)->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE); \
+ ppb_wctr(&(vpo)->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE); \
+ ppb_wctr(&(vpo)->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE); \
+}
+
+#define vpoio_c_pulse(vpo,b) { \
+ ppb_wdtr(&(vpo)->vpo_dev, b); \
+ ppb_wctr(&(vpo)->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE); \
+ ppb_wctr(&(vpo)->vpo_dev, H_AUTO | H_SELIN | H_INIT | H_STROBE); \
+ ppb_wctr(&(vpo)->vpo_dev, H_nAUTO | H_SELIN | H_INIT | H_STROBE); \
+ ppb_wctr(&(vpo)->vpo_dev, H_nAUTO | H_SELIN | H_INIT | H_STROBE); \
+ ppb_wctr(&(vpo)->vpo_dev, H_nAUTO | H_SELIN | H_INIT | H_STROBE); \
+ ppb_wctr(&(vpo)->vpo_dev, H_AUTO | H_SELIN | H_INIT | H_STROBE); \
+ ppb_wctr(&(vpo)->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE); \
+ ppb_wctr(&(vpo)->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE); \
+ ppb_wctr(&(vpo)->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE); \
+}
+
+static int
+vpoio_disconnect(struct vpo_data *vpo)
+{
+
+ vpoio_d_pulse(vpo, 0);
+ vpoio_d_pulse(vpo, 0x3c);
+ vpoio_d_pulse(vpo, 0x20);
+ vpoio_d_pulse(vpo, 0xf);
+
+ return (ppb_release_bus(&vpo->vpo_dev));
+}
+
+/*
+ * how : PPB_WAIT or PPB_DONTWAIT
+ */
+static int
+vpoio_connect(struct vpo_data *vpo, int how)
+{
+ int error;
+
+ if ((error = ppb_request_bus(&vpo->vpo_dev, how)))
+ return error;
+
+ vpoio_c_pulse(vpo, 0);
+ vpoio_c_pulse(vpo, 0x3c);
+ vpoio_c_pulse(vpo, 0x20);
+
+ if (PPB_IN_EPP_MODE(&vpo->vpo_dev)) {
+ vpoio_c_pulse(vpo, 0xcf);
+ } else {
+ vpoio_c_pulse(vpo, 0x8f);
+ }
+
+ return (0);
+}
+
+/*
+ * vpoio_in_disk_mode()
+ *
+ * Check if we are in disk mode
+ */
+static int
+vpoio_in_disk_mode(struct vpo_data *vpo)
+{
+
+ /* first, set H_AUTO high */
+ ppb_wctr(&vpo->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE);
+
+ /* when H_AUTO is set low, H_FLT should be high */
+ ppb_wctr(&vpo->vpo_dev, H_nAUTO | H_nSELIN | H_INIT | H_STROBE);
+ if ((ppb_rstr(&vpo->vpo_dev) & H_FLT) == 0)
+ return (0);
+
+ /* when H_AUTO is set high, H_FLT should be low */
+ ppb_wctr(&vpo->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE);
+ if ((ppb_rstr(&vpo->vpo_dev) & H_FLT) != 0)
+ return (0);
+
+ return (1);
+}
+
+/*
+ * vpoio_reset()
+ *
+ * SCSI reset signal, the drive must be in disk mode
+ */
+static void
+vpoio_reset (struct vpo_data *vpo)
+{
+
+ /*
+ * SCSI reset signal.
+ */
+ ppb_wdtr(&vpo->vpo_dev, (1 << 7));
+ ppb_wctr(&vpo->vpo_dev, H_AUTO | H_nSELIN | H_nINIT | H_STROBE);
+ DELAY(25);
+ ppb_wctr(&vpo->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE);
+
+ return;
+}
+
+
+/*
+ * vpo_detect()
+ *
+ * Detect and initialise the VP0 adapter.
+ */
+static int
+vpo_detect(struct vpo_data *vpo)
+{
+
+ vpoio_disconnect(vpo);
+ vpoio_connect(vpo, PPB_DONTWAIT);
+
+ if (!vpoio_in_disk_mode(vpo)) {
+ vpoio_disconnect(vpo);
+ return (VP0_EINITFAILED);
+ }
+
+ /* send SCSI reset signal */
+ vpoio_reset (vpo);
+
+ vpoio_disconnect(vpo);
+
+ if (vpoio_in_disk_mode(vpo))
+ return (VP0_EINITFAILED);
+
+ return (0);
+}
+
+#define vpo_wctr(dev,byte,delay) { \
+ int i; int iter = delay / MHZ_16_IO_DURATION; \
+ for (i = 0; i < iter; i++) { \
+ ppb_wctr(dev, byte); \
+ } \
+}
+
+#define vpoio_spp_outbyte(vpo,byte) { \
+ ppb_wdtr(&vpo->vpo_dev, byte); \
+ ppb_wctr(&vpo->vpo_dev, H_nAUTO | H_nSELIN | H_INIT | H_STROBE); \
+ vpo_wctr(&vpo->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE, \
+ VP0_SPP_WRITE_PULSE); \
+}
+
+#define vpoio_nibble_inbyte(vpo,buffer) { \
+ register char h, l; \
+ vpo_wctr(&vpo->vpo_dev, H_AUTO | H_SELIN | H_INIT | H_STROBE, \
+ VP0_NIBBLE_READ_PULSE); \
+ h = ppb_rstr(&vpo->vpo_dev); \
+ ppb_wctr(&vpo->vpo_dev, H_nAUTO | H_SELIN | H_INIT | H_STROBE); \
+ l = ppb_rstr(&vpo->vpo_dev); \
+ *buffer = ((l >> 4) & 0x0f) + (h & 0xf0); \
+}
+
+#define vpoio_ps2_inbyte(vpo,buffer) { \
+ *buffer = ppb_rdtr(&vpo->vpo_dev); \
+ ppb_wctr(&vpo->vpo_dev, PCD | H_nAUTO | H_SELIN | H_INIT | H_nSTROBE); \
+ ppb_wctr(&vpo->vpo_dev, PCD | H_AUTO | H_SELIN | H_INIT | H_nSTROBE); \
+}
+
+/*
+ * vpoio_outstr()
+ */
+static int
+vpoio_outstr(struct vpo_data *vpo, char *buffer, int size)
+{
+
+ register int k;
+ int error = 0;
+ int r, mode, epp;
+
+ mode = ppb_get_mode(&vpo->vpo_dev);
+ switch (mode) {
+ case PPB_NIBBLE:
+ case PPB_PS2:
+ for (k = 0; k < size; k++) {
+ vpoio_spp_outbyte(vpo, *buffer++);
+ }
+ break;
+
+ case PPB_EPP:
+ case PPB_ECP_EPP:
+ epp = ppb_get_epp_protocol(&vpo->vpo_dev);
+
+ ppb_reset_epp_timeout(&vpo->vpo_dev);
+ ppb_wctr(&vpo->vpo_dev,
+ H_AUTO | H_SELIN | H_INIT | H_STROBE);
+
+ if (epp == EPP_1_7)
+ for (k = 0; k < size; k++) {
+ ppb_wepp(&vpo->vpo_dev, *buffer++);
+ if ((ppb_rstr(&vpo->vpo_dev) & TIMEOUT)) {
+ error = VP0_EPPDATA_TIMEOUT;
+ break;
+ }
+ }
+ else {
+ if (((long) buffer | size) & 0x03)
+ ppb_outsb_epp(&vpo->vpo_dev,
+ buffer, size);
+ else
+ ppb_outsl_epp(&vpo->vpo_dev,
+ buffer, size/4);
+
+ if ((ppb_rstr(&vpo->vpo_dev) & TIMEOUT)) {
+ error = VP0_EPPDATA_TIMEOUT;
+ break;
+ }
+ }
+ ppb_wctr(&vpo->vpo_dev,
+ H_AUTO | H_nSELIN | H_INIT | H_STROBE);
+ /* ppb_ecp_sync(&vpo->vpo_dev); */
+ break;
+
+ default:
+ printf("vpoio_outstr(): unknown transfer mode (%d)!\n",
+ mode);
+ return (1); /* XXX */
+ }
+
+ return (error);
+}
+
+/*
+ * vpoio_instr()
+ */
+static int
+vpoio_instr(struct vpo_data *vpo, char *buffer, int size)
+{
+
+ register int k;
+ int error = 0;
+ int r, mode, epp;
+
+ mode = ppb_get_mode(&vpo->vpo_dev);
+ switch (mode) {
+ case PPB_NIBBLE:
+ for (k = 0; k < size; k++) {
+ vpoio_nibble_inbyte(vpo, buffer++);
+ }
+ ppb_wctr(&vpo->vpo_dev,
+ H_AUTO | H_nSELIN | H_INIT | H_STROBE);
+ break;
+
+ case PPB_PS2:
+ ppb_wctr(&vpo->vpo_dev, PCD |
+ H_AUTO | H_SELIN | H_INIT | H_nSTROBE);
+
+ for (k = 0; k < size; k++) {
+ vpoio_ps2_inbyte(vpo, buffer++);
+ }
+ ppb_wctr(&vpo->vpo_dev,
+ H_AUTO | H_nSELIN | H_INIT | H_STROBE);
+ break;
+
+ case PPB_EPP:
+ case PPB_ECP_EPP:
+ epp = ppb_get_epp_protocol(&vpo->vpo_dev);
+
+ ppb_reset_epp_timeout(&vpo->vpo_dev);
+ ppb_wctr(&vpo->vpo_dev, PCD |
+ H_AUTO | H_SELIN | H_INIT | H_STROBE);
+
+ if (epp == EPP_1_7)
+ for (k = 0; k < size; k++) {
+ *buffer++ = ppb_repp(&vpo->vpo_dev);
+ if ((ppb_rstr(&vpo->vpo_dev) & TIMEOUT)) {
+ error = VP0_EPPDATA_TIMEOUT;
+ break;
+ }
+ }
+ else {
+ if (((long) buffer | size) & 0x03)
+ ppb_insb_epp(&vpo->vpo_dev,
+ buffer, size);
+ else
+ ppb_insl_epp(&vpo->vpo_dev,
+ buffer, size/4);
+
+ if ((ppb_rstr(&vpo->vpo_dev) & TIMEOUT)) {
+ error = VP0_EPPDATA_TIMEOUT;
+ break;
+ }
+ }
+ ppb_wctr(&vpo->vpo_dev, PCD |
+ H_AUTO | H_nSELIN | H_INIT | H_STROBE);
+ /* ppb_ecp_sync(&vpo->vpo_dev); */
+ break;
+
+ default:
+ printf("vpoio_instr(): unknown transfer mode (%d)!\n",
+ mode);
+ return (1); /* XXX */
+ }
+
+ return (error);
+}
+
+static inline char
+vpoio_select(struct vpo_data *vpo, int initiator, int target)
+{
+
+ register int k;
+
+ ppb_wdtr(&vpo->vpo_dev, (1 << target));
+ ppb_wctr(&vpo->vpo_dev, H_nAUTO | H_nSELIN | H_INIT | H_STROBE);
+ ppb_wctr(&vpo->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE);
+ ppb_wdtr(&vpo->vpo_dev, (1 << initiator));
+ ppb_wctr(&vpo->vpo_dev, H_AUTO | H_nSELIN | H_nINIT | H_STROBE);
+
+ k = 0;
+ while (!(ppb_rstr(&vpo->vpo_dev) & 0x40) && (k++ < VP0_SELTMO))
+ barrier();
+
+ if (k >= VP0_SELTMO)
+ return (VP0_ESELECT_TIMEOUT);
+
+ return (0);
+}
+
+/*
+ * vpoio_wait()
+ *
+ * H_SELIN must be low.
+ */
+static inline char
+vpoio_wait(struct vpo_data *vpo, int tmo)
+{
+
+ register int k;
+ register char r;
+
+ k = 0;
+ while (!((r = ppb_rstr(&vpo->vpo_dev)) & 0x80) && (k++ < tmo))
+ barrier();
+
+ /*
+ * Return some status information.
+ * Semantics : 0xc0 = ZIP wants more data
+ * 0xd0 = ZIP wants to send more data
+ * 0xe0 = ZIP wants command
+ * 0xf0 = end of transfer, ZIP is sending status
+ */
+ if (k < tmo)
+ return (r & 0xf0);
+
+ return (0); /* command timed out */
+}
+
+static inline int
+vpoio_do_scsi(struct vpo_data *vpo, int host, int target, char *command,
+ int clen, char *buffer, int blen, int *result, int *count)
+{
+
+ register char r;
+ char l, h = 0;
+ int rw, len, error = 0;
+ register int k;
+
+ /* enter disk state, allocate the ppbus */
+ vpoio_connect(vpo, PPB_WAIT | PPB_NOINTR);
+
+ if (!vpoio_in_disk_mode(vpo)) {
+ error = VP0_ECONNECT; goto error;
+ }
+
+ if ((error = vpoio_select(vpo,host,target)))
+ goto error;
+
+ /*
+ * Send the command ...
+ *
+ * set H_SELIN low for vpoio_wait().
+ */
+ ppb_wctr(&vpo->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE);
+
+#ifdef VP03_DEBUG
+ printf("vpo%d: drive selected, now sending the command...\n",
+ vpo->vpo_unit);
+#endif
+
+ for (k = 0; k < clen; k++) {
+ if (vpoio_wait(vpo, VP0_FAST_SPINTMO) != (char)0xe0) {
+ error = VP0_ECMD_TIMEOUT;
+ goto error;
+ }
+ if (vpoio_outstr(vpo, &command[k], 1)) {
+ error = VP0_EPPDATA_TIMEOUT;
+ goto error;
+ }
+ }
+
+#ifdef VP03_DEBUG
+ printf("vpo%d: command sent, now completing the request...\n",
+ vpo->vpo_unit);
+#endif
+
+ /*
+ * Completion ...
+ */
+ rw = ((command[0] == READ_COMMAND) || (command[0] == READ_BIG) ||
+ (command[0] == WRITE_COMMAND) || (command[0] == WRITE_BIG));
+
+ *count = 0;
+ for (;;) {
+
+ if (!(r = vpoio_wait(vpo, VP0_LOW_SPINTMO))) {
+ error = VP0_ESTATUS_TIMEOUT; goto error;
+ }
+
+ /* stop when the ZIP wants to send status */
+ if (r == (char)0xf0)
+ break;
+
+ if (*count >= blen) {
+ error = VP0_EDATA_OVERFLOW;
+ goto error;
+ }
+ len = (rw && ((blen - *count) >= VP0_SECTOR_SIZE)) ?
+ VP0_SECTOR_SIZE : 1;
+
+ /* ZIP wants to send data? */
+ if (r == (char)0xc0)
+ error = vpoio_outstr(vpo, &buffer[*count], len);
+ else
+ error = vpoio_instr(vpo, &buffer[*count], len);
+
+ if (error)
+ goto error;
+
+ *count += len;
+ }
+
+ if (vpoio_instr(vpo, &l, 1)) {
+ error = VP0_EOTHER; goto error;
+ }
+
+ /* check if the ZIP wants to send more status */
+ if (vpoio_wait(vpo, VP0_FAST_SPINTMO) == (char)0xf0)
+ if (vpoio_instr(vpo, &h, 1)) {
+ error = VP0_EOTHER+2; goto error;
+ }
+
+ /* return to printer state */
+ vpoio_disconnect(vpo);
+
+#if 0
+ if (vpoio_in_disk_mode(vpo)) {
+ vpoio_reset (vpo);
+ error = VP0_EDISCONNECT; goto error;
+ }
+#endif
+
+ *result = ((int) h << 8) | ((int) l & 0xff);
+
+ return (0);
+
+error:
+ vpoio_disconnect(vpo);
+ return (error);
+}
diff --git a/sys/dev/ppbus/vpo.h b/sys/dev/ppbus/vpo.h
new file mode 100644
index 0000000..582538f
--- /dev/null
+++ b/sys/dev/ppbus/vpo.h
@@ -0,0 +1,109 @@
+/*-
+ * Copyright (c) 1997 Nicolas Souchu
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $Id$
+ *
+ */
+#ifndef __VP03_H
+#define __VP03_H
+
+#define barrier() __asm__("": : :"memory")
+
+#define VP0_INITIATOR 0x7
+
+#define VP0_SECTOR_SIZE 512
+#define VP0_BUFFER_SIZE 0x12000
+
+#define VP0_SPL() splbio()
+
+#define VP0_ESELECT_TIMEOUT 1
+#define VP0_ECMD_TIMEOUT 2
+#define VP0_ECONNECT 3
+#define VP0_ESTATUS_TIMEOUT 4
+#define VP0_EDATA_OVERFLOW 5
+#define VP0_EDISCONNECT 6
+#define VP0_EPPDATA_TIMEOUT 7
+#define VP0_ENOPORT 9
+#define VP0_EINITFAILED 10
+#define VP0_EINTR 12
+
+#define VP0_EOTHER 13
+
+#define VP0_OPENNINGS 1
+
+#define n(flags) (~(flags) & (flags))
+
+/*
+ * VP0 timings.
+ */
+#define MHZ_16_IO_DURATION 62
+
+#define VP0_SPP_WRITE_PULSE 253
+#define VP0_NIBBLE_READ_PULSE 486
+
+/*
+ * VP0 connections.
+ */
+#define H_AUTO n(AUTOFEED)
+#define H_nAUTO AUTOFEED
+#define H_STROBE n(STROBE)
+#define H_nSTROBE STROBE
+#define H_BSY n(nBUSY)
+#define H_nBSY n_BUSY
+#define H_SEL SELECT
+#define H_nSEL n(SELECT)
+#define H_ERR ERROR
+#define H_nERR n(ERROR)
+#define H_ACK nACK
+#define H_nACK n(nACK)
+#define H_FLT nFAULT
+#define H_nFLT n(nFAULT)
+#define H_SELIN n(SELECTIN)
+#define H_nSELIN SELECTIN
+#define H_INIT nINIT
+#define H_nINIT n(nINIT)
+
+struct vpo_sense {
+ struct scsi_sense cmd;
+ unsigned int stat;
+ unsigned int count;
+};
+
+struct vpo_data {
+ unsigned short vpo_unit;
+
+ int vpo_stat;
+ int vpo_count;
+
+ struct ppb_status vpo_status;
+ struct vpo_sense vpo_sense;
+
+ unsigned char vpo_buffer[VP0_BUFFER_SIZE];
+
+ struct ppb_device vpo_dev;
+ struct scsi_link sc_link;
+};
+
+#endif
OpenPOWER on IntegriCloud