summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormsmith <msmith@FreeBSD.org>1997-08-16 14:05:38 +0000
committermsmith <msmith@FreeBSD.org>1997-08-16 14:05:38 +0000
commit4e86e1b8146d6d3db414343b88c3dd0a70c3f3e8 (patch)
tree872dbe7ecf3974deb2f497cb3182cb26f1059975
parent1899bf201a04592fed57f354db459ee66c21bbaa (diff)
downloadFreeBSD-src-4e86e1b8146d6d3db414343b88c3dd0a70c3f3e8.zip
FreeBSD-src-4e86e1b8146d6d3db414343b88c3dd0a70c3f3e8.tar.gz
Sync with ppbus-970815 from the author :
- interrupt-driven printing now works (nlpt) - Rearrangement of bus-related functions into ppb_base/ppbconf - Addition of ieee1284 interface functions, preliminary parallel-port PnP support Submitted by: Nicolas Souchu <Nicolas.Souchu@prism.uvsq.fr>
-rw-r--r--sys/dev/ppbus/nlpt.c99
-rw-r--r--sys/dev/ppbus/nlpt.h7
-rw-r--r--sys/dev/ppbus/ppb_1284.c163
-rw-r--r--sys/dev/ppbus/ppb_1284.h40
-rw-r--r--sys/dev/ppbus/ppb_base.c210
-rw-r--r--sys/dev/ppbus/ppbconf.c381
-rw-r--r--sys/dev/ppbus/ppbconf.h35
-rw-r--r--sys/dev/ppbus/ppi.c83
-rw-r--r--sys/dev/ppbus/vpo.c124
-rw-r--r--sys/dev/ppbus/vpo.h3
10 files changed, 900 insertions, 245 deletions
diff --git a/sys/dev/ppbus/nlpt.c b/sys/dev/ppbus/nlpt.c
index 6e35a12..8e9ed39 100644
--- a/sys/dev/ppbus/nlpt.c
+++ b/sys/dev/ppbus/nlpt.c
@@ -47,7 +47,7 @@
*
* from: unknown origin, 386BSD 0.1
* From Id: lpt.c,v 1.55.2.1 1996/11/12 09:08:38 phk Exp
- * $Id$
+ * $Id: nlpt.c,v 1.1 1997/08/14 13:57:40 msmith Exp $
*/
/*
@@ -71,6 +71,9 @@
#include <sys/kernel.h>
#include <sys/uio.h>
#include <sys/syslog.h>
+#ifdef DEVFS
+#include <sys/devfsext.h>
+#endif /*DEVFS*/
#include <sys/malloc.h>
#include <machine/stdarg.h>
@@ -86,7 +89,7 @@
#include <dev/ppbus/ppbconf.h>
#include <dev/ppbus/nlpt.h>
-#ifndef DEBUG
+#ifndef NLPT_DEBUG
#define nlprintf (void)
#else
#define nlprintf if (nlptflag) printf
@@ -133,6 +136,8 @@ DATA_SET(ppbdriver_set, nlptdriver);
#define INIT (1<<6) /* waiting to initialize for open */
#define INTERRUPTED (1<<7) /* write call was interrupted */
+#define HAVEBUS (1<<8) /* the driver owns the bus */
+
/* status masks to interrogate printer status */
#define RDY_MASK (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR) /* ready ? */
@@ -158,6 +163,20 @@ static struct cdevsw nlpt_cdevsw =
nlptioctl, nullstop, nullreset, nodevtotty,/* lpt */
seltrue, nommap, nostrat, "nlpt", NULL, -1 };
+static int
+lpt_request_ppbus(struct lpt_data *lpt, int how)
+{
+ lpt->sc_state |= HAVEBUS;
+ return (ppb_request_bus(&lpt->lpt_dev, how));
+}
+
+static int
+lpt_release_ppbus(struct lpt_data *lpt)
+{
+ lpt->sc_state &= ~HAVEBUS;
+ return (ppb_release_bus(&lpt->lpt_dev));
+}
+
/*
* Internal routine to nlptprobe to do port tests of one byte value
*/
@@ -228,12 +247,12 @@ nlpt_detect(struct lpt_data *lpt)
int status;
u_char data;
u_char mask;
- int i;
+ int i, error;
status = IO_LPTSIZE;
- if (ppb_request_bus(&lpt->lpt_dev, PPB_DONTWAIT)) {
- printf("nlpt: cannot alloc ppbus!\n");
+ if ((error = lpt_request_ppbus(lpt, PPB_DONTWAIT))) {
+ printf("nlpt: cannot alloc ppbus (%d)!\n", error);
status = 0 ; goto end_probe ;
}
@@ -263,7 +282,7 @@ end_probe:
ppb_wdtr(&lpt->lpt_dev, 0);
ppb_wctr(&lpt->lpt_dev, 0);
- ppb_release_bus(&lpt->lpt_dev);
+ lpt_release_ppbus(lpt);
return (status);
}
@@ -316,6 +335,7 @@ static int
nlptattach(struct ppb_device *dev)
{
struct lpt_data *lpt = lptdata[dev->id_unit];
+ int error;
/*
* Report ourselves
@@ -325,8 +345,8 @@ nlptattach(struct ppb_device *dev)
lpt->sc_primed = 0; /* not primed yet */
- if (ppb_request_bus(&lpt->lpt_dev, PPB_DONTWAIT)) {
- printf("nlpt: cannot alloc ppbus!\n");
+ if ((error = lpt_request_ppbus(lpt, PPB_DONTWAIT))) {
+ printf("nlpt: cannot alloc ppbus (%d)!\n", error);
return (0);
}
@@ -343,7 +363,17 @@ nlptattach(struct ppb_device *dev)
}
nlprintf("irq %x\n", lpt->sc_irq);
- ppb_release_bus(&lpt->lpt_dev);
+ lpt_release_ppbus(lpt);
+
+#ifdef DEVFS
+ /* XXX what to do about the flags in the minor number? */
+ sc->devfs_token = devfs_add_devswf(&nlpt_cdevsw,
+ unit, DV_CHR,
+ UID_ROOT, GID_WHEEL, 0600, "nlpt%d", unit);
+ sc->devfs_token_ctl = devfs_add_devswf(&nlpt_cdevsw,
+ unit | LP_BYPASS, DV_CHR,
+ UID_ROOT, GID_WHEEL, 0600, "lpctl%d", unit);
+#endif
return (1);
}
@@ -368,6 +398,19 @@ nlptout(struct lpt_data *lpt)
* Avoid possible hangs do to missed interrupts
*/
if (lpt->sc_xfercnt) {
+ /* if we cannot allocate the bus NOW, retry later */
+ if ((lpt->sc_state & HAVEBUS) == 0 &&
+ lpt_request_ppbus (lpt, PPB_DONTWAIT)) {
+
+ 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);
+ return;
+ }
+
pl = spltty();
nlptintr(lpt->lpt_unit);
splx(pl);
@@ -375,8 +418,6 @@ nlptout(struct lpt_data *lpt)
lpt->sc_state &= ~OBUSY;
wakeup((caddr_t)lpt);
}
-
- ppb_release_bus(&lpt->lpt_dev);
}
/*
@@ -399,9 +440,6 @@ nlptopen(dev_t dev, int flags, int fmt, struct proc *p)
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);
@@ -416,6 +454,9 @@ nlptopen(dev_t dev, int flags, int fmt, struct proc *p)
return(0);
}
+ if (lpt_request_ppbus(lpt, PPB_WAIT|PPB_INTR))
+ return (EINTR);
+
s = spltty();
nlprintf("nlpt flags 0x%x\n", lpt->sc_flags);
@@ -445,7 +486,7 @@ nlptopen(dev_t dev, int flags, int fmt, struct proc *p)
lpt->sc_state = 0;
nlprintf ("status %x\n", ppb_rstr(&lpt->lpt_dev) );
- ppb_release_bus(&lpt->lpt_dev);
+ lpt_release_ppbus(lpt);
return (EBUSY);
}
@@ -455,7 +496,7 @@ nlptopen(dev_t dev, int flags, int fmt, struct proc *p)
lpt->sc_state = 0;
splx(s);
- ppb_release_bus(&lpt->lpt_dev);
+ lpt_release_ppbus(lpt);
return (EBUSY);
}
@@ -479,14 +520,16 @@ nlptopen(dev_t dev, int flags, int fmt, struct proc *p)
lpt->sc_xfercnt = 0;
splx(s);
+ /* release the bus, nlptout() will try to allocate it later */
+ lpt_release_ppbus(lpt);
+
/* 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);
@@ -502,12 +545,14 @@ static int
nlptclose(dev_t dev, int flags, int fmt, struct proc *p)
{
struct lpt_data *lpt = lptdata[LPTUNIT(minor(dev))];
+ int err;
if(lpt->sc_flags & LP_BYPASS)
goto end_close;
- if (ppb_request_bus(&lpt->lpt_dev, PPB_WAIT|PPB_INTR))
- return (EINTR);
+ if ((lpt->sc_state & HAVEBUS) == 0 &&
+ (err = lpt_request_ppbus(lpt, PPB_WAIT|PPB_INTR)))
+ return (err);
lpt->sc_state &= ~OPEN;
@@ -524,7 +569,7 @@ nlptclose(dev_t dev, int flags, int fmt, struct proc *p)
ppb_wctr(&lpt->lpt_dev, LPC_NINIT);
brelse(lpt->sc_inbuf);
- ppb_release_bus(&lpt->lpt_dev);
+ lpt_release_ppbus(lpt);
end_close:
lpt->sc_state = 0;
@@ -612,7 +657,7 @@ nlptwrite(dev_t dev, struct uio *uio, int ioflag)
return(EPERM);
}
- if (ppb_request_bus(&lpt->lpt_dev, PPB_WAIT|PPB_INTR))
+ if (lpt_request_ppbus(lpt, PPB_WAIT|PPB_INTR))
return (EINTR);
lpt->sc_state &= ~INTERRUPTED;
@@ -641,11 +686,13 @@ nlptwrite(dev_t dev, struct uio *uio, int ioflag)
/* 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)))
+
+ err = nlpt_pushbytes(lpt);
+ lpt_release_ppbus(lpt);
+
+ if (err)
return(err);
}
-
- ppb_release_bus(&lpt->lpt_dev);
}
return(0);
}
@@ -694,6 +741,8 @@ nlptintr(int unit)
* Wakeup is not done if write call was interrupted.
*/
lpt->sc_state &= ~OBUSY;
+ lpt_release_ppbus(lpt);
+
if(!(lpt->sc_state & INTERRUPTED))
wakeup((caddr_t)lpt);
nlprintf("w ");
diff --git a/sys/dev/ppbus/nlpt.h b/sys/dev/ppbus/nlpt.h
index 85f3dce..b0b3df6 100644
--- a/sys/dev/ppbus/nlpt.h
+++ b/sys/dev/ppbus/nlpt.h
@@ -27,7 +27,7 @@
* @(#)lptreg.h 1.1 (Berkeley) 12/19/90
* Id: lptreg.h,v 1.6 1997/02/22 09:36:52 peter Exp
*
- * $Id$
+ * $Id: nlpt.h,v 1.1 1997/08/14 13:57:40 msmith Exp $
*/
#ifndef __NLPT_H
#define __NLPT_H
@@ -69,6 +69,11 @@ struct lpt_data {
#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 */
+
+#ifdef DEVFS
+ void *devfs_token;
+ void *devfs_token_ctl;
+#endif
};
#endif
diff --git a/sys/dev/ppbus/ppb_1284.c b/sys/dev/ppbus/ppb_1284.c
new file mode 100644
index 0000000..5fef52a
--- /dev/null
+++ b/sys/dev/ppbus/ppb_1284.c
@@ -0,0 +1,163 @@
+/*-
+ * 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 <dev/ppbus/ppbconf.h>
+#include <dev/ppbus/ppb_1284.h>
+
+/*
+ * nibble_1284_wait()
+ *
+ * Wait for the peripherial up to 40ms
+ */
+int
+nibble_1284_wait(struct ppb_device *dev, char mask, char status)
+{
+ int i;
+
+ return (ppb_poll_device(dev, 4, mask, status, PPB_NOINTR));
+}
+
+#define nibble2char(s) (((s & ~nACK) >> 3) | (~s & nBUSY) >> 4)
+
+/*
+ * nibble_1284_inbyte()
+ *
+ * Read data in NIBBLE mode
+ */
+int
+nibble_1284_inbyte(struct ppb_device *dev, char *buffer)
+{
+ char nibble[2], r;
+ int i, error;
+
+ r = ppb_rctr(dev);
+
+ for (i = 0; i < 2; i++) {
+ /* ready to take data (nAUTO low) */
+ ppb_wctr(dev, r | AUTOFEED);
+
+ if ((error = nibble_1284_wait(dev, nACK, 0))) {
+ ppb_wctr(dev, r);
+ return (error);
+ }
+
+ /* read nibble */
+ nibble[i] = ppb_rstr(dev);
+
+#ifdef DEBUG_1284
+ printf("nibble_1284_inbyte: nibble[%d]=0x%x\n", i, nibble[i]);
+#endif
+
+ /* ack, not ready for another nibble */
+ ppb_wctr(dev, r & ~AUTOFEED);
+
+ /* wait ack from peripherial */
+ if ((error = nibble_1284_wait(dev, nACK, nACK))) {
+ ppb_wctr(dev, r);
+ return (error);
+ }
+ }
+
+ *buffer = ((nibble2char(nibble[1]) << 4) & 0xf0) |
+ (nibble2char(nibble[0]) & 0x0f);
+
+#ifdef DEBUG_1284
+ printf("nibble_1284_inbyte: byte=0x%x\n", *buffer);
+#endif
+
+ return (0);
+}
+
+/*
+ * nibble_1284_sync()
+ */
+void
+nibble_1284_sync(struct ppb_device *dev)
+{
+ char ctr;
+
+ ctr = ppb_rctr(dev);
+
+ ppb_wctr(dev, (ctr & ~AUTOFEED) | SELECTIN);
+ if (nibble_1284_wait(dev, nACK, 0))
+ return;
+
+ ppb_wctr(dev, ctr | AUTOFEED);
+ nibble_1284_wait(dev, nACK, nACK);
+
+ ppb_wctr(dev, (ctr & ~AUTOFEED) | SELECTIN);
+
+ return;
+}
+
+/*
+ * nibble_1284_mode()
+ *
+ * Normal nibble mode or request device id mode (see ppb_1284.h)
+ */
+int
+nibble_1284_mode(struct ppb_device *dev, int mode)
+{
+ char ctrl;
+ int error;
+
+ ctrl = ppb_rctr(dev);
+
+ ppb_wdtr(dev, mode);
+ DELAY(5);
+
+ ppb_wctr(dev, (ctrl & ~SELECTIN) | AUTOFEED);
+ if ((error = nibble_1284_wait(dev, nACK | ERROR | SELECT | nFAULT,
+ ERROR | SELECT | nFAULT))) {
+ ppb_wctr(dev, ctrl);
+ return (error);
+ }
+
+ ppb_wctr(dev, ppb_rctr(dev) | STROBE);
+ DELAY(5);
+
+ ppb_wctr(dev, ppb_rctr(dev) & ~STROBE);
+ DELAY(5);
+
+ ppb_wctr(dev, ppb_rctr(dev) & ~AUTOFEED);
+
+ return (0);
+}
diff --git a/sys/dev/ppbus/ppb_1284.h b/sys/dev/ppbus/ppb_1284.h
new file mode 100644
index 0000000..527d90a
--- /dev/null
+++ b/sys/dev/ppbus/ppb_1284.h
@@ -0,0 +1,40 @@
+/*-
+ * 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 __1284_H
+#define __1284_H
+
+#define NIBBLE_1284_NORMAL 0
+#define NIBBLE_1284_REQUEST_ID 4
+
+extern void nibble_1284_sync(struct ppb_device *);
+extern int nibble_1284_inbyte(struct ppb_device *, char *);
+extern int nibble_1284_wait(struct ppb_device *, char, char);
+extern int nibble_1284_mode(struct ppb_device *, int);
+
+#endif
diff --git a/sys/dev/ppbus/ppb_base.c b/sys/dev/ppbus/ppb_base.c
new file mode 100644
index 0000000..99d2446
--- /dev/null
+++ b/sys/dev/ppbus/ppb_base.c
@@ -0,0 +1,210 @@
+/*-
+ * 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>
+
+/*
+ * 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_poll_device()
+ *
+ * Polls the device
+ *
+ * max is a delay in 10-milliseconds
+ */
+int
+ppb_poll_device(struct ppb_device *dev, int max,
+ char mask, char status, int how)
+{
+ int i, error;
+
+ for (i = 0; i < max; i++) {
+ if ((ppb_rstr(dev) & mask) == status)
+ return (0);
+
+ switch (how) {
+ case PPB_NOINTR:
+ /* wait 10 ms */
+ if ((error = tsleep((caddr_t)dev, PPBPRI,
+ "ppbpoll", hz/100)))
+ return (error);
+ break;
+
+ case PPB_INTR:
+ default:
+ /* wait 10 ms */
+ if ((error = tsleep((caddr_t)dev, PPBPRI | PCATCH,
+ "ppbpoll", hz/100)))
+ return (error);
+ break;
+ }
+ }
+
+ return (EWOULDBLOCK);
+}
+
+/*
+ * 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.c b/sys/dev/ppbus/ppbconf.c
index 5d2bc45..b72012c 100644
--- a/sys/dev/ppbus/ppbconf.c
+++ b/sys/dev/ppbus/ppbconf.c
@@ -23,7 +23,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id$
+ * $Id: ppbconf.c,v 1.1 1997/08/14 13:57:41 msmith Exp $
*
*/
#include <sys/param.h>
@@ -48,6 +48,7 @@
#include <i386/isa/isa_device.h>
#include <dev/ppbus/ppbconf.h>
+#include <dev/ppbus/ppb_1284.h>
LIST_HEAD(, ppb_data) ppbdata; /* list of existing ppbus */
@@ -62,11 +63,6 @@ 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.
@@ -98,6 +94,159 @@ ppb_alloc_bus(void)
return(ppb);
}
+static char *pnp_tokens[] = {
+ "PRINTER", "MODEM", "NET", "HDC", "PCMCIA", "MEDIA",
+ "FDC", "PORTS", "SCANNER", "DIGICAM", "", NULL };
+
+static char *pnp_classes[] = {
+ "printer", "modem", "network device",
+ "hard disk", "PCMCIA", "multimedia device",
+ "floppy disk", "ports", "scanner",
+ "digital camera", "unknown device", NULL };
+
+/*
+ * search_token()
+ *
+ * Search the first occurence of a token within a string
+ */
+static char *
+search_token(char *str, int slen, char *token)
+{
+ char *p;
+ int tlen, i, j;
+
+#define UNKNOWN_LENGTH -1
+
+ if (slen == UNKNOWN_LENGTH)
+ /* get string's length */
+ for (slen = 0, p = str; *p != '\0'; p++)
+ slen ++;
+
+ /* get token's length */
+ for (tlen = 0, p = token; *p != '\0'; p++)
+ tlen ++;
+
+ if (tlen == 0)
+ return (str);
+
+ for (i = 0; i <= slen-tlen; i++) {
+ for (j = 0; j < tlen; j++)
+ if (str[i+j] != token[j])
+ break;
+ if (j == tlen)
+ return (&str[i]);
+ }
+
+ return (NULL);
+}
+
+/*
+ * ppb_pnp_detect()
+ *
+ * Returns the class id. of the peripherial, -1 otherwise
+ */
+static int
+ppb_pnp_detect(struct ppb_data *ppb)
+{
+ char *token, *q, *class = 0;
+ int i, len, error;
+ char str[PPB_PnP_STRING_SIZE+1];
+
+ struct ppb_device pnpdev; /* temporary device to perform I/O */
+
+ /* initialize the pnpdev structure for future use */
+ bzero(&pnpdev, sizeof(pnpdev));
+
+ pnpdev.ppb = ppb;
+
+#ifdef PnP_DEBUG
+ printf("ppb: <PnP> probing PnP devices on ppbus%d...\n",
+ ppb->ppb_link->adapter_unit);
+#endif
+
+ ppb_wctr(&pnpdev, nINIT | SELECTIN);
+
+ /* select NIBBLE_1284_REQUEST_ID mode */
+ if ((error = nibble_1284_mode(&pnpdev, NIBBLE_1284_REQUEST_ID))) {
+#ifdef PnP_DEBUG
+ printf("ppb: <PnP> nibble_1284_mode()=%d\n", error);
+#endif
+ return (-1);
+ }
+
+ len = 0;
+ for (q = str; !(ppb_rstr(&pnpdev) & ERROR); q++) {
+ if ((error = nibble_1284_inbyte(&pnpdev, q))) {
+#ifdef PnP_DEBUG
+ printf("ppb: <PnP> nibble_1284_inbyte()=%d\n", error);
+#endif
+ return (-1);
+ }
+ if (len++ >= PPB_PnP_STRING_SIZE) {
+ printf("ppb: <PnP> not space left!\n");
+ return (-1);
+ }
+ }
+ *q = '\0';
+
+ nibble_1284_sync(&pnpdev);
+
+#ifdef PnP_DEBUG
+ printf("ppb: <PnP> %d characters: ", len);
+ for (i = 0; i < len; i++)
+ printf("0x%x ", str[i]);
+ printf("\n");
+#endif
+
+ /* replace ';' characters by '\0' */
+ for (i = 0; i < len; i++)
+ str[i] = (str[i] == ';') ? '\0' : str[i];
+
+ if ((token = search_token(str, len, "MFG")) != NULL)
+ printf("ppbus%d: <%s", ppb->ppb_link->adapter_unit,
+ search_token(token, UNKNOWN_LENGTH, ":") + 1);
+ else
+ printf("ppbus%d: <unknown", ppb->ppb_link->adapter_unit);
+
+ if ((token = search_token(str, len, "MDL")) != NULL)
+ printf(" %s",
+ search_token(token, UNKNOWN_LENGTH, ":") + 1);
+ else
+ printf(" unknown");
+
+ if ((token = search_token(str, len, "VER")) != NULL)
+ printf("/%s",
+ search_token(token, UNKNOWN_LENGTH, ":") + 1);
+
+ if ((token = search_token(str, len, "REV")) != NULL)
+ printf(".%s",
+ search_token(token, UNKNOWN_LENGTH, ":") + 1);
+
+ printf(">");
+
+ if ((token = search_token(str, len, "CLS")) != NULL) {
+ class = search_token(token, UNKNOWN_LENGTH, ":") + 1;
+ printf(" %s", class);
+ }
+
+ if ((token = search_token(str, len, "CMD")) != NULL)
+ printf(" %s",
+ search_token(token, UNKNOWN_LENGTH, ":") + 1);
+
+ printf("\n");
+
+ if (class)
+ /* identify class ident */
+ for (i = 0; pnp_tokens[i] != NULL; i++) {
+ if (search_token(class, len, pnp_tokens[i]) != NULL) {
+ return (i);
+ break;
+ }
+ }
+
+ return (PPB_PnP_UNKNOWN);
+}
+
/*
* ppb_attachdevs()
*
@@ -110,9 +259,12 @@ 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;
+
+ /* detect PnP devices */
+ ppb->class_id = ppb_pnp_detect(ppb);
/*
* Blindly try all probes here. Later we should look at
@@ -134,206 +286,133 @@ ppb_attachdevs(struct ppb_data *ppb)
}
/*
- * ppb_request_bus()
+ * ppb_next_bus()
*
- * Allocate the device to perform transfers.
- *
- * how : PPB_WAIT or PPB_DONTWAIT
+ * Return the next bus in ppbus queue
*/
-int
-ppb_request_bus(struct ppb_device *dev, int how)
+struct ppb_data *
+ppb_next_bus(struct ppb_data *ppb)
{
- int s, error = 0;
- struct ppb_data *ppb = dev->ppb;
- /*
- * During initialisation, ppb is null.
- */
- if (!ppb)
- return (0);
+ if (ppb == NULL)
+ return (ppbdata.lh_first);
- 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;
- }
+ return (ppb->ppb_chain.le_next);
+}
- } else {
- ppb->ppb_owner = dev;
+/*
+ * ppb_lookup_bus()
+ *
+ * Get ppb_data structure pointer according to the base address of the ppbus
+ */
+struct ppb_data *
+ppb_lookup_bus(int base_port)
+{
+ struct ppb_data *ppb;
- splx(s);
- return (0);
- }
- }
+ for (ppb = ppbdata.lh_first; ppb; ppb = ppb->ppb_chain.le_next)
+ if (ppb->ppb_link->base == base_port)
+ break;
- return (EINTR);
+ return (ppb);
}
/*
- * ppb_release_bus()
+ * ppb_attach_device()
*
- * Release the device allocated with ppb_request_dev()
+ * Called by loadable kernel modules to add a device
*/
int
-ppb_release_bus(struct ppb_device *dev)
+ppb_attach_device(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);
+ /* add the device to the list of probed devices */
+ LIST_INSERT_HEAD(&ppb->ppb_devs, dev, chain);
return (0);
}
/*
- * ppb_intr()
+ * ppb_remove_device()
*
- * Function called by ppcintr() when an intr occurs.
+ * Called by loadable kernel modules to remove a device
*/
void
-ppb_intr(struct ppb_link *pl)
+ppb_remove_device(struct ppb_device *dev)
{
- 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);
+ /* remove the device from the list of probed devices */
+ LIST_REMOVE(dev, chain);
return;
}
/*
- * ppb_reset_epp_timeout()
+ * ppb_request_bus()
*
- * 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()
+ * Allocate the device to perform transfers.
*
- * Wait for the ECP FIFO to be empty.
+ * how : PPB_WAIT or PPB_DONTWAIT
*/
int
-ppb_ecp_sync(struct ppb_device *dev)
+ppb_request_bus(struct ppb_device *dev, int how)
{
+ int s, error = 0;
struct ppb_data *ppb = dev->ppb;
- if (ppb->ppb_owner != dev)
- return (EACCES);
+ while (!error) {
+ s = splhigh();
+ if (ppb->ppb_owner) {
+ splx(s);
- (*ppb->ppb_link->adapter->ecp_sync)(dev->id_unit);
+ switch (how) {
+ case (PPB_WAIT | PPB_INTR):
+ error = tsleep(ppb, PPBPRI|PCATCH, "ppbreq", 0);
+ break;
- return (0);
-}
+ case (PPB_WAIT | PPB_NOINTR):
+ error = tsleep(ppb, PPBPRI, "ppbreq", 0);
+ break;
-/*
- * 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);
-}
+ default:
+ return (EWOULDBLOCK);
+ break;
+ }
-/*
- * 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);
-}
+ } else {
+ ppb->ppb_owner = dev;
-/*
- * ppb_get_irq()
- *
- * Return the irq, 0 if none.
- */
-int
-ppb_get_irq(struct ppb_device *dev)
-{
- return (dev->ppb->ppb_link->id_irq);
+ splx(s);
+ return (0);
+ }
+ }
+
+ return (error);
}
/*
- * ppb_get_status()
+ * ppb_release_bus()
*
- * Read the status register and update the status info.
+ * Release the device allocated with ppb_request_dev()
*/
int
-ppb_get_status(struct ppb_device *dev, struct ppb_status *status)
+ppb_release_bus(struct ppb_device *dev)
{
+ int s;
struct ppb_data *ppb = dev->ppb;
- register char r;
- if (ppb->ppb_owner != dev)
+ s = splhigh();
+ if (ppb->ppb_owner != dev) {
+ splx(s);
return (EACCES);
+ }
- r = status->status = ppb_rstr(dev);
+ ppb->ppb_owner = 0;
+ splx(s);
- 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);
+ /* wakeup waiting processes */
+ wakeup(ppb);
return (0);
}
diff --git a/sys/dev/ppbus/ppbconf.h b/sys/dev/ppbus/ppbconf.h
index b10df44..15a6fb0 100644
--- a/sys/dev/ppbus/ppbconf.h
+++ b/sys/dev/ppbus/ppbconf.h
@@ -23,13 +23,18 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id$
+ * $Id: ppbconf.h,v 1.1 1997/08/14 13:57:42 msmith Exp $
*
*/
#ifndef __PPBCONF_H
#define __PPBCONF_H
/*
+ * Parallel Port Bus sleep/wakeup queue.
+ */
+#define PPBPRI PZERO+8
+
+/*
* Parallel Port Chipset modes.
*/
#define PPB_AUTODETECT 0x0 /* autodetect */
@@ -140,6 +145,7 @@ struct ppb_link {
int adapter_unit; /* unit of the adapter */
+ int base; /* base address of the port */
int id_irq; /* != 0 if irq enabled */
int mode; /* NIBBLE, PS2, EPP, ECP */
@@ -153,10 +159,28 @@ struct ppb_link {
};
/*
+ * Maximum size of the PnP info string
+ */
+#define PPB_PnP_STRING_SIZE 160 /* XXX */
+
+/*
* Parallel Port Bus structure.
*/
struct ppb_data {
+#define PPB_PnP_PRINTER 0
+#define PPB_PnP_MODEM 1
+#define PPB_PnP_NET 2
+#define PPB_PnP_HDC 3
+#define PPB_PnP_PCMCIA 4
+#define PPB_PnP_MEDIA 5
+#define PPB_PnP_FDC 6
+#define PPB_PnP_PORTS 7
+#define PPB_PnP_SCANNER 8
+#define PPB_PnP_DIGICAM 9
+#define PPB_PnP_UNKNOWN 10
+ int class_id; /* not a PnP device if class_id < 0 */
+
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 */
@@ -176,11 +200,20 @@ struct ppb_driver
extern struct linker_set ppbdriver_set;
extern struct ppb_data *ppb_alloc_bus(void);
+extern struct ppb_data *ppb_next_bus(struct ppb_data *);
+extern struct ppb_data *ppb_lookup_bus(int);
+
+extern int ppb_attach_device(struct ppb_device *);
+extern void ppb_remove_device(struct ppb_device *);
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_poll_device(struct ppb_device *, int, char, char, int);
+
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 *);
diff --git a/sys/dev/ppbus/ppi.c b/sys/dev/ppbus/ppi.c
index 79df5b5..e3a51b1 100644
--- a/sys/dev/ppbus/ppi.c
+++ b/sys/dev/ppbus/ppi.c
@@ -23,9 +23,13 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id$
+ * $Id: ppi.c,v 1.1 1997/08/14 13:57:43 msmith Exp $
*
*/
+#include "ppi.h"
+
+#if NPPI > 0
+
#include <sys/types.h>
#ifdef KERNEL
@@ -49,10 +53,16 @@
#endif /*KERNEL */
#include <dev/ppbus/ppbconf.h>
-#include <dev/ppbus/ppi.h>
-static int nppi = 0;
+struct ppi_data {
+
+ int ppi_unit;
+
+ struct ppb_device ppi_dev;
+};
+
#define MAXPPI 8 /* XXX not much better! */
+static int nppi = 0;
static struct ppi_data *ppidata[MAXPPI];
/*
@@ -63,14 +73,11 @@ 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;
@@ -78,7 +85,7 @@ static d_ioctl_t ppiioctl;
#define CDEV_MAJOR 14 /* XXX */
static struct cdevsw ppi_cdevsw =
- { ppiopen, ppiclose, noread, nowrite,
+ { ppiopen, ppiclose, noread, nowrite, /* 14 */
ppiioctl, nullstop, nullreset, nodevtotty,
seltrue, nommap, nostrat, "ppi", NULL, -1 };
@@ -141,6 +148,13 @@ ppiintr(int unit)
static int
ppiopen(dev_t dev, int flags, int fmt, struct proc *p)
{
+ u_int unit = minor(dev);
+
+ if (unit >= nppi)
+ return (ENXIO);
+
+ printf("ppi open!\n");
+
return (EOPNOTSUPP);
}
@@ -156,17 +170,66 @@ ppiioctl(dev_t dev, int cmd, caddr_t data, int flags, struct proc *p)
return (EOPNOTSUPP);
}
+#ifdef PPI_MODULE
+
+#include <sys/exec.h>
+#include <sys/sysent.h>
+#include <sys/lkm.h>
+
+MOD_DEV(ppi, LM_DT_CHAR, CDEV_MAJOR, &ppi_cdevsw);
+
+static int
+ppi_load(struct lkm_table *lkmtp, int cmd)
+{
+ struct ppb_data *ppb;
+ struct ppb_device *dev;
+ int i;
+
+ for (ppb = ppb_next_bus(NULL); ppb; ppb = ppb_next_bus(ppb)) {
+
+ dev = ppiprobe(ppb);
+ ppiattach(dev);
+
+ ppb_attach_device(dev);
+ }
+
+ return (0);
+}
+
+static int
+ppi_unload(struct lkm_table *lkmtp, int cmd)
+{
+ int i;
+
+ for (i = nppi-1; i > 0; i--) {
+ ppb_remove_device(&ppidata[i]->ppi_dev);
+ free(ppidata[i], M_TEMP);
+ }
+
+ return (0);
+}
+
+int
+ppi_mod(struct lkm_table *lkmtp, int cmd, int ver)
+{
+ DISPATCH(lkmtp, cmd, ver, ppi_load, ppi_unload, lkm_nullcmd);
+}
+
+#endif /* PPI_MODULE */
+
static ppi_devsw_installed = 0;
-static void ppi_drvinit(void *unused)
+static void ppi_drvinit(void *unused)
{
dev_t dev;
- if( ! ppi_devsw_installed ) {
+ 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)
+SYSINIT(ppidev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,ppi_drvinit,NULL)
+
+#endif /* NPPI */
diff --git a/sys/dev/ppbus/vpo.c b/sys/dev/ppbus/vpo.c
index 1cd69be..61eb4c6 100644
--- a/sys/dev/ppbus/vpo.c
+++ b/sys/dev/ppbus/vpo.c
@@ -23,7 +23,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id$
+ * $Id: vpo.c,v 1.1 1997/08/14 13:57:44 msmith Exp $
*
*/
#include <sys/types.h>
@@ -65,14 +65,6 @@
#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
* --------------------------------------------------------------------
@@ -175,9 +167,9 @@ vpoprobe(struct ppb_data *ppb)
vpo->vpo_dev.ppb = ppb;
/* now, try to initialise the drive */
- if (vpo_detect(vpo) != 0) {
+ if (vpo_detect(vpo)) {
free(vpo, M_DEVBUF);
- return(NULL);
+ return (NULL);
}
/* ok, go to next device on next probe */
@@ -288,25 +280,37 @@ static inline void
vpointr(struct vpo_data *vpo, struct scsi_xfer *xs)
{
- register int timeout;
+ int errno; /* error in errno.h */
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);
+ errno = 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_DEBUG
+ printf("vpo_do_scsi = %d, status = 0x%x, count = %d, vpo_error = %d\n",
+ errno, vpo->vpo_stat, vpo->vpo_count, vpo->vpo_error);
+#endif
+
+ if (errno) {
#ifdef VP0_WARNING
- vpo_warning(vpo, xs, timeout);
+ log(LOG_WARNING, "vpo%d: errno = %d\n", vpo->vpo_unit, errno);
#endif
+ /* connection to ppbus interrupted */
+ xs->error = XS_DRIVER_STUFFUP;
+ goto error;
+ }
-#ifdef VP03_DEBUG
- printf("vpo_do_scsi = %d, status = 0x%x, count = %d\n",
- timeout, vpo->vpo_stat, vpo->vpo_count);
+ /* if a timeout occured, no sense */
+ if (vpo->vpo_error) {
+#ifdef VP0_WARNING
+ vpo_warning(vpo, xs, vpo->vpo_error);
#endif
+ xs->error = XS_TIMEOUT;
+ goto error;
+ }
#define RESERVED_BITS_MASK 0x3e /* 00111110b */
#define NO_SENSE 0x0
@@ -317,23 +321,25 @@ vpointr(struct vpo_data *vpo, struct scsi_xfer *xs)
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,
+ errno = 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;
+ if (errno)
+ /* connection to ppbus interrupted */
+ xs->error = XS_DRIVER_STUFFUP;
+ else
+ xs->error = XS_SENSE;
+
goto error;
- }
- if (timeout) {
+ default: /* BUSY or RESERVATION_CONFLICT */
xs->error = XS_TIMEOUT;
goto error;
}
@@ -369,7 +375,7 @@ vpo_scsi_cmd(struct scsi_xfer *xs)
return TRY_AGAIN_LATER;
}
-#ifdef VP03_DEBUG
+#ifdef VP0_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,
@@ -729,8 +735,15 @@ vpoio_wait(struct vpo_data *vpo, int tmo)
register int k;
register char r;
+#if 0 /* broken */
+ if (ppb_poll_device(&vpo->vpo_dev, 150, nBUSY, nBUSY, PPB_INTR))
+ return (0);
+
+ return (ppb_rstr(&vpo->vpo_dev) & 0xf0);
+#endif
+
k = 0;
- while (!((r = ppb_rstr(&vpo->vpo_dev)) & 0x80) && (k++ < tmo))
+ while (!((r = ppb_rstr(&vpo->vpo_dev)) & nBUSY) && (k++ < tmo))
barrier();
/*
@@ -756,14 +769,22 @@ vpoio_do_scsi(struct vpo_data *vpo, int host, int target, char *command,
int rw, len, error = 0;
register int k;
- /* enter disk state, allocate the ppbus */
- vpoio_connect(vpo, PPB_WAIT | PPB_NOINTR);
+ /*
+ * enter disk state, allocate the ppbus
+ *
+ * XXX
+ * Should we allow this call to be interruptible?
+ * The only way to report the interruption is to return
+ * EIO do upper SCSI code :^(
+ */
+ if ((error = vpoio_connect(vpo, PPB_WAIT|PPB_INTR)))
+ return (error);
if (!vpoio_in_disk_mode(vpo)) {
- error = VP0_ECONNECT; goto error;
+ vpo->vpo_error = VP0_ECONNECT; goto error;
}
- if ((error = vpoio_select(vpo,host,target)))
+ if ((vpo->vpo_error = vpoio_select(vpo,host,target)))
goto error;
/*
@@ -773,23 +794,23 @@ vpoio_do_scsi(struct vpo_data *vpo, int host, int target, char *command,
*/
ppb_wctr(&vpo->vpo_dev, H_AUTO | H_nSELIN | H_INIT | H_STROBE);
-#ifdef VP03_DEBUG
+#ifdef VP0_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;
+ vpo->vpo_error = VP0_ECMD_TIMEOUT;
goto error;
}
if (vpoio_outstr(vpo, &command[k], 1)) {
- error = VP0_EPPDATA_TIMEOUT;
+ vpo->vpo_error = VP0_EPPDATA_TIMEOUT;
goto error;
}
}
-#ifdef VP03_DEBUG
+#ifdef VP0_DEBUG
printf("vpo%d: command sent, now completing the request...\n",
vpo->vpo_unit);
#endif
@@ -804,7 +825,7 @@ vpoio_do_scsi(struct vpo_data *vpo, int host, int target, char *command,
for (;;) {
if (!(r = vpoio_wait(vpo, VP0_LOW_SPINTMO))) {
- error = VP0_ESTATUS_TIMEOUT; goto error;
+ vpo->vpo_error = VP0_ESTATUS_TIMEOUT; goto error;
}
/* stop when the ZIP wants to send status */
@@ -812,7 +833,7 @@ vpoio_do_scsi(struct vpo_data *vpo, int host, int target, char *command,
break;
if (*count >= blen) {
- error = VP0_EDATA_OVERFLOW;
+ vpo->vpo_error = VP0_EDATA_OVERFLOW;
goto error;
}
len = (rw && ((blen - *count) >= VP0_SECTOR_SIZE)) ?
@@ -824,37 +845,28 @@ vpoio_do_scsi(struct vpo_data *vpo, int host, int target, char *command,
else
error = vpoio_instr(vpo, &buffer[*count], len);
- if (error)
+ if (error) {
+ vpo->vpo_error = error;
goto error;
+ }
*count += len;
}
if (vpoio_instr(vpo, &l, 1)) {
- error = VP0_EOTHER; goto error;
+ vpo->vpo_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;
+ vpo->vpo_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:
+ /* return to printer state, release the ppbus */
vpoio_disconnect(vpo);
- return (error);
+ return (0);
}
diff --git a/sys/dev/ppbus/vpo.h b/sys/dev/ppbus/vpo.h
index 582538f..5a724dd 100644
--- a/sys/dev/ppbus/vpo.h
+++ b/sys/dev/ppbus/vpo.h
@@ -23,7 +23,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id$
+ * $Id: vpo.h,v 1.1 1997/08/14 13:57:45 msmith Exp $
*
*/
#ifndef __VP03_H
@@ -96,6 +96,7 @@ struct vpo_data {
int vpo_stat;
int vpo_count;
+ int vpo_error;
struct ppb_status vpo_status;
struct vpo_sense vpo_sense;
OpenPOWER on IntegriCloud