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>
This commit is contained in:
parent
9109c1638f
commit
b96b8da32b
@ -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 @@ nlpt_detect(struct lpt_data *lpt)
|
||||
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 ");
|
||||
|
@ -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
|
||||
|
163
sys/dev/ppbus/ppb_1284.c
Normal file
163
sys/dev/ppbus/ppb_1284.c
Normal file
@ -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);
|
||||
}
|
40
sys/dev/ppbus/ppb_1284.h
Normal file
40
sys/dev/ppbus/ppb_1284.h
Normal file
@ -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
|
210
sys/dev/ppbus/ppb_base.c
Normal file
210
sys/dev/ppbus/ppb_base.c
Normal file
@ -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);
|
||||
}
|
@ -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 */
|
||||
|
||||
@ -61,11 +62,6 @@ static struct ppb_driver nulldriver = {
|
||||
DATA_SET(ppbdriver_set, nulldriver);
|
||||
|
||||
|
||||
/*
|
||||
* Parallel Port Bus sleep/wakeup queue.
|
||||
*/
|
||||
#define PRIPPB 28 /* PSOCK < PRIPPB < PWAIT XXX */
|
||||
|
||||
/*
|
||||
* ppb_alloc_bus()
|
||||
*
|
||||
@ -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
|
||||
@ -133,6 +285,69 @@ ppb_attachdevs(struct ppb_data *ppb)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* ppb_next_bus()
|
||||
*
|
||||
* Return the next bus in ppbus queue
|
||||
*/
|
||||
struct ppb_data *
|
||||
ppb_next_bus(struct ppb_data *ppb)
|
||||
{
|
||||
|
||||
if (ppb == NULL)
|
||||
return (ppbdata.lh_first);
|
||||
|
||||
return (ppb->ppb_chain.le_next);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
for (ppb = ppbdata.lh_first; ppb; ppb = ppb->ppb_chain.le_next)
|
||||
if (ppb->ppb_link->base == base_port)
|
||||
break;
|
||||
|
||||
return (ppb);
|
||||
}
|
||||
|
||||
/*
|
||||
* ppb_attach_device()
|
||||
*
|
||||
* Called by loadable kernel modules to add a device
|
||||
*/
|
||||
int
|
||||
ppb_attach_device(struct ppb_device *dev)
|
||||
{
|
||||
struct ppb_data *ppb = dev->ppb;
|
||||
|
||||
/* add the device to the list of probed devices */
|
||||
LIST_INSERT_HEAD(&ppb->ppb_devs, dev, chain);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* ppb_remove_device()
|
||||
*
|
||||
* Called by loadable kernel modules to remove a device
|
||||
*/
|
||||
void
|
||||
ppb_remove_device(struct ppb_device *dev)
|
||||
{
|
||||
|
||||
/* remove the device from the list of probed devices */
|
||||
LIST_REMOVE(dev, chain);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* ppb_request_bus()
|
||||
*
|
||||
@ -146,28 +361,22 @@ 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) {
|
||||
while (!error) {
|
||||
s = splhigh();
|
||||
if (ppb->ppb_owner) {
|
||||
splx(s);
|
||||
|
||||
switch (how) {
|
||||
case (PPB_WAIT | PPB_INTR):
|
||||
|
||||
error = tsleep(ppb, PRIPPB | PCATCH,
|
||||
"ppbreq", 0);
|
||||
error = tsleep(ppb, PPBPRI|PCATCH, "ppbreq", 0);
|
||||
break;
|
||||
case (PPB_WAIT):
|
||||
error = tsleep(ppb, PRIPPB, "ppbreq", 0);
|
||||
|
||||
case (PPB_WAIT | PPB_NOINTR):
|
||||
error = tsleep(ppb, PPBPRI, "ppbreq", 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
return EWOULDBLOCK;
|
||||
return (EWOULDBLOCK);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -179,7 +388,7 @@ ppb_request_bus(struct ppb_device *dev, int how)
|
||||
}
|
||||
}
|
||||
|
||||
return (EINTR);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -193,12 +402,6 @@ 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);
|
||||
@ -208,132 +411,8 @@ ppb_release_bus(struct ppb_device *dev)
|
||||
ppb->ppb_owner = 0;
|
||||
splx(s);
|
||||
|
||||
/*
|
||||
* Wakeup waiting processes.
|
||||
*/
|
||||
/* 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);
|
||||
}
|
||||
|
@ -23,12 +23,17 @@
|
||||
* 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.
|
||||
*/
|
||||
@ -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 */
|
||||
|
||||
@ -152,11 +158,29 @@ struct ppb_link {
|
||||
struct ppb_data *ppbus; /* link to the ppbus */
|
||||
};
|
||||
|
||||
/*
|
||||
* 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 *);
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
goto error;
|
||||
}
|
||||
if (errno)
|
||||
/* connection to ppbus interrupted */
|
||||
xs->error = XS_DRIVER_STUFFUP;
|
||||
else
|
||||
xs->error = XS_SENSE;
|
||||
|
||||
if (timeout) {
|
||||
goto error;
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user