From 4e86e1b8146d6d3db414343b88c3dd0a70c3f3e8 Mon Sep 17 00:00:00 2001 From: msmith Date: Sat, 16 Aug 1997 14:05:38 +0000 Subject: 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 --- sys/dev/ppbus/nlpt.c | 99 ++++++++---- sys/dev/ppbus/nlpt.h | 7 +- sys/dev/ppbus/ppb_1284.c | 163 ++++++++++++++++++++ sys/dev/ppbus/ppb_1284.h | 40 +++++ sys/dev/ppbus/ppb_base.c | 210 ++++++++++++++++++++++++++ sys/dev/ppbus/ppbconf.c | 381 ++++++++++++++++++++++++++++------------------- sys/dev/ppbus/ppbconf.h | 35 ++++- sys/dev/ppbus/ppi.c | 83 +++++++++-- sys/dev/ppbus/vpo.c | 124 ++++++++------- sys/dev/ppbus/vpo.h | 3 +- 10 files changed, 900 insertions(+), 245 deletions(-) create mode 100644 sys/dev/ppbus/ppb_1284.c create mode 100644 sys/dev/ppbus/ppb_1284.h create mode 100644 sys/dev/ppbus/ppb_base.c 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 #include #include +#ifdef DEVFS +#include +#endif /*DEVFS*/ #include #include @@ -86,7 +89,7 @@ #include #include -#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include + +#include + +/* + * 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 @@ -48,6 +48,7 @@ #include #include +#include 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: 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: 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: nibble_1284_inbyte()=%d\n", error); +#endif + return (-1); + } + if (len++ >= PPB_PnP_STRING_SIZE) { + printf("ppb: not space left!\n"); + return (-1); + } + } + *q = '\0'; + + nibble_1284_sync(&pnpdev); + +#ifdef PnP_DEBUG + printf("ppb: %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: 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 #ifdef KERNEL @@ -49,10 +53,16 @@ #endif /*KERNEL */ #include -#include -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 +#include +#include + +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 @@ -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; -- cgit v1.1