Major ppbus commit with:
+ ECP parallel port chipset FIFO detection + DMA+FIFO parallel I/O handled as chipset specific + nlpt updated in order to use the above enhanced parallel I/O. Use 'lptcontrol -e' to use enhanced I/O + Various options documented in LINT + Full IEEE1284 NIBBLE and BYTE modes support. See ppbus(4) for an overview of the IEEE1284 standard + Detection of PnP parallel devices at boot + Read capability added to nlpt driver to get IEEE1284 compliant printer status with a simple 'cat /dev/lpt0' + IEEE1284 peripheral emulation added to BYTE mode. Two computers may dialog according to IEEE1284 signaling method. See PERIPH_1284 option and /sys/dev/ppbus/ppi.c All this code is supposed to provide basic functions for IEEE1284 programming. ppi.c and nlpt.c may act as examples.
This commit is contained in:
parent
b7fe2b6dab
commit
bc35c17446
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=42475
@ -1,4 +1,4 @@
|
||||
.\" Copyright (c) 1998, Nicolas Souchu
|
||||
.\" Copyright (c) 1998, 1999 Nicolas Souchu
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
@ -38,6 +38,8 @@ Parallel port bus system
|
||||
.Cd "device nlpt0 at ppbus?"
|
||||
.Cd "device plip0 at ppbus?"
|
||||
.Cd "device ppi0 at ppbus?"
|
||||
.Cd "device pps0 at ppbus?"
|
||||
.Cd "device lpbb0 at ppbus?"
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Em ppbus
|
||||
@ -68,6 +70,8 @@ and non-standard software:
|
||||
.It Sy vpo Ta "VPI0 parallel to Adaptec AIC-7110 SCSI controller driver."
|
||||
It uses standard and non-standard parallel port accesses
|
||||
.It Sy ppi Ta "Parallel port interface for general I/O"
|
||||
.It Sy pps Ta "Pulse per second Timing Interface"
|
||||
.It Sy lpbb Ta "Philips official parallel port I2C bit-banging interface"
|
||||
.El
|
||||
.Ss Porting existing drivers
|
||||
.Pp
|
||||
@ -155,6 +159,50 @@ standard parallel port.
|
||||
Some manufacturers, like SMC, have implemented chipsets that support mixed
|
||||
modes. With such chipsets, mode switching is available at any time by
|
||||
accessing the extended control register.
|
||||
.Sh IEEE1284-1994 Standard
|
||||
.Ss Background
|
||||
This standard is also named "IEEE Standard Signaling Method for a
|
||||
Bidirectional Parallel Peripheral Interface for Personal Computers". It
|
||||
defines a signaling method for asynchroneous, fully interlocked, bidirectional
|
||||
parallel communications between hosts and printers or other peripherals. It
|
||||
also specifies a format for a peripheral identification string and a method of
|
||||
returning this string to the host outside of the bidirectional data stream.
|
||||
.Pp
|
||||
This standard is architecture independent and only specifiy dialog handshake
|
||||
at signal level. One should refer to any architecture specific document in
|
||||
order to manipulate machine dependent registers, mapped memory or whatelse
|
||||
to control these signals.
|
||||
.Pp
|
||||
The IEEE1284 protocol is fully oriented with all supported parallel port
|
||||
modes. The computer acts as master and the peripheral as slave.
|
||||
.Pp
|
||||
Any transfer is defined as a finite state automate. It allows software to
|
||||
properly manage the fully interlocked scheme of the signaling method.
|
||||
The compatible mode is supported "as is" without any negociation because it
|
||||
is compatible. Any other mode must be firstly negociated by the host to check
|
||||
it is supported by the peripheral, then to enter one of the forward idle
|
||||
states.
|
||||
.Pp
|
||||
At any time, the slave may want to send data to the host. This is only
|
||||
possible from forward idle states (nibble, byte, ecp...). So, the
|
||||
host must have previously negociated to permit the peripheral to
|
||||
request transfer. Interrupt lines may be dedicated to the requesting signals
|
||||
to prevent time consuming polling methods.
|
||||
.Pp
|
||||
But peripheral requests are only a hint to the master host. If the host
|
||||
accepts the transfer, it must firstly negociate the reverse mode and then
|
||||
starts the transfer. At any time during reverse transfer, the host may
|
||||
terminate the transfer or the slave may drive wires to signal that no more
|
||||
data is available.
|
||||
.Ss Implementation
|
||||
IEEE1284 Standard support has been implemented at the top of the ppbus system
|
||||
as a set of procedures that perform high level functions like negociation,
|
||||
termination, transfer in any mode without bothering you with low level
|
||||
caracteristics of the stantdard.
|
||||
.Pp
|
||||
IEEE1284 interacts with the ppbus system as least as possible. That means
|
||||
you still have to request the ppbus when you want to access it, the negociate
|
||||
function doesn't do it for you. And of course, release it later.
|
||||
.Sh ARCHITECTURE
|
||||
.Ss adapter, ppbus and device layers
|
||||
First, there is the
|
||||
|
@ -23,7 +23,7 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: immio.c,v 1.3 1998/10/02 20:44:58 nsouch Exp $
|
||||
* $Id: immio.c,v 1.4 1998/10/31 11:35:21 nsouch Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
@ -47,6 +47,8 @@
|
||||
#include <sys/kernel.h>
|
||||
#endif /*KERNEL */
|
||||
|
||||
#include "opt_vpo.h"
|
||||
|
||||
#include <dev/ppbus/ppbconf.h>
|
||||
#include <dev/ppbus/ppb_msq.h>
|
||||
#include <dev/ppbus/vpoio.h>
|
||||
|
@ -23,7 +23,7 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: lpbb.c,v 1.2 1998/11/09 22:22:01 nsouch Exp $
|
||||
* $Id: lpbb.c,v 1.3 1998/12/07 21:58:16 archie Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
@ -240,14 +240,6 @@ else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int getSCL(struct lpbb_softc *sc)
|
||||
{
|
||||
if((ppb_rstr(&sc->lpbb_dev)&SCL_in)==SCL_in)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void setSDA(struct lpbb_softc *sc, char val)
|
||||
{
|
||||
if(val==0)
|
||||
|
@ -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: nlpt.c,v 1.10 1998/09/20 14:41:54 nsouch Exp $
|
||||
* $Id: nlpt.c,v 1.11 1998/12/04 22:00:33 archie Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -81,8 +81,11 @@
|
||||
#endif /*KERNEL*/
|
||||
|
||||
#include <dev/ppbus/ppbconf.h>
|
||||
#include <dev/ppbus/ppb_1284.h>
|
||||
#include <dev/ppbus/nlpt.h>
|
||||
|
||||
#include "opt_nlpt.h"
|
||||
|
||||
#ifndef NLPT_DEBUG
|
||||
#define nlprintf(args)
|
||||
#else
|
||||
@ -99,6 +102,7 @@ static int volatile nlptflag = 1;
|
||||
#define LPTOUTMAX 1 /* maximal timeout 1 s */
|
||||
#define LPPRI (PZERO+8)
|
||||
#define BUFSIZE 1024
|
||||
#define BUFSTATSIZE 32
|
||||
|
||||
#define LPTUNIT(s) ((s)&0x03)
|
||||
#define LPTFLAGS(s) ((s)&0xfc)
|
||||
@ -163,11 +167,12 @@ DATA_SET(ppbdriver_set, nlptdriver);
|
||||
static d_open_t nlptopen;
|
||||
static d_close_t nlptclose;
|
||||
static d_write_t nlptwrite;
|
||||
static d_read_t nlptread;
|
||||
static d_ioctl_t nlptioctl;
|
||||
|
||||
#define CDEV_MAJOR 16
|
||||
static struct cdevsw nlpt_cdevsw =
|
||||
{ nlptopen, nlptclose, noread, nlptwrite, /*16*/
|
||||
{ nlptopen, nlptclose, nlptread, nlptwrite, /*16*/
|
||||
nlptioctl, nullstop, nullreset, nodevtotty, /* lpt */
|
||||
seltrue, nommap, nostrat, LPT_NAME, NULL, -1 };
|
||||
|
||||
@ -176,6 +181,9 @@ lpt_request_ppbus(struct lpt_data *sc, int how)
|
||||
{
|
||||
int error;
|
||||
|
||||
if (sc->sc_state & HAVEBUS)
|
||||
return (0);
|
||||
|
||||
/* we have the bus only if the request succeded */
|
||||
if ((error = ppb_request_bus(&sc->lpt_dev, how)) == 0)
|
||||
sc->sc_state |= HAVEBUS;
|
||||
@ -186,13 +194,10 @@ lpt_request_ppbus(struct lpt_data *sc, int how)
|
||||
static int
|
||||
lpt_release_ppbus(struct lpt_data *sc)
|
||||
{
|
||||
int error;
|
||||
ppb_release_bus(&sc->lpt_dev);
|
||||
sc->sc_state &= ~HAVEBUS;
|
||||
|
||||
/* we do not have the bus only if the request succeeded */
|
||||
if ((error = ppb_release_bus(&sc->lpt_dev)) == 0)
|
||||
sc->sc_state &= ~HAVEBUS;
|
||||
|
||||
return (error);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -439,7 +444,7 @@ nlptopen(dev_t dev, int flags, int fmt, struct proc *p)
|
||||
struct lpt_data *sc;
|
||||
|
||||
int s;
|
||||
int trys;
|
||||
int trys, err;
|
||||
u_int unit = LPTUNIT(minor(dev));
|
||||
|
||||
if ((unit >= nlpt))
|
||||
@ -462,9 +467,8 @@ nlptopen(dev_t dev, int flags, int fmt, struct proc *p)
|
||||
}
|
||||
|
||||
/* request the ppbus only if we don't have it already */
|
||||
if ((sc->sc_state & HAVEBUS) == 0 &&
|
||||
lpt_request_ppbus(sc, PPB_WAIT|PPB_INTR))
|
||||
return (EINTR);
|
||||
if (err = lpt_request_ppbus(sc, PPB_WAIT|PPB_INTR))
|
||||
return (err);
|
||||
|
||||
s = spltty();
|
||||
nlprintf((LPT_NAME " flags 0x%x\n", sc->sc_flags));
|
||||
@ -526,6 +530,7 @@ nlptopen(dev_t dev, int flags, int fmt, struct proc *p)
|
||||
|
||||
sc->sc_state = OPEN;
|
||||
sc->sc_inbuf = geteblk(BUFSIZE);
|
||||
sc->sc_statbuf = geteblk(BUFSTATSIZE);
|
||||
sc->sc_xfercnt = 0;
|
||||
splx(s);
|
||||
|
||||
@ -559,8 +564,7 @@ nlptclose(dev_t dev, int flags, int fmt, struct proc *p)
|
||||
if(sc->sc_flags & LP_BYPASS)
|
||||
goto end_close;
|
||||
|
||||
if ((sc->sc_state & HAVEBUS) == 0 &&
|
||||
(err = lpt_request_ppbus(sc, PPB_WAIT|PPB_INTR)))
|
||||
if (err = lpt_request_ppbus(sc, PPB_WAIT|PPB_INTR))
|
||||
return (err);
|
||||
|
||||
sc->sc_state &= ~OPEN;
|
||||
@ -577,6 +581,7 @@ nlptclose(dev_t dev, int flags, int fmt, struct proc *p)
|
||||
|
||||
ppb_wctr(&sc->lpt_dev, LPC_NINIT);
|
||||
brelse(sc->sc_inbuf);
|
||||
brelse(sc->sc_statbuf);
|
||||
|
||||
end_close:
|
||||
/* release the bus anyway */
|
||||
@ -648,6 +653,40 @@ nlpt_pushbytes(struct lpt_data *sc)
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* nlptread --retrieve printer status in IEEE1284 NIBBLE mode
|
||||
*/
|
||||
|
||||
static int
|
||||
nlptread(dev_t dev, struct uio *uio, int ioflag)
|
||||
{
|
||||
struct lpt_data *sc = lptdata[LPTUNIT(minor(dev))];
|
||||
int error = 0, len;
|
||||
|
||||
if ((error = ppb_1284_negociate(&sc->lpt_dev, PPB_NIBBLE, 0)))
|
||||
return (error);
|
||||
|
||||
/* read data in an other buffer, read/write may be simultaneous */
|
||||
len = 0;
|
||||
while (uio->uio_resid) {
|
||||
if ((error = ppb_1284_read(&sc->lpt_dev, PPB_NIBBLE,
|
||||
sc->sc_statbuf->b_data, min(BUFSTATSIZE,
|
||||
uio->uio_resid), &len))) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!len)
|
||||
goto error; /* no more data */
|
||||
|
||||
if ((error = uiomove(sc->sc_statbuf->b_data, len, uio)))
|
||||
goto error;
|
||||
}
|
||||
|
||||
error:
|
||||
ppb_1284_terminate(&sc->lpt_dev);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* nlptwrite --copy a line from user space to a local buffer, then call
|
||||
* putc to get the chars moved to the output queue.
|
||||
@ -660,6 +699,7 @@ nlptwrite(dev_t dev, struct uio *uio, int ioflag)
|
||||
{
|
||||
register unsigned n;
|
||||
int pl, err;
|
||||
u_int unit = LPTUNIT(minor(dev));
|
||||
struct lpt_data *sc = lptdata[LPTUNIT(minor(dev))];
|
||||
|
||||
if(sc->sc_flags & LP_BYPASS) {
|
||||
@ -668,16 +708,36 @@ nlptwrite(dev_t dev, struct uio *uio, int ioflag)
|
||||
}
|
||||
|
||||
/* request the ppbus only if we don't have it already */
|
||||
if ((sc->sc_state & HAVEBUS) == 0 &&
|
||||
lpt_request_ppbus(sc, PPB_WAIT|PPB_INTR))
|
||||
return (EINTR);
|
||||
if (err = lpt_request_ppbus(sc, PPB_WAIT|PPB_INTR))
|
||||
return (err);
|
||||
|
||||
sc->sc_state &= ~INTERRUPTED;
|
||||
while ((n = min(BUFSIZE, uio->uio_resid)) != 0) {
|
||||
sc->sc_cp = sc->sc_inbuf->b_data ;
|
||||
uiomove(sc->sc_cp, n, uio);
|
||||
sc->sc_xfercnt = n ;
|
||||
while ((sc->sc_xfercnt > 0)&&(sc->sc_irq & LP_USE_IRQ)) {
|
||||
|
||||
if (sc->sc_irq & LP_ENABLE_EXT) {
|
||||
/* try any extended mode */
|
||||
err = ppb_write(&sc->lpt_dev, sc->sc_cp,
|
||||
sc->sc_xfercnt, 0);
|
||||
switch (err) {
|
||||
case 0:
|
||||
/* if not all data was sent, we could rely
|
||||
* on polling for the last bytes */
|
||||
sc->sc_xfercnt = 0;
|
||||
break;
|
||||
case EINTR:
|
||||
sc->sc_state |= INTERRUPTED;
|
||||
return(err);
|
||||
case EINVAL:
|
||||
/* advanced mode not avail */
|
||||
log(LOG_NOTICE, LPT_NAME "%d: advanced mode not avail, polling\n", unit);
|
||||
break;
|
||||
default:
|
||||
return(err);
|
||||
}
|
||||
} else while ((sc->sc_xfercnt > 0)&&(sc->sc_irq & LP_USE_IRQ)) {
|
||||
nlprintf(("i"));
|
||||
/* if the printer is ready for a char, */
|
||||
/* give it one */
|
||||
@ -695,6 +755,7 @@ nlptwrite(dev_t dev, struct uio *uio, int ioflag)
|
||||
return(err);
|
||||
}
|
||||
}
|
||||
|
||||
/* check to see if we must do a polled write */
|
||||
if(!(sc->sc_irq & LP_USE_IRQ) && (sc->sc_xfercnt)) {
|
||||
nlprintf(("p"));
|
||||
@ -809,15 +870,35 @@ nlptioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
|
||||
* this gets syslog'd.
|
||||
*/
|
||||
old_sc_irq = sc->sc_irq;
|
||||
if(*(int*)data == 0)
|
||||
switch(*(int*)data) {
|
||||
case 0:
|
||||
sc->sc_irq &= (~LP_ENABLE_IRQ);
|
||||
else
|
||||
break;
|
||||
case 1:
|
||||
sc->sc_irq &= (~LP_ENABLE_EXT);
|
||||
sc->sc_irq |= LP_ENABLE_IRQ;
|
||||
break;
|
||||
case 2:
|
||||
/* classic irq based transfer and advanced
|
||||
* modes are in conflict
|
||||
*/
|
||||
sc->sc_irq &= (~LP_ENABLE_IRQ);
|
||||
sc->sc_irq |= LP_ENABLE_EXT;
|
||||
break;
|
||||
case 3:
|
||||
sc->sc_irq &= (~LP_ENABLE_EXT);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (old_sc_irq != sc->sc_irq )
|
||||
log(LOG_NOTICE, LPT_NAME "%d: switched to %s mode\n",
|
||||
log(LOG_NOTICE, LPT_NAME "%d: switched to %s %s mode\n",
|
||||
unit,
|
||||
(sc->sc_irq & LP_ENABLE_IRQ)?
|
||||
"interrupt-driven":"polled");
|
||||
"interrupt-driven":"polled",
|
||||
(sc->sc_irq & LP_ENABLE_EXT)?
|
||||
"extended":"standard");
|
||||
} else /* polled port */
|
||||
error = EOPNOTSUPP;
|
||||
break;
|
||||
|
@ -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: nlpt.h,v 1.1 1997/08/14 13:57:40 msmith Exp $
|
||||
* $Id: nlpt.h,v 1.2 1997/08/16 14:05:32 msmith Exp $
|
||||
*/
|
||||
#ifndef __NLPT_H
|
||||
#define __NLPT_H
|
||||
@ -61,13 +61,15 @@ struct lpt_data {
|
||||
#define LP_AUTOLF 0x40 /* tell printer to do an automatic lf */
|
||||
#define LP_BYPASS 0x80 /* bypass printer ready checks */
|
||||
struct buf *sc_inbuf;
|
||||
struct buf *sc_statbuf;
|
||||
short sc_xfercnt ;
|
||||
char sc_primed;
|
||||
char *sc_cp ;
|
||||
u_char sc_irq ; /* IRQ status of port */
|
||||
u_short sc_irq ; /* IRQ status of port */
|
||||
#define LP_HAS_IRQ 0x01 /* we have an irq available */
|
||||
#define LP_USE_IRQ 0x02 /* we are using our irq */
|
||||
#define LP_ENABLE_IRQ 0x04 /* enable IRQ on open */
|
||||
#define LP_ENABLE_EXT 0x10 /* we shall use advanced mode when possible */
|
||||
u_char sc_backoff ; /* time to call lptout() again */
|
||||
|
||||
#ifdef DEVFS
|
||||
|
@ -23,11 +23,15 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: ppb_1284.c,v 1.5 1998/09/13 18:26:26 nsouch Exp $
|
||||
* $Id: ppb_1284.c,v 1.6 1998/09/13 20:44:55 nsouch Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
#include "opt_debug_1284.h"
|
||||
/*
|
||||
* General purpose routines for the IEEE1284-1994 Standard
|
||||
*/
|
||||
|
||||
#include "opt_ppb_1284.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
@ -42,25 +46,415 @@
|
||||
*
|
||||
* Wait for the peripherial up to 40ms
|
||||
*/
|
||||
int
|
||||
static int
|
||||
do_1284_wait(struct ppb_device *dev, char mask, char status)
|
||||
{
|
||||
int i;
|
||||
char r;
|
||||
return (ppb_poll_device(dev, 4, mask, status, PPB_NOINTR | PPB_POLL));
|
||||
}
|
||||
|
||||
/* try up to 5ms */
|
||||
for (i = 0; i < 20; i++) {
|
||||
r = ppb_rstr(dev);
|
||||
DELAY(25);
|
||||
if ((r & mask) == status)
|
||||
return (0);
|
||||
}
|
||||
|
||||
return (ppb_poll_device(dev, 4, mask, status, PPB_NOINTR));
|
||||
static int
|
||||
do_peripheral_wait(struct ppb_device *dev, char mask, char status)
|
||||
{
|
||||
return (ppb_poll_device(dev, 100, mask, status, PPB_NOINTR | PPB_POLL));
|
||||
}
|
||||
|
||||
#define nibble2char(s) (((s & ~nACK) >> 3) | (~s & nBUSY) >> 4)
|
||||
|
||||
/*
|
||||
* ppb_1284_reset_error()
|
||||
*
|
||||
* Unconditionaly reset the error field
|
||||
*/
|
||||
static int
|
||||
ppb_1284_reset_error(struct ppb_device *dev, int state)
|
||||
{
|
||||
dev->ppb->error = PPB_NO_ERROR;
|
||||
dev->ppb->state = state;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* ppb_1284_get_state()
|
||||
*
|
||||
* Get IEEE1284 state
|
||||
*/
|
||||
static int
|
||||
ppb_1284_get_state(struct ppb_device *dev)
|
||||
{
|
||||
return (dev->ppb->state);
|
||||
}
|
||||
|
||||
/*
|
||||
* ppb_1284_set_state()
|
||||
*
|
||||
* Change IEEE1284 state if no error occured
|
||||
*/
|
||||
static int
|
||||
ppb_1284_set_state(struct ppb_device *dev, int state)
|
||||
{
|
||||
/* call ppb_1284_reset_error() if you absolutly want to change
|
||||
* the state from PPB_ERROR to another */
|
||||
if ((dev->ppb->state != PPB_ERROR) &&
|
||||
(dev->ppb->error == PPB_NO_ERROR)) {
|
||||
dev->ppb->state = state;
|
||||
dev->ppb->error = PPB_NO_ERROR;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
ppb_1284_set_error(struct ppb_device *dev, int error, int event)
|
||||
{
|
||||
/* do not accumulate errors */
|
||||
if ((dev->ppb->error == PPB_NO_ERROR) &&
|
||||
(dev->ppb->state != PPB_ERROR)) {
|
||||
dev->ppb->error = error;
|
||||
dev->ppb->state = PPB_ERROR;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_1284
|
||||
printf("ppb1284: error=%d status=0x%x event=%d\n", error,
|
||||
ppb_rstr(dev) & 0xff, event);
|
||||
#endif
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* ppb_request_mode()
|
||||
*
|
||||
* Converts mode+options into ext. value
|
||||
*/
|
||||
static int
|
||||
ppb_request_mode(int mode, int options)
|
||||
{
|
||||
int request_mode = 0;
|
||||
|
||||
if (options & PPB_EXTENSIBILITY_LINK) {
|
||||
request_mode = EXT_LINK_1284_NORMAL;
|
||||
|
||||
} else {
|
||||
switch (mode) {
|
||||
case PPB_NIBBLE:
|
||||
request_mode = (options & PPB_REQUEST_ID) ?
|
||||
NIBBLE_1284_REQUEST_ID :
|
||||
NIBBLE_1284_NORMAL;
|
||||
break;
|
||||
case PPB_PS2:
|
||||
request_mode = (options & PPB_REQUEST_ID) ?
|
||||
BYTE_1284_REQUEST_ID :
|
||||
BYTE_1284_NORMAL;
|
||||
break;
|
||||
case PPB_ECP:
|
||||
if (options & PPB_USE_RLE)
|
||||
request_mode = (options & PPB_REQUEST_ID) ?
|
||||
ECP_1284_RLE_REQUEST_ID :
|
||||
ECP_1284_RLE;
|
||||
else
|
||||
request_mode = (options & PPB_REQUEST_ID) ?
|
||||
ECP_1284_REQUEST_ID :
|
||||
ECP_1284_NORMAL;
|
||||
break;
|
||||
case PPB_EPP:
|
||||
request_mode = EPP_1284_NORMAL;
|
||||
break;
|
||||
default:
|
||||
panic("%s: unsupported mode %d\n", __FUNCTION__, mode);
|
||||
}
|
||||
}
|
||||
|
||||
return (request_mode);
|
||||
}
|
||||
|
||||
/*
|
||||
* ppb_peripheral_negociate()
|
||||
*
|
||||
* Negociate the peripheral side
|
||||
*/
|
||||
int
|
||||
ppb_peripheral_negociate(struct ppb_device *dev, int mode, int options)
|
||||
{
|
||||
int spin, request_mode, error = 0;
|
||||
char r;
|
||||
|
||||
ppb_set_mode(dev, PPB_COMPATIBLE);
|
||||
ppb_1284_set_state(dev, PPB_PERIPHERAL_NEGOCIATION);
|
||||
|
||||
/* compute ext. value */
|
||||
request_mode = ppb_request_mode(mode, options);
|
||||
|
||||
/* wait host */
|
||||
spin = 10;
|
||||
while (spin-- && (ppb_rstr(dev) & nBUSY))
|
||||
DELAY(1);
|
||||
|
||||
/* check termination */
|
||||
if (!(ppb_rstr(dev) & SELECT) || !spin) {
|
||||
error = ENODEV;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Event 4 - read ext. value */
|
||||
r = ppb_rdtr(dev);
|
||||
|
||||
/* nibble mode is not supported */
|
||||
if ((r == (char)request_mode) ||
|
||||
(r == NIBBLE_1284_NORMAL)) {
|
||||
|
||||
/* Event 5 - restore direction bit, no data avail */
|
||||
ppb_wctr(dev, (STROBE | nINIT) & ~(SELECTIN));
|
||||
DELAY(1);
|
||||
|
||||
/* Event 6 */
|
||||
ppb_wctr(dev, (nINIT) & ~(SELECTIN | STROBE));
|
||||
|
||||
if (r == NIBBLE_1284_NORMAL) {
|
||||
#ifdef DEBUG_1284
|
||||
printf("R");
|
||||
#endif
|
||||
ppb_1284_set_error(dev, PPB_MODE_UNSUPPORTED, 4);
|
||||
error = EINVAL;
|
||||
goto error;
|
||||
} else {
|
||||
ppb_1284_set_state(dev, PPB_PERIPHERAL_IDLE);
|
||||
switch (r) {
|
||||
case BYTE_1284_NORMAL:
|
||||
ppb_set_mode(dev, PPB_BYTE);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#ifdef DEBUG_1284
|
||||
printf("A");
|
||||
#endif
|
||||
/* negociation succeeds */
|
||||
}
|
||||
} else {
|
||||
/* Event 5 - mode not supported */
|
||||
ppb_wctr(dev, SELECTIN);
|
||||
DELAY(1);
|
||||
|
||||
/* Event 6 */
|
||||
ppb_wctr(dev, (SELECTIN) & ~(STROBE | nINIT));
|
||||
ppb_1284_set_error(dev, PPB_MODE_UNSUPPORTED, 4);
|
||||
|
||||
#ifdef DEBUG_1284
|
||||
printf("r");
|
||||
#endif
|
||||
error = EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
return (0);
|
||||
|
||||
error:
|
||||
ppb_peripheral_terminate(dev, PPB_WAIT);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* ppb_peripheral_terminate()
|
||||
*
|
||||
* Terminate peripheral transfer side
|
||||
*
|
||||
* Always return 0 in compatible mode
|
||||
*/
|
||||
int
|
||||
ppb_peripheral_terminate(struct ppb_device *dev, int how)
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
#ifdef DEBUG_1284
|
||||
printf("t");
|
||||
#endif
|
||||
|
||||
ppb_1284_set_state(dev, PPB_PERIPHERAL_TERMINATION);
|
||||
|
||||
/* Event 22 - wait up to host response time (1s) */
|
||||
if ((error = do_peripheral_wait(dev, SELECT | nBUSY, 0))) {
|
||||
ppb_1284_set_error(dev, PPB_TIMEOUT, 22);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Event 24 */
|
||||
ppb_wctr(dev, (nINIT | STROBE) & ~(AUTOFEED | SELECTIN));
|
||||
|
||||
/* Event 25 - wait up to host response time (1s) */
|
||||
if ((error = do_peripheral_wait(dev, nBUSY, nBUSY))) {
|
||||
ppb_1284_set_error(dev, PPB_TIMEOUT, 25);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Event 26 */
|
||||
ppb_wctr(dev, (SELECTIN | nINIT | STROBE) & ~(AUTOFEED));
|
||||
DELAY(1);
|
||||
/* Event 27 */
|
||||
ppb_wctr(dev, (SELECTIN | nINIT) & ~(STROBE | AUTOFEED));
|
||||
|
||||
/* Event 28 - wait up to host response time (1s) */
|
||||
if ((error = do_peripheral_wait(dev, nBUSY, 0))) {
|
||||
ppb_1284_set_error(dev, PPB_TIMEOUT, 28);
|
||||
goto error;
|
||||
}
|
||||
|
||||
error:
|
||||
ppb_set_mode(dev, PPB_COMPATIBLE);
|
||||
ppb_1284_set_state(dev, PPB_FORWARD_IDLE);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* byte_peripheral_outbyte()
|
||||
*
|
||||
* Write 1 byte in BYTE mode
|
||||
*/
|
||||
static int
|
||||
byte_peripheral_outbyte(struct ppb_device *dev, char *buffer, int last)
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
/* Event 7 */
|
||||
if ((error = do_1284_wait(dev, nBUSY, nBUSY))) {
|
||||
ppb_1284_set_error(dev, PPB_TIMEOUT, 7);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* check termination */
|
||||
if (!(ppb_rstr(dev) & SELECT)) {
|
||||
ppb_peripheral_terminate(dev, PPB_WAIT);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Event 15 - put byte on data lines */
|
||||
#ifdef DEBUG_1284
|
||||
printf("B");
|
||||
#endif
|
||||
ppb_wdtr(dev, *buffer);
|
||||
|
||||
/* Event 9 */
|
||||
ppb_wctr(dev, (AUTOFEED | STROBE) & ~(nINIT | SELECTIN));
|
||||
|
||||
/* Event 10 - wait data read */
|
||||
if ((error = do_peripheral_wait(dev, nBUSY, 0))) {
|
||||
ppb_1284_set_error(dev, PPB_TIMEOUT, 16);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Event 11 */
|
||||
if (!last) {
|
||||
ppb_wctr(dev, (AUTOFEED) & ~(nINIT | STROBE | SELECTIN));
|
||||
} else {
|
||||
ppb_wctr(dev, (nINIT) & ~(STROBE | SELECTIN | AUTOFEED));
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* Event 16 - wait strobe */
|
||||
if ((error = do_peripheral_wait(dev, nACK | nBUSY, 0))) {
|
||||
ppb_1284_set_error(dev, PPB_TIMEOUT, 16);
|
||||
goto error;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* check termination */
|
||||
if (!(ppb_rstr(dev) & SELECT)) {
|
||||
ppb_peripheral_terminate(dev, PPB_WAIT);
|
||||
goto error;
|
||||
}
|
||||
|
||||
error:
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* byte_peripheral_write()
|
||||
*
|
||||
* Write n bytes in BYTE mode
|
||||
*/
|
||||
int
|
||||
byte_peripheral_write(struct ppb_device *dev, char *buffer, int len, int *sent)
|
||||
{
|
||||
int error = 0, i;
|
||||
char r;
|
||||
|
||||
ppb_1284_set_state(dev, PPB_PERIPHERAL_TRANSFER);
|
||||
|
||||
/* wait forever, the remote host is master and should initiate
|
||||
* termination
|
||||
*/
|
||||
for (i=0; i<len; i++) {
|
||||
/* force remote nFAULT low to release the remote waiting
|
||||
* process, if any
|
||||
*/
|
||||
r = ppb_rctr(dev);
|
||||
ppb_wctr(dev, r & ~nINIT);
|
||||
|
||||
#ifdef DEBUG_1284
|
||||
printf("y");
|
||||
#endif
|
||||
/* Event 7 */
|
||||
error = ppb_poll_device(dev, PPB_FOREVER, nBUSY, nBUSY,
|
||||
PPB_INTR);
|
||||
|
||||
if (error && error != EWOULDBLOCK)
|
||||
goto error;
|
||||
|
||||
#ifdef DEBUG_1284
|
||||
printf("b");
|
||||
#endif
|
||||
if ((error = byte_peripheral_outbyte(dev, buffer+i, (i == len-1))))
|
||||
goto error;
|
||||
}
|
||||
error:
|
||||
if (!error)
|
||||
ppb_1284_set_state(dev, PPB_PERIPHERAL_IDLE);
|
||||
|
||||
*sent = i;
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* byte_1284_inbyte()
|
||||
*
|
||||
* Read 1 byte in BYTE mode
|
||||
*/
|
||||
int
|
||||
byte_1284_inbyte(struct ppb_device *dev, char *buffer)
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
/* Event 7 - ready to take data (nAUTO low) */
|
||||
ppb_wctr(dev, (PCD | nINIT | AUTOFEED) & ~(STROBE | SELECTIN));
|
||||
|
||||
/* Event 9 - peripheral set nAck low */
|
||||
if ((error = do_1284_wait(dev, nACK, 0))) {
|
||||
ppb_1284_set_error(dev, PPB_TIMEOUT, 9);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* read the byte */
|
||||
*buffer = ppb_rdtr(dev);
|
||||
|
||||
/* Event 10 - data received, can't accept more */
|
||||
ppb_wctr(dev, (nINIT) & ~(AUTOFEED | STROBE | SELECTIN));
|
||||
|
||||
/* Event 11 - peripheral ack */
|
||||
if ((error = do_1284_wait(dev, nACK, nACK))) {
|
||||
ppb_1284_set_error(dev, PPB_TIMEOUT, 11);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Event 16 - strobe */
|
||||
ppb_wctr(dev, (nINIT | STROBE) & ~(AUTOFEED | SELECTIN));
|
||||
DELAY(3);
|
||||
ppb_wctr(dev, (nINIT) & ~(AUTOFEED | STROBE | SELECTIN));
|
||||
|
||||
error:
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* nibble_1284_inbyte()
|
||||
*
|
||||
@ -73,126 +467,372 @@ nibble_1284_inbyte(struct ppb_device *dev, char *buffer)
|
||||
int i, error;
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
/* ready to take data (nAUTO low) */
|
||||
ppb_wctr(dev, AUTOFEED & ~(STROBE | SELECTIN));
|
||||
|
||||
if ((error = do_1284_wait(dev, nACK, 0)))
|
||||
return (error);
|
||||
/* Event 7 - ready to take data (nAUTO low) */
|
||||
ppb_wctr(dev, (nINIT | AUTOFEED) & ~(STROBE | SELECTIN));
|
||||
|
||||
/* Event 8 - peripheral writes the first nibble */
|
||||
|
||||
/* Event 9 - peripheral set nAck low */
|
||||
if ((error = do_1284_wait(dev, nACK, 0))) {
|
||||
ppb_1284_set_error(dev, PPB_TIMEOUT, 9);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* read nibble */
|
||||
nibble[i] = ppb_rstr(dev);
|
||||
|
||||
/* ack, not ready for another nibble */
|
||||
ppb_wctr(dev, 0 & ~(AUTOFEED | STROBE | SELECTIN));
|
||||
/* Event 10 - ack, nibble received */
|
||||
ppb_wctr(dev, nINIT & ~(AUTOFEED | STROBE | SELECTIN));
|
||||
|
||||
/* wait ack from peripherial */
|
||||
if ((error = do_1284_wait(dev, nACK, nACK)))
|
||||
return (error);
|
||||
/* Event 11 - wait ack from peripherial */
|
||||
if ((error = do_1284_wait(dev, nACK, nACK))) {
|
||||
ppb_1284_set_error(dev, PPB_TIMEOUT, 11);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
*buffer = ((nibble2char(nibble[1]) << 4) & 0xf0) |
|
||||
(nibble2char(nibble[0]) & 0x0f);
|
||||
|
||||
return (0);
|
||||
error:
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* nibble_1284_sync()
|
||||
* spp_1284_read()
|
||||
*
|
||||
* Read in IEEE1284 NIBBLE/BYTE mode
|
||||
*/
|
||||
void
|
||||
nibble_1284_sync(struct ppb_device *dev)
|
||||
int
|
||||
spp_1284_read(struct ppb_device *dev, int mode, char *buffer, int max, int *read)
|
||||
{
|
||||
char ctr;
|
||||
int error = 0, len = 0;
|
||||
int terminate_after_transfer = 1;
|
||||
int state;
|
||||
|
||||
ctr = ppb_rctr(dev);
|
||||
*read = len = 0;
|
||||
|
||||
ppb_wctr(dev, (ctr & ~AUTOFEED) | SELECTIN);
|
||||
if (do_1284_wait(dev, nACK, 0))
|
||||
return;
|
||||
state = ppb_1284_get_state(dev);
|
||||
|
||||
ppb_wctr(dev, ctr | AUTOFEED);
|
||||
do_1284_wait(dev, nACK, nACK);
|
||||
switch (state) {
|
||||
case PPB_FORWARD_IDLE:
|
||||
if ((error = ppb_1284_negociate(dev, mode, 0)))
|
||||
return (error);
|
||||
break;
|
||||
|
||||
ppb_wctr(dev, (ctr & ~AUTOFEED) | SELECTIN);
|
||||
case PPB_REVERSE_IDLE:
|
||||
terminate_after_transfer = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
ppb_1284_terminate(dev);
|
||||
if ((error = ppb_1284_negociate(dev, mode, 0)))
|
||||
return (error);
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
while ((len < max) && !(ppb_rstr(dev) & (nFAULT))) {
|
||||
|
||||
ppb_1284_set_state(dev, PPB_REVERSE_TRANSFER);
|
||||
|
||||
#ifdef DEBUG_1284
|
||||
printf("B");
|
||||
#endif
|
||||
|
||||
switch (mode) {
|
||||
case PPB_NIBBLE:
|
||||
/* read a byte, error means no more data */
|
||||
if (nibble_1284_inbyte(dev, buffer+len))
|
||||
goto end_while;
|
||||
break;
|
||||
case PPB_BYTE:
|
||||
if (byte_1284_inbyte(dev, buffer+len))
|
||||
goto end_while;
|
||||
break;
|
||||
default:
|
||||
error = EINVAL;
|
||||
goto end_while;
|
||||
}
|
||||
len ++;
|
||||
}
|
||||
end_while:
|
||||
|
||||
if (!error)
|
||||
ppb_1284_set_state(dev, PPB_REVERSE_IDLE);
|
||||
|
||||
*read = len;
|
||||
|
||||
if (terminate_after_transfer || error)
|
||||
ppb_1284_terminate(dev);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* ppb_1284_read_id()
|
||||
*
|
||||
*/
|
||||
int
|
||||
ppb_1284_read_id(struct ppb_device *dev, int mode, char *buffer,
|
||||
int max, int *read)
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
/* fill the buffer with 0s */
|
||||
bzero(buffer, max);
|
||||
|
||||
switch (mode) {
|
||||
case PPB_NIBBLE:
|
||||
case PPB_ECP:
|
||||
if ((error = ppb_1284_negociate(dev, PPB_NIBBLE, PPB_REQUEST_ID)))
|
||||
return (error);
|
||||
error = spp_1284_read(dev, PPB_NIBBLE, buffer, max, read);
|
||||
break;
|
||||
case PPB_BYTE:
|
||||
if ((error = ppb_1284_negociate(dev, PPB_BYTE, PPB_REQUEST_ID)))
|
||||
return (error);
|
||||
error = spp_1284_read(dev, PPB_BYTE, buffer, max, read);
|
||||
break;
|
||||
default:
|
||||
panic("%s: unsupported mode %d\n", __FUNCTION__, mode);
|
||||
}
|
||||
|
||||
ppb_1284_terminate(dev);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* ppb_1284_read()
|
||||
*
|
||||
* IEEE1284 read
|
||||
*/
|
||||
int
|
||||
ppb_1284_read(struct ppb_device *dev, int mode, char *buffer,
|
||||
int max, int *read)
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
switch (mode) {
|
||||
case PPB_NIBBLE:
|
||||
case PPB_BYTE:
|
||||
error = spp_1284_read(dev, mode, buffer, max, read);
|
||||
break;
|
||||
default:
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* ppb_1284_negociate()
|
||||
*
|
||||
* IEEE1284 negociation phase
|
||||
*
|
||||
* Normal nibble mode or request device id mode (see ppb_1284.h)
|
||||
*
|
||||
* After negociation, nFAULT is low if data is available
|
||||
*/
|
||||
int
|
||||
ppb_1284_negociate(struct ppb_device *dev, int mode)
|
||||
ppb_1284_negociate(struct ppb_device *dev, int mode, int options)
|
||||
{
|
||||
int error;
|
||||
int phase = 0;
|
||||
int request_mode;
|
||||
|
||||
#ifdef DEBUG_1284
|
||||
printf("n");
|
||||
#endif
|
||||
|
||||
if (ppb_1284_get_state(dev) >= PPB_PERIPHERAL_NEGOCIATION)
|
||||
ppb_peripheral_terminate(dev, PPB_WAIT);
|
||||
|
||||
if (ppb_1284_get_state(dev) != PPB_FORWARD_IDLE)
|
||||
ppb_1284_terminate(dev);
|
||||
|
||||
#ifdef DEBUG_1284
|
||||
printf("%d", mode);
|
||||
#endif
|
||||
|
||||
/* ensure the host is in compatible mode */
|
||||
ppb_set_mode(dev, PPB_COMPATIBLE);
|
||||
|
||||
/* reset error to catch the actual negociation error */
|
||||
ppb_1284_reset_error(dev, PPB_FORWARD_IDLE);
|
||||
|
||||
/* calculate ext. value */
|
||||
request_mode = ppb_request_mode(mode, options);
|
||||
|
||||
/* default state */
|
||||
ppb_wctr(dev, (nINIT | SELECTIN) & ~(STROBE | AUTOFEED));
|
||||
DELAY(1);
|
||||
|
||||
ppb_wdtr(dev, mode);
|
||||
/* enter negociation phase */
|
||||
ppb_1284_set_state(dev, PPB_NEGOCIATION);
|
||||
|
||||
/* Event 0 - put the exten. value on the data lines */
|
||||
ppb_wdtr(dev, request_mode);
|
||||
|
||||
#ifdef PERIPH_1284
|
||||
/* request remote host attention */
|
||||
ppb_wctr(dev, (nINIT | STROBE) & ~(AUTOFEED | SELECTIN));
|
||||
DELAY(1);
|
||||
ppb_wctr(dev, (nINIT) & ~(STROBE | AUTOFEED | SELECTIN));
|
||||
#else
|
||||
DELAY(1);
|
||||
|
||||
#endif /* !PERIPH_1284 */
|
||||
|
||||
/* Event 1 - enter IEEE1284 mode */
|
||||
ppb_wctr(dev, (nINIT | AUTOFEED) & ~(STROBE | SELECTIN));
|
||||
|
||||
if ((error = do_1284_wait(dev, nACK | PERROR | SELECT | nFAULT,
|
||||
PERROR | SELECT | nFAULT)))
|
||||
#ifdef PERIPH_1284
|
||||
/* ignore the PError line, wait a bit more, remote host's
|
||||
* interrupts don't respond fast enough */
|
||||
if (ppb_poll_device(dev, 40, nACK | SELECT | nFAULT,
|
||||
SELECT | nFAULT, PPB_NOINTR | PPB_POLL)) {
|
||||
ppb_1284_set_error(dev, PPB_NOT_IEEE1284, 2);
|
||||
error = ENODEV;
|
||||
goto error;
|
||||
}
|
||||
#else
|
||||
/* Event 2 - trying IEEE1284 dialog */
|
||||
if (do_1284_wait(dev, nACK | PERROR | SELECT | nFAULT,
|
||||
PERROR | SELECT | nFAULT)) {
|
||||
ppb_1284_set_error(dev, PPB_NOT_IEEE1284, 2);
|
||||
error = ENODEV;
|
||||
goto error;
|
||||
}
|
||||
#endif /* !PERIPH_1284 */
|
||||
|
||||
phase = 1;
|
||||
|
||||
/* Event 3 - latch the ext. value to the peripheral */
|
||||
ppb_wctr(dev, (nINIT | STROBE | AUTOFEED) & ~SELECTIN);
|
||||
DELAY(5);
|
||||
DELAY(1);
|
||||
|
||||
/* Event 4 - IEEE1284 device recognized */
|
||||
ppb_wctr(dev, nINIT & ~(SELECTIN | AUTOFEED | STROBE));
|
||||
|
||||
#if 0 /* not respected by most devices */
|
||||
if ((error = do_1284_wait(dev, nACK, nACK)))
|
||||
/* Event 6 - waiting for status lines */
|
||||
if (do_1284_wait(dev, nACK, nACK)) {
|
||||
ppb_1284_set_error(dev, PPB_TIMEOUT, 6);
|
||||
error = EBUSY;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (mode == 0)
|
||||
if ((error = do_1284_wait(dev, SELECT, 0)))
|
||||
/* Event 7 - quering result consider nACK not to misunderstand
|
||||
* a remote computer terminate sequence */
|
||||
if (request_mode == NIBBLE_1284_NORMAL) {
|
||||
if (do_1284_wait(dev, nACK | SELECT, nACK)) {
|
||||
ppb_1284_set_error(dev, PPB_MODE_UNSUPPORTED, 7);
|
||||
error = ENODEV;
|
||||
goto error;
|
||||
else
|
||||
if ((error = do_1284_wait(dev, SELECT, SELECT)))
|
||||
}
|
||||
} else {
|
||||
if (do_1284_wait(dev, nACK | SELECT, SELECT | nACK)) {
|
||||
ppb_1284_set_error(dev, PPB_MODE_UNSUPPORTED, 7);
|
||||
error = ENODEV;
|
||||
goto error;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
switch (mode) {
|
||||
case PPB_NIBBLE:
|
||||
case PPB_PS2:
|
||||
/* enter reverse idle phase */
|
||||
ppb_1284_set_state(dev, PPB_REVERSE_IDLE);
|
||||
break;
|
||||
case PPB_ECP:
|
||||
/* negociation ok, now setup the communication */
|
||||
ppb_1284_set_state(dev, PPB_SETUP);
|
||||
ppb_wctr(dev, (nINIT | AUTOFEED) & ~(SELECTIN | STROBE));
|
||||
|
||||
#ifdef PERIPH_1284
|
||||
/* ignore PError line */
|
||||
if (do_1284_wait(dev, nACK | SELECT | nBUSY,
|
||||
nACK | SELECT | nBUSY)) {
|
||||
ppb_1284_set_error(dev, PPB_TIMEOUT, 30);
|
||||
error = ENODEV;
|
||||
goto error;
|
||||
}
|
||||
#else
|
||||
if (do_1284_wait(dev, nACK | SELECT | PERROR | nBUSY,
|
||||
nACK | SELECT | PERROR | nBUSY)) {
|
||||
ppb_1284_set_error(dev, PPB_TIMEOUT, 30);
|
||||
error = ENODEV;
|
||||
goto error;
|
||||
}
|
||||
#endif /* !PERIPH_1284 */
|
||||
|
||||
/* ok, the host enters the ForwardIdle state */
|
||||
ppb_1284_set_state(dev, PPB_ECP_FORWARD_IDLE);
|
||||
break;
|
||||
case PPB_EPP:
|
||||
ppb_1284_set_state(dev, PPB_EPP_IDLE);
|
||||
break;
|
||||
|
||||
default:
|
||||
panic("%s: unknown mode (%d)!", __FUNCTION__, mode);
|
||||
}
|
||||
ppb_set_mode(dev, mode);
|
||||
|
||||
return (0);
|
||||
|
||||
error:
|
||||
if (bootverbose)
|
||||
printf("%s: status=0x%x %d\n", __FUNCTION__, ppb_rstr(dev), phase);
|
||||
ppb_1284_terminate(dev);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* ppb_1284_terminate()
|
||||
*
|
||||
* IEEE1284 termination phase, return code should ignored since the host
|
||||
* is _always_ in compatible mode after ppb_1284_terminate()
|
||||
*/
|
||||
int
|
||||
ppb_1284_terminate(struct ppb_device *dev, int how)
|
||||
ppb_1284_terminate(struct ppb_device *dev)
|
||||
{
|
||||
int error;
|
||||
|
||||
switch (how) {
|
||||
case VALID_STATE:
|
||||
#ifdef DEBUG_1284
|
||||
printf("T");
|
||||
#endif
|
||||
|
||||
ppb_wctr(dev, SELECTIN & ~(STROBE | AUTOFEED));
|
||||
/* do not reset error here to keep the error that
|
||||
* may occured before the ppb_1284_terminate() call */
|
||||
ppb_1284_set_state(dev, PPB_TERMINATION);
|
||||
|
||||
if ((error = do_1284_wait(dev, nACK | nBUSY | nFAULT, nFAULT)))
|
||||
return (error);
|
||||
#ifdef PERIPH_1284
|
||||
/* request remote host attention */
|
||||
ppb_wctr(dev, (nINIT | STROBE | SELECTIN) & ~(AUTOFEED));
|
||||
DELAY(1);
|
||||
#endif /* PERIPH_1284 */
|
||||
|
||||
ppb_wctr(dev, (SELECTIN | AUTOFEED) & ~STROBE);
|
||||
/* Event 22 - set nSelectin low and nAutoFeed high */
|
||||
ppb_wctr(dev, (nINIT | SELECTIN) & ~(STROBE | AUTOFEED));
|
||||
|
||||
if ((error = do_1284_wait(dev, nACK, nACK)))
|
||||
return (error);
|
||||
|
||||
ppb_wctr(dev, SELECTIN & ~(STROBE | AUTOFEED));
|
||||
break;
|
||||
|
||||
default:
|
||||
return (EINVAL);
|
||||
/* Event 24 - waiting for peripheral, Xflag ignored */
|
||||
if (do_1284_wait(dev, nACK | nBUSY | nFAULT, nFAULT)) {
|
||||
ppb_1284_set_error(dev, PPB_TIMEOUT, 24);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Event 25 - set nAutoFd low */
|
||||
ppb_wctr(dev, (nINIT | SELECTIN | AUTOFEED) & ~STROBE);
|
||||
|
||||
/* Event 26 - compatible mode status is set */
|
||||
|
||||
/* Event 27 - peripheral set nAck high */
|
||||
if (do_1284_wait(dev, nACK, nACK)) {
|
||||
ppb_1284_set_error(dev, PPB_TIMEOUT, 27);
|
||||
}
|
||||
|
||||
/* Event 28 - end termination, return to idle phase */
|
||||
ppb_wctr(dev, (nINIT | SELECTIN) & ~(STROBE | AUTOFEED));
|
||||
|
||||
error:
|
||||
/* return to compatible mode */
|
||||
ppb_set_mode(dev, PPB_COMPATIBLE);
|
||||
ppb_1284_set_state(dev, PPB_FORWARD_IDLE);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
@ -23,7 +23,7 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: ppb_1284.h,v 1.2 1998/08/03 19:14:31 msmith Exp $
|
||||
* $Id: ppb_1284.h,v 1.3 1998/09/13 18:26:26 nsouch Exp $
|
||||
*
|
||||
*/
|
||||
#ifndef __1284_H
|
||||
@ -66,20 +66,59 @@
|
||||
#define Intr nACK
|
||||
|
||||
/* request mode values */
|
||||
#define NIBBLE_1284_NORMAL 0
|
||||
#define NIBBLE_1284_REQUEST_ID 4
|
||||
#define NIBBLE_1284_NORMAL 0x0
|
||||
#define NIBBLE_1284_REQUEST_ID 0x4
|
||||
#define BYTE_1284_NORMAL 0x1
|
||||
#define BYTE_1284_REQUEST_ID 0x5
|
||||
#define ECP_1284_NORMAL 0x10
|
||||
#define ECP_1284_REQUEST_ID 0x14
|
||||
#define ECP_1284_RLE 0x30
|
||||
#define ECP_1284_RLE_REQUEST_ID 0x34
|
||||
#define EPP_1284_NORMAL 0x40
|
||||
#define EXT_LINK_1284_NORMAL 0x80
|
||||
|
||||
/* how to terminate */
|
||||
#define VALID_STATE 0
|
||||
#define IMMEDIATE 1
|
||||
/* ieee1284 mode options */
|
||||
#define PPB_REQUEST_ID 0x1
|
||||
#define PPB_USE_RLE 0x2
|
||||
#define PPB_EXTENSIBILITY_LINK 0x4
|
||||
|
||||
extern int do_1284_wait(struct ppb_device *, char, char);
|
||||
/* ieee1284 errors */
|
||||
#define PPB_NO_ERROR 0
|
||||
#define PPB_MODE_UNSUPPORTED 1 /* mode not supported by peripheral */
|
||||
#define PPB_NOT_IEEE1284 2 /* not an IEEE1284 compliant periph. */
|
||||
#define PPB_TIMEOUT 3 /* timeout */
|
||||
#define PPB_INVALID_MODE 4 /* current mode is incorrect */
|
||||
|
||||
/* ieee1284 host side states */
|
||||
#define PPB_ERROR 0
|
||||
#define PPB_FORWARD_IDLE 1
|
||||
#define PPB_NEGOCIATION 2
|
||||
#define PPB_SETUP 3
|
||||
#define PPB_ECP_FORWARD_IDLE 4
|
||||
#define PPB_FWD_TO_REVERSE 5
|
||||
#define PPB_REVERSE_IDLE 6
|
||||
#define PPB_REVERSE_TRANSFER 7
|
||||
#define PPB_REVERSE_TO_FWD 8
|
||||
#define PPB_EPP_IDLE 9
|
||||
#define PPB_TERMINATION 10
|
||||
|
||||
/* peripheral side states */
|
||||
#define PPB_PERIPHERAL_NEGOCIATION 11
|
||||
#define PPB_PERIPHERAL_IDLE 12
|
||||
#define PPB_PERIPHERAL_TRANSFER 13
|
||||
#define PPB_PERIPHERAL_TERMINATION 14
|
||||
|
||||
extern int nibble_1284_inbyte(struct ppb_device *, char *);
|
||||
extern void nibble_1284_sync(struct ppb_device *);
|
||||
extern int nibble_1284_mode(struct ppb_device *, int);
|
||||
extern int byte_1284_inbyte(struct ppb_device *, char *);
|
||||
extern int spp_1284_read(struct ppb_device *, int, char *, int, int *);
|
||||
|
||||
extern int ppb_1284_negociate(struct ppb_device *, int);
|
||||
extern int ppb_1284_terminate(struct ppb_device *, int how);
|
||||
extern int ppb_1284_negociate(struct ppb_device *, int, int);
|
||||
extern int ppb_1284_terminate(struct ppb_device *);
|
||||
extern int ppb_1284_read_id(struct ppb_device *, int, char *, int, int *);
|
||||
extern int ppb_1284_read(struct ppb_device *, int, char *, int, int *);
|
||||
|
||||
extern int ppb_peripheral_terminate(struct ppb_device *, int);
|
||||
extern int ppb_peripheral_negociate(struct ppb_device *, int, int);
|
||||
extern int byte_peripheral_write(struct ppb_device *, char *, int, int *);
|
||||
|
||||
#endif
|
||||
|
@ -23,12 +23,13 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: ppb_base.c,v 1.4 1998/08/03 19:14:31 msmith Exp $
|
||||
* $Id: ppb_base.c,v 1.5 1998/09/13 18:26:26 nsouch Exp $
|
||||
*
|
||||
*/
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <machine/clock.h>
|
||||
|
||||
#include <dev/ppbus/ppbconf.h>
|
||||
|
||||
@ -70,28 +71,39 @@ int
|
||||
ppb_poll_device(struct ppb_device *dev, int max,
|
||||
char mask, char status, int how)
|
||||
{
|
||||
int i, error;
|
||||
int i, j, error;
|
||||
char r;
|
||||
|
||||
for (i = 0; i < max; i++) {
|
||||
/* try at least up to 10ms */
|
||||
for (j = 0; j < ((how & PPB_POLL) ? max : 1); j++) {
|
||||
for (i = 0; i < 10000; i++) {
|
||||
r = ppb_rstr(dev);
|
||||
DELAY(1);
|
||||
if ((r & mask) == status)
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
if (!(how & PPB_POLL)) {
|
||||
for (i = 0; max == PPB_FOREVER || i < max-1; 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);
|
||||
tsleep((caddr_t)dev, PPBPRI, "ppbpoll", hz/100);
|
||||
break;
|
||||
|
||||
case PPB_INTR:
|
||||
default:
|
||||
/* wait 10 ms */
|
||||
if ((error = tsleep((caddr_t)dev, PPBPRI | PCATCH,
|
||||
"ppbpoll", hz/100)))
|
||||
"ppbpoll", hz/100)) != EWOULDBLOCK)
|
||||
return (error);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (EWOULDBLOCK);
|
||||
@ -108,15 +120,30 @@ ppb_set_mode(struct ppb_device *dev, int mode)
|
||||
struct ppb_data *ppb = dev->ppb;
|
||||
int old_mode = ppb_get_mode(dev);
|
||||
|
||||
if ((*ppb->ppb_link->adapter->setmode)(dev->id_unit, mode))
|
||||
if ((*ppb->ppb_link->adapter->setmode)(
|
||||
ppb->ppb_link->adapter_unit, mode))
|
||||
return (-1);
|
||||
|
||||
/* XXX yet device mode = ppbus mode = chipset mode */
|
||||
dev->mode = ppb->mode = mode;
|
||||
dev->mode = ppb->mode = (mode & PPB_MASK);
|
||||
|
||||
return (old_mode);
|
||||
}
|
||||
|
||||
/*
|
||||
* ppb_write()
|
||||
*
|
||||
* Write charaters to the port
|
||||
*/
|
||||
int
|
||||
ppb_write(struct ppb_device *dev, char *buf, int len, int how)
|
||||
{
|
||||
struct ppb_data *ppb = dev->ppb;
|
||||
|
||||
return (ppb->ppb_link->adapter->write(ppb->ppb_link->adapter_unit,
|
||||
buf, len, how));
|
||||
}
|
||||
|
||||
/*
|
||||
* ppb_reset_epp_timeout()
|
||||
*
|
||||
@ -130,7 +157,7 @@ ppb_reset_epp_timeout(struct ppb_device *dev)
|
||||
if (ppb->ppb_owner != dev)
|
||||
return (EACCES);
|
||||
|
||||
(*ppb->ppb_link->adapter->reset_epp_timeout)(dev->id_unit);
|
||||
(*ppb->ppb_link->adapter->reset_epp_timeout)(ppb->ppb_link->adapter_unit);
|
||||
|
||||
return (0);
|
||||
}
|
||||
@ -148,7 +175,7 @@ ppb_ecp_sync(struct ppb_device *dev)
|
||||
if (ppb->ppb_owner != dev)
|
||||
return (EACCES);
|
||||
|
||||
(*ppb->ppb_link->adapter->ecp_sync)(dev->id_unit);
|
||||
(*ppb->ppb_link->adapter->ecp_sync)(ppb->ppb_link->adapter_unit);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
@ -23,7 +23,7 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: ppb_msq.c,v 1.2 1998/09/13 18:26:26 nsouch Exp $
|
||||
* $Id: ppb_msq.c,v 1.3 1998/09/20 14:41:54 nsouch Exp $
|
||||
*
|
||||
*/
|
||||
#include <machine/stdarg.h>
|
||||
@ -272,9 +272,19 @@ ppb_MS_microseq(struct ppb_device *dev, struct ppb_microseq *msq, int *ret)
|
||||
xfer = mode2xfer(dev, mi->opcode);
|
||||
|
||||
/* figure out if we should use ieee1284 code */
|
||||
if (!xfer->loop)
|
||||
panic("%s: IEEE1284 code not supported",
|
||||
__FUNCTION__);
|
||||
if (!xfer->loop) {
|
||||
if (mi->opcode == MS_OP_PUT) {
|
||||
if ((error = ppb->ppb_link->adapter->write(
|
||||
ppb->ppb_link->adapter_unit,
|
||||
(char *)mi->arg[0].p,
|
||||
mi->arg[1].i, 0)))
|
||||
goto error;
|
||||
|
||||
INCR_PC;
|
||||
goto next;
|
||||
} else
|
||||
panic("%s: IEEE1284 read not supported", __FUNCTION__);
|
||||
}
|
||||
|
||||
/* XXX should use ppb_MS_init_msq() */
|
||||
initxfer[0].arg[0].p = mi->arg[0].p;
|
||||
@ -309,10 +319,12 @@ ppb_MS_microseq(struct ppb_device *dev, struct ppb_microseq *msq, int *ret)
|
||||
* is unknown here
|
||||
*/
|
||||
if ((error = ppb->ppb_link->adapter->exec_microseq(
|
||||
dev->id_unit, &mi)))
|
||||
ppb->ppb_link->adapter_unit,
|
||||
&mi)))
|
||||
goto error;
|
||||
break;
|
||||
}
|
||||
next:
|
||||
}
|
||||
error:
|
||||
return (error);
|
||||
|
@ -23,7 +23,7 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: ppb_msq.h,v 1.1.2.7 1998/06/20 19:03:47 son Exp $
|
||||
* $Id: ppb_msq.h,v 1.2 1998/09/13 18:26:26 nsouch Exp $
|
||||
*
|
||||
*/
|
||||
#ifndef __PPB_MSQ_H
|
||||
@ -34,7 +34,7 @@
|
||||
*/
|
||||
|
||||
/* microsequence parameter descriptor */
|
||||
#define MS_INS_MASK 0x00ff /* mask to retrieve the instruction position */
|
||||
#define MS_INS_MASK 0x00ff /* mask to retrieve the instruction position < 256 XXX */
|
||||
#define MS_ARG_MASK 0x0f00 /* mask to retrieve the argument number */
|
||||
#define MS_TYP_MASK 0xf000 /* mask to retrieve the type of the param */
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*-
|
||||
* Copyright (c) 1997, 1998 Nicolas Souchu
|
||||
* Copyright (c) 1997, 1998, 1999 Nicolas Souchu
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -23,7 +23,7 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: ppbconf.c,v 1.8 1998/09/20 14:41:54 nsouch Exp $
|
||||
* $Id: ppbconf.c,v 1.9 1998/12/07 21:58:16 archie Exp $
|
||||
*
|
||||
*/
|
||||
#include <sys/param.h>
|
||||
@ -37,6 +37,8 @@
|
||||
#include <dev/ppbus/ppbconf.h>
|
||||
#include <dev/ppbus/ppb_1284.h>
|
||||
|
||||
#include "opt_ppb_1284.h"
|
||||
|
||||
LIST_HEAD(, ppb_data) ppbdata; /* list of existing ppbus */
|
||||
|
||||
/*
|
||||
@ -80,15 +82,30 @@ ppb_alloc_bus(void)
|
||||
return(ppb);
|
||||
}
|
||||
|
||||
#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
|
||||
|
||||
#ifndef DONTPROBE_1284
|
||||
|
||||
static char *pnp_tokens[] = {
|
||||
"PRINTER", "MODEM", "NET", "HDC", "PCMCIA", "MEDIA",
|
||||
"FDC", "PORTS", "SCANNER", "DIGICAM", "", NULL };
|
||||
|
||||
#if 0
|
||||
static char *pnp_classes[] = {
|
||||
"printer", "modem", "network device",
|
||||
"hard disk", "PCMCIA", "multimedia device",
|
||||
"floppy disk", "ports", "scanner",
|
||||
"digital camera", "unknown device", NULL };
|
||||
#endif
|
||||
|
||||
/*
|
||||
* search_token()
|
||||
@ -134,75 +151,40 @@ search_token(char *str, int slen, char *token)
|
||||
* Returns the class id. of the peripherial, -1 otherwise
|
||||
*/
|
||||
static int
|
||||
ppb_pnp_detect(struct ppb_data *ppb)
|
||||
ppb_pnp_detect(struct ppb_data *ppb, struct ppb_device *pnpdev)
|
||||
{
|
||||
char *token, *q, *class = 0;
|
||||
char *token, *class = 0;
|
||||
int i, len, error;
|
||||
int class_id = -1;
|
||||
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;
|
||||
|
||||
if (bootverbose)
|
||||
printf("ppb: <PnP> probing devices on ppbus %d...\n",
|
||||
printf("Probing for PnP devices on ppbus%d:\n",
|
||||
ppb->ppb_link->adapter_unit);
|
||||
|
||||
if (ppb_request_bus(&pnpdev, PPB_DONTWAIT)) {
|
||||
if (bootverbose)
|
||||
printf("ppb: <PnP> cannot allocate ppbus!\n");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if ((error = ppb_1284_negociate(&pnpdev, NIBBLE_1284_REQUEST_ID))) {
|
||||
if (bootverbose)
|
||||
printf("ppb: <PnP> ppb_1284_negociate()=%d\n", error);
|
||||
|
||||
goto end_detect;
|
||||
}
|
||||
|
||||
len = 0;
|
||||
for (q=str; !(ppb_rstr(&pnpdev) & PERROR); q++) {
|
||||
if ((error = nibble_1284_inbyte(&pnpdev, q))) {
|
||||
if (bootverbose) {
|
||||
*q = '\0';
|
||||
printf("ppb: <PnP> len=%d, %s\n", len, str);
|
||||
printf("ppb: <PnP> nibble_1284_inbyte()=%d\n",
|
||||
error);
|
||||
}
|
||||
goto end_detect;
|
||||
}
|
||||
if ((error = ppb_1284_read_id(pnpdev, PPB_NIBBLE, str,
|
||||
PPB_PnP_STRING_SIZE, &len)))
|
||||
goto end_detect;
|
||||
|
||||
if (len++ >= PPB_PnP_STRING_SIZE) {
|
||||
printf("ppb: <PnP> not space left!\n");
|
||||
goto end_detect;
|
||||
}
|
||||
}
|
||||
*q = '\0';
|
||||
|
||||
nibble_1284_sync(&pnpdev);
|
||||
|
||||
if (bootverbose) {
|
||||
printf("ppb: <PnP> %d characters: ", len);
|
||||
for (i = 0; i < len; i++)
|
||||
printf("0x%x ", str[i]);
|
||||
printf("\n");
|
||||
}
|
||||
#ifdef DEBUG_1284
|
||||
printf("ppb: <PnP> %d characters: ", len);
|
||||
for (i = 0; i < len; i++)
|
||||
printf("%c(0x%x) ", str[i], 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)
|
||||
if ((token = search_token(str, len, "MFG")) != NULL ||
|
||||
(token = search_token(str, len, "MANUFACTURER")) != 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)
|
||||
if ((token = search_token(str, len, "MDL")) != NULL ||
|
||||
(token = search_token(str, len, "MODEL")) != NULL)
|
||||
printf(" %s",
|
||||
search_token(token, UNKNOWN_LENGTH, ":") + 1);
|
||||
else
|
||||
@ -223,7 +205,8 @@ ppb_pnp_detect(struct ppb_data *ppb)
|
||||
printf(" %s", class);
|
||||
}
|
||||
|
||||
if ((token = search_token(str, len, "CMD")) != NULL)
|
||||
if ((token = search_token(str, len, "CMD")) != NULL ||
|
||||
(token = search_token(str, len, "COMMAND")) != NULL)
|
||||
printf(" %s",
|
||||
search_token(token, UNKNOWN_LENGTH, ":") + 1);
|
||||
|
||||
@ -241,13 +224,116 @@ ppb_pnp_detect(struct ppb_data *ppb)
|
||||
class_id = PPB_PnP_UNKNOWN;
|
||||
|
||||
end_detect:
|
||||
if ((error = ppb_1284_terminate(&pnpdev, VALID_STATE)) && bootverbose)
|
||||
printf("ppb: ppb_1284_terminate()=%d\n", error);
|
||||
|
||||
ppb_release_bus(&pnpdev);
|
||||
return (class_id);
|
||||
}
|
||||
|
||||
/*
|
||||
* ppb_scan_bus()
|
||||
*
|
||||
* Scan the ppbus for IEEE1284 compliant devices
|
||||
*/
|
||||
static int
|
||||
ppb_scan_bus(struct ppb_data *ppb)
|
||||
{
|
||||
struct ppb_device pnpdev; /* temporary device to perform I/O */
|
||||
int error = 0;
|
||||
|
||||
/* initialize the pnpdev structure for future use */
|
||||
bzero(&pnpdev, sizeof(pnpdev));
|
||||
pnpdev.ppb = ppb;
|
||||
|
||||
if ((error = ppb_request_bus(&pnpdev, PPB_DONTWAIT))) {
|
||||
if (bootverbose)
|
||||
printf("ppb: cannot allocate ppbus!\n");
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
/* try all IEEE1284 modes, for one device only
|
||||
*
|
||||
* XXX We should implement the IEEE1284.3 standard to detect
|
||||
* daisy chained devices
|
||||
*/
|
||||
|
||||
error = ppb_1284_negociate(&pnpdev, PPB_NIBBLE, PPB_REQUEST_ID);
|
||||
|
||||
if ((ppb->state == PPB_ERROR) && (ppb->error == PPB_NOT_IEEE1284))
|
||||
goto end_scan;
|
||||
|
||||
ppb_1284_terminate(&pnpdev);
|
||||
|
||||
printf("ppc%d: IEEE1284 device found ", ppb->ppb_link->adapter_unit);
|
||||
|
||||
if (!(error = ppb_1284_negociate(&pnpdev, PPB_NIBBLE, 0))) {
|
||||
printf("/NIBBLE");
|
||||
ppb_1284_terminate(&pnpdev);
|
||||
}
|
||||
|
||||
if (!(error = ppb_1284_negociate(&pnpdev, PPB_PS2, 0))) {
|
||||
printf("/PS2");
|
||||
ppb_1284_terminate(&pnpdev);
|
||||
}
|
||||
|
||||
if (!(error = ppb_1284_negociate(&pnpdev, PPB_ECP, 0))) {
|
||||
printf("/ECP");
|
||||
ppb_1284_terminate(&pnpdev);
|
||||
}
|
||||
|
||||
if (!(error = ppb_1284_negociate(&pnpdev, PPB_ECP, PPB_USE_RLE))) {
|
||||
printf("/ECP_RLE");
|
||||
ppb_1284_terminate(&pnpdev);
|
||||
}
|
||||
|
||||
if (!(error = ppb_1284_negociate(&pnpdev, PPB_EPP, 0))) {
|
||||
printf("/EPP");
|
||||
ppb_1284_terminate(&pnpdev);
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (!(error = ppb_1284_negociate(&pnpdev, PPB_NIBBLE, PPB_REQUEST_ID))) {
|
||||
printf("/NIBBLE_ID");
|
||||
ppb_1284_terminate(&pnpdev);
|
||||
}
|
||||
|
||||
if (!(error = ppb_1284_negociate(&pnpdev, PPB_PS2, PPB_REQUEST_ID))) {
|
||||
printf("/PS2_ID");
|
||||
ppb_1284_terminate(&pnpdev);
|
||||
}
|
||||
|
||||
if (!(error = ppb_1284_negociate(&pnpdev, PPB_ECP, PPB_REQUEST_ID))) {
|
||||
printf("/ECP_ID");
|
||||
ppb_1284_terminate(&pnpdev);
|
||||
}
|
||||
|
||||
if (!(error = ppb_1284_negociate(&pnpdev, PPB_ECP,
|
||||
PPB_REQUEST_ID | PPB_USE_RLE))) {
|
||||
printf("/ECP_RLE_ID");
|
||||
ppb_1284_terminate(&pnpdev);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!(error = ppb_1284_negociate(&pnpdev, PPB_COMPATIBLE,
|
||||
PPB_EXTENSIBILITY_LINK))) {
|
||||
printf("/Extensibility Link");
|
||||
ppb_1284_terminate(&pnpdev);
|
||||
}
|
||||
|
||||
printf(" in FORWARD_IDLE state\n");
|
||||
|
||||
/* detect PnP devices */
|
||||
ppb->class_id = ppb_pnp_detect(ppb, &pnpdev);
|
||||
|
||||
ppb_release_bus(&pnpdev);
|
||||
|
||||
return (0);
|
||||
|
||||
end_scan:
|
||||
ppb_release_bus(&pnpdev);
|
||||
return (error);
|
||||
}
|
||||
|
||||
#endif /* !DONTPROBE_1284 */
|
||||
|
||||
/*
|
||||
* ppb_attachdevs()
|
||||
*
|
||||
@ -263,11 +349,10 @@ ppb_attachdevs(struct ppb_data *ppb)
|
||||
LIST_INIT(&ppb->ppb_devs); /* initialise device/driver list */
|
||||
p_drvpp = (struct ppb_driver **)ppbdriver_set.ls_items;
|
||||
|
||||
/* XXX wait for ieee1284 good support */
|
||||
#if 0
|
||||
/* detect PnP devices */
|
||||
ppb->class_id = ppb_pnp_detect(ppb);
|
||||
#endif
|
||||
#ifndef DONTPROBE_1284
|
||||
/* detect IEEE1284 compliant devices */
|
||||
ppb_scan_bus(ppb);
|
||||
#endif /* !DONTPROBE_1284 */
|
||||
|
||||
/*
|
||||
* Blindly try all probes here. Later we should look at
|
||||
|
@ -23,7 +23,7 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: ppbconf.h,v 1.8 1998/09/13 18:26:26 nsouch Exp $
|
||||
* $Id: ppbconf.h,v 1.9 1998/09/20 14:41:54 nsouch Exp $
|
||||
*
|
||||
*/
|
||||
#ifndef __PPBCONF_H
|
||||
@ -47,7 +47,12 @@
|
||||
#define PPB_EPP 0x4 /* EPP mode, 32 bit */
|
||||
#define PPB_ECP 0x8 /* ECP mode */
|
||||
|
||||
#define PPB_SPP PPB_NIBBLE|PPB_PS2
|
||||
/* mode aliases */
|
||||
#define PPB_SPP PPB_NIBBLE|PPB_PS2
|
||||
#define PPB_BYTE PPB_PS2
|
||||
|
||||
#define PPB_MASK 0x0f
|
||||
#define PPB_OPTIONS_MASK 0xf0
|
||||
|
||||
#define PPB_IS_EPP(mode) (mode & PPB_EPP)
|
||||
#define PPB_IN_EPP_MODE(dev) (PPB_IS_EPP (ppb_get_mode (dev)))
|
||||
@ -103,6 +108,8 @@ struct ppb_status {
|
||||
#define PPB_NOINTR 0
|
||||
#define PPB_WAIT 0x1
|
||||
#define PPB_INTR 0x2
|
||||
#define PPB_POLL 0x4
|
||||
#define PPB_FOREVER -1
|
||||
|
||||
/*
|
||||
* Microsequence stuff.
|
||||
@ -144,14 +151,14 @@ struct ppb_context {
|
||||
struct microseq *curmsq; /* currently executed microseqence */
|
||||
};
|
||||
|
||||
|
||||
struct ppb_device {
|
||||
|
||||
int id_unit; /* unit of the device */
|
||||
char *name; /* name of the device */
|
||||
|
||||
ushort mode; /* current mode of the device */
|
||||
ushort avm; /* available modes of the device */
|
||||
ushort avm; /* available IEEE1284 modes of
|
||||
* the device */
|
||||
|
||||
struct ppb_context ctx; /* context of the device */
|
||||
|
||||
@ -184,6 +191,8 @@ struct ppb_adapter {
|
||||
int (*exec_microseq)(int, struct ppb_microseq **);
|
||||
|
||||
int (*setmode)(int, int);
|
||||
int (*read)(int, char *, int, int);
|
||||
int (*write)(int, char *, int, int);
|
||||
|
||||
void (*outsb_epp)(int, char *, int);
|
||||
void (*outsw_epp)(int, char *, int);
|
||||
@ -230,7 +239,7 @@ struct ppb_link {
|
||||
/*
|
||||
* Maximum size of the PnP info string
|
||||
*/
|
||||
#define PPB_PnP_STRING_SIZE 128 /* XXX */
|
||||
#define PPB_PnP_STRING_SIZE 256 /* XXX */
|
||||
|
||||
/*
|
||||
* Parallel Port Bus structure.
|
||||
@ -250,10 +259,11 @@ struct ppb_data {
|
||||
#define PPB_PnP_UNKNOWN 10
|
||||
int class_id; /* not a PnP device if class_id < 0 */
|
||||
|
||||
int state; /* current IEEE1284 state */
|
||||
int error; /* last IEEE1284 error */
|
||||
|
||||
ushort mode; /* IEEE 1284-1994 mode
|
||||
* NIBBLE, PS2, EPP or ECP */
|
||||
ushort avm; /* IEEE 1284-1994 available
|
||||
* modes */
|
||||
|
||||
struct ppb_link *ppb_link; /* link to the adapter */
|
||||
struct ppb_device *ppb_owner; /* device which owns the bus */
|
||||
@ -294,6 +304,7 @@ extern int ppb_ecp_sync(struct ppb_device *);
|
||||
extern int ppb_get_status(struct ppb_device *, struct ppb_status *);
|
||||
|
||||
extern int ppb_set_mode(struct ppb_device *, int);
|
||||
extern int ppb_write(struct ppb_device *, char *, int, int);
|
||||
|
||||
/*
|
||||
* These are defined as macros for speedup.
|
||||
|
@ -23,7 +23,7 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: ppi.c,v 1.7 1998/06/07 17:09:49 dfr Exp $
|
||||
* $Id: ppi.c,v 1.8 1998/12/07 21:58:16 archie Exp $
|
||||
*
|
||||
*/
|
||||
#include "ppi.h"
|
||||
@ -34,18 +34,35 @@
|
||||
#include <sys/systm.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/fcntl.h>
|
||||
|
||||
#include <machine/clock.h>
|
||||
|
||||
#include <dev/ppbus/ppbconf.h>
|
||||
#include <dev/ppbus/ppb_msq.h>
|
||||
|
||||
#include "opt_ppb_1284.h"
|
||||
|
||||
#ifdef PERIPH_1284
|
||||
#include <dev/ppbus/ppb_1284.h>
|
||||
#endif
|
||||
|
||||
#include <dev/ppbus/ppi.h>
|
||||
|
||||
#define BUFSIZE 512
|
||||
|
||||
struct ppi_data {
|
||||
|
||||
int ppi_unit;
|
||||
int ppi_flags;
|
||||
#define HAVE_PPBUS (1<<0)
|
||||
#define HAD_PPBUS (1<<1)
|
||||
|
||||
int ppi_count;
|
||||
int ppi_mode; /* IEEE1284 mode */
|
||||
char ppi_buffer[BUFSIZE];
|
||||
|
||||
struct ppb_device ppi_dev;
|
||||
};
|
||||
@ -70,13 +87,41 @@ DATA_SET(ppbdriver_set, ppidriver);
|
||||
static d_open_t ppiopen;
|
||||
static d_close_t ppiclose;
|
||||
static d_ioctl_t ppiioctl;
|
||||
static d_write_t ppiwrite;
|
||||
static d_read_t ppiread;
|
||||
|
||||
#define CDEV_MAJOR 82
|
||||
static struct cdevsw ppi_cdevsw =
|
||||
{ ppiopen, ppiclose, noread, nowrite, /* 82 */
|
||||
{ ppiopen, ppiclose, ppiread, ppiwrite, /* 82 */
|
||||
ppiioctl, nullstop, nullreset, nodevtotty,
|
||||
seltrue, nommap, nostrat, "ppi", NULL, -1 };
|
||||
|
||||
#ifdef PERIPH_1284
|
||||
|
||||
static void
|
||||
ppi_enable_intr(struct ppi_data *ppi)
|
||||
{
|
||||
char r;
|
||||
|
||||
r = ppb_rctr(&ppi->ppi_dev);
|
||||
ppb_wctr(&ppi->ppi_dev, r | IRQENABLE);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
ppi_disable_intr(struct ppi_data *ppi)
|
||||
{
|
||||
char r;
|
||||
|
||||
r = ppb_rctr(&ppi->ppi_dev);
|
||||
ppb_wctr(&ppi->ppi_dev, r & ~IRQENABLE);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#endif /* PERIPH_1284 */
|
||||
|
||||
/*
|
||||
* ppiprobe()
|
||||
*/
|
||||
@ -125,9 +170,72 @@ ppiattach(struct ppb_device *dev)
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Cable
|
||||
* -----
|
||||
*
|
||||
* Use an IEEE1284 compliant (DB25/DB25) cable with the following tricks:
|
||||
*
|
||||
* nStrobe <-> nAck 1 <-> 10
|
||||
* nAutofd <-> Busy 11 <-> 14
|
||||
* nSelectin <-> Select 17 <-> 13
|
||||
* nInit <-> nFault 15 <-> 16
|
||||
*
|
||||
*/
|
||||
static void
|
||||
ppiintr(int unit)
|
||||
{
|
||||
#ifdef PERIPH_1284
|
||||
struct ppi_data *ppi = ppidata[unit];
|
||||
|
||||
ppi_disable_intr(ppi);
|
||||
|
||||
switch (ppi->ppi_dev.ppb->state) {
|
||||
|
||||
/* accept IEEE1284 negociation then wakeup an waiting process to
|
||||
* continue negociation at process level */
|
||||
case PPB_FORWARD_IDLE:
|
||||
/* Event 1 */
|
||||
if ((ppb_rstr(&ppi->ppi_dev) & (SELECT | nBUSY)) ==
|
||||
(SELECT | nBUSY)) {
|
||||
/* IEEE1284 negociation */
|
||||
#ifdef DEBUG_1284
|
||||
printf("N");
|
||||
#endif
|
||||
|
||||
/* Event 2 - prepare for reading the ext. value */
|
||||
ppb_wctr(&ppi->ppi_dev, (PCD | STROBE | nINIT) & ~SELECTIN);
|
||||
|
||||
ppi->ppi_dev.ppb->state = PPB_NEGOCIATION;
|
||||
|
||||
} else {
|
||||
#ifdef DEBUG_1284
|
||||
printf("0x%x", ppb_rstr(&ppi->ppi_dev));
|
||||
#endif
|
||||
ppb_peripheral_terminate(&ppi->ppi_dev, PPB_DONTWAIT);
|
||||
break;
|
||||
}
|
||||
|
||||
/* wake up any process waiting for negociation from
|
||||
* remote master host */
|
||||
|
||||
/* XXX should set a variable to warn the process about
|
||||
* the interrupt */
|
||||
|
||||
wakeup(ppi);
|
||||
break;
|
||||
default:
|
||||
#ifdef DEBUG_1284
|
||||
printf("?%d", ppi->ppi_dev.ppb->state);
|
||||
#endif
|
||||
ppi->ppi_dev.ppb->state = PPB_FORWARD_IDLE;
|
||||
ppb_set_mode(&ppi->ppi_dev, PPB_COMPATIBLE);
|
||||
break;
|
||||
}
|
||||
|
||||
ppi_enable_intr(ppi);
|
||||
#endif /* PERIPH_1284 */
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -141,11 +249,16 @@ ppiopen(dev_t dev, int flags, int fmt, struct proc *p)
|
||||
if (unit >= nppi)
|
||||
return (ENXIO);
|
||||
|
||||
if (!(ppi->ppi_flags & HAVE_PPBUS))
|
||||
if ((res = ppb_request_bus(&ppi->ppi_dev, (flags & O_NONBLOCK) ? PPB_DONTWAIT : (PPB_WAIT | PPB_INTR))))
|
||||
if (!(ppi->ppi_flags & HAVE_PPBUS)) {
|
||||
if ((res = ppb_request_bus(&ppi->ppi_dev,
|
||||
(flags & O_NONBLOCK) ? PPB_DONTWAIT :
|
||||
(PPB_WAIT | PPB_INTR))))
|
||||
return (res);
|
||||
|
||||
ppi->ppi_flags |= HAVE_PPBUS;
|
||||
ppi->ppi_flags |= HAVE_PPBUS;
|
||||
}
|
||||
ppi->ppi_count += 1;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -155,12 +268,206 @@ ppiclose(dev_t dev, int flags, int fmt, struct proc *p)
|
||||
u_int unit = minor(dev);
|
||||
struct ppi_data *ppi = ppidata[unit];
|
||||
|
||||
if (ppi->ppi_flags & HAVE_PPBUS)
|
||||
ppi->ppi_count --;
|
||||
if (!ppi->ppi_count) {
|
||||
|
||||
#ifdef PERIPH_1284
|
||||
switch (ppi->ppi_dev.ppb->state) {
|
||||
case PPB_PERIPHERAL_IDLE:
|
||||
ppb_peripheral_terminate(&ppi->ppi_dev, 0);
|
||||
break;
|
||||
case PPB_REVERSE_IDLE:
|
||||
case PPB_EPP_IDLE:
|
||||
case PPB_ECP_FORWARD_IDLE:
|
||||
default:
|
||||
ppb_1284_terminate(&ppi->ppi_dev);
|
||||
break;
|
||||
}
|
||||
#endif /* PERIPH_1284 */
|
||||
|
||||
ppb_release_bus(&ppi->ppi_dev);
|
||||
ppi->ppi_flags &= ~HAVE_PPBUS;
|
||||
ppi->ppi_flags &= ~HAVE_PPBUS;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* ppiread()
|
||||
*
|
||||
* IEEE1284 compliant read.
|
||||
*
|
||||
* First, try negociation to BYTE then NIBBLE mode
|
||||
* If no data is available, wait for it otherwise transfer as much as possible
|
||||
*/
|
||||
static int
|
||||
ppiread(dev_t dev, struct uio *uio, int ioflag)
|
||||
{
|
||||
#ifdef PERIPH_1284
|
||||
u_int unit = minor(dev);
|
||||
struct ppi_data *ppi = ppidata[unit];
|
||||
int len, error = 0;
|
||||
|
||||
switch (ppi->ppi_dev.ppb->state) {
|
||||
case PPB_PERIPHERAL_IDLE:
|
||||
ppb_peripheral_terminate(&ppi->ppi_dev, 0);
|
||||
/* fall throught */
|
||||
|
||||
case PPB_FORWARD_IDLE:
|
||||
/* if can't negociate NIBBLE mode then try BYTE mode,
|
||||
* the peripheral may be a computer
|
||||
*/
|
||||
if ((ppb_1284_negociate(&ppi->ppi_dev,
|
||||
ppi->ppi_mode = PPB_NIBBLE, 0))) {
|
||||
|
||||
/* XXX Wait 2 seconds to let the remote host some
|
||||
* time to terminate its interrupt
|
||||
*/
|
||||
tsleep(ppi, PPBPRI, "ppiread", 2*hz);
|
||||
|
||||
if ((error = ppb_1284_negociate(&ppi->ppi_dev,
|
||||
ppi->ppi_mode = PPB_BYTE, 0)))
|
||||
return (error);
|
||||
}
|
||||
break;
|
||||
|
||||
case PPB_REVERSE_IDLE:
|
||||
case PPB_EPP_IDLE:
|
||||
case PPB_ECP_FORWARD_IDLE:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_1284
|
||||
printf("N");
|
||||
#endif
|
||||
/* read data */
|
||||
len = 0;
|
||||
while (uio->uio_resid) {
|
||||
if ((error = ppb_1284_read(&ppi->ppi_dev, ppi->ppi_mode,
|
||||
ppi->ppi_buffer, min(BUFSIZE, uio->uio_resid),
|
||||
&len))) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!len)
|
||||
goto error; /* no more data */
|
||||
|
||||
#ifdef DEBUG_1284
|
||||
printf("d");
|
||||
#endif
|
||||
if ((error = uiomove(ppi->ppi_buffer, len, uio)))
|
||||
goto error;
|
||||
}
|
||||
|
||||
error:
|
||||
|
||||
#else /* PERIPH_1284 */
|
||||
int error = ENODEV;
|
||||
#endif
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* ppiwrite()
|
||||
*
|
||||
* IEEE1284 compliant write
|
||||
*
|
||||
* Actually, this is the peripheral side of a remote IEEE1284 read
|
||||
*
|
||||
* The first part of the negociation (IEEE1284 device detection) is
|
||||
* done at interrupt level, then the remaining is done by the writing
|
||||
* process
|
||||
*
|
||||
* Once negociation done, transfer data
|
||||
*/
|
||||
static int
|
||||
ppiwrite(dev_t dev, struct uio *uio, int ioflag)
|
||||
{
|
||||
#ifdef PERIPH_1284
|
||||
u_int unit = minor(dev);
|
||||
struct ppi_data *ppi = ppidata[unit];
|
||||
struct ppb_data *ppb = ppi->ppi_dev.ppb;
|
||||
int len, error = 0, sent;
|
||||
|
||||
#if 0
|
||||
int ret;
|
||||
|
||||
#define ADDRESS MS_PARAM(0, 0, MS_TYP_PTR)
|
||||
#define LENGTH MS_PARAM(0, 1, MS_TYP_INT)
|
||||
|
||||
struct ppb_microseq msq[] = {
|
||||
{ MS_OP_PUT, { MS_UNKNOWN, MS_UNKNOWN, MS_UNKNOWN } },
|
||||
MS_RET(0)
|
||||
};
|
||||
|
||||
/* negociate ECP mode */
|
||||
if (ppb_1284_negociate(&ppi->ppi_dev, PPB_ECP, 0)) {
|
||||
printf("ppiwrite: ECP negociation failed\n");
|
||||
}
|
||||
|
||||
while (!error && (len = min(uio->uio_resid, BUFSIZE))) {
|
||||
uiomove(ppi->ppi_buffer, len, uio);
|
||||
|
||||
ppb_MS_init_msq(msq, 2, ADDRESS, ppi->ppi_buffer, LENGTH, len);
|
||||
|
||||
error = ppb_MS_microseq(&ppi->ppi_dev, msq, &ret);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* we have to be peripheral to be able to send data, so
|
||||
* wait for the appropriate state
|
||||
*/
|
||||
if (ppb->state < PPB_PERIPHERAL_NEGOCIATION)
|
||||
ppb_1284_terminate(&ppi->ppi_dev);
|
||||
|
||||
while (ppb->state != PPB_PERIPHERAL_IDLE) {
|
||||
/* XXX should check a variable before sleeping */
|
||||
#ifdef DEBUG_1284
|
||||
printf("s");
|
||||
#endif
|
||||
|
||||
ppi_enable_intr(ppi);
|
||||
|
||||
/* sleep until IEEE1284 negociation starts */
|
||||
error = tsleep(ppi, PCATCH | PPBPRI, "ppiwrite", 0);
|
||||
|
||||
switch (error) {
|
||||
case 0:
|
||||
/* negociate peripheral side with BYTE mode */
|
||||
ppb_peripheral_negociate(&ppi->ppi_dev, PPB_BYTE, 0);
|
||||
break;
|
||||
case EWOULDBLOCK:
|
||||
break;
|
||||
default:
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG_1284
|
||||
printf("N");
|
||||
#endif
|
||||
|
||||
/* negociation done, write bytes to master host */
|
||||
while (len = min(uio->uio_resid, BUFSIZE)) {
|
||||
uiomove(ppi->ppi_buffer, len, uio);
|
||||
if ((error = byte_peripheral_write(&ppi->ppi_dev,
|
||||
ppi->ppi_buffer, len, &sent)))
|
||||
goto error;
|
||||
#ifdef DEBUG_1284
|
||||
printf("d");
|
||||
#endif
|
||||
}
|
||||
|
||||
error:
|
||||
|
||||
#else /* PERIPH_1284 */
|
||||
int error = ENODEV;
|
||||
#endif
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
ppiioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
|
||||
{
|
||||
@ -208,7 +515,6 @@ ppiioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
|
||||
case PPISFIFO: /* write FIFO */
|
||||
ppb_wfifo(&ppi->ppi_dev, *val);
|
||||
break;
|
||||
|
||||
default:
|
||||
error = ENOTTY;
|
||||
break;
|
||||
|
@ -23,7 +23,7 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: vpo.c,v 1.9 1998/12/07 21:58:16 archie Exp $
|
||||
* $Id: vpo.c,v 1.10 1999/01/09 18:05:46 nsouch Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
@ -51,6 +51,8 @@
|
||||
#include <sys/kernel.h>
|
||||
#endif /*KERNEL */
|
||||
|
||||
#include "opt_vpo.h"
|
||||
|
||||
#include <dev/ppbus/ppbconf.h>
|
||||
#include <dev/ppbus/vpoio.h>
|
||||
|
||||
|
@ -23,7 +23,7 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: vpoio.c,v 1.3 1998/09/20 14:41:54 nsouch Exp $
|
||||
* $Id: vpoio.c,v 1.4 1998/12/07 21:58:16 archie Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
@ -41,6 +41,8 @@
|
||||
#include <sys/kernel.h>
|
||||
#endif /*KERNEL */
|
||||
|
||||
#include "opt_vpo.h"
|
||||
|
||||
#include <dev/ppbus/ppbconf.h>
|
||||
#include <dev/ppbus/ppb_msq.h>
|
||||
#include <dev/ppbus/vpoio.h>
|
||||
@ -284,8 +286,13 @@ vpoio_connect(struct vpoio_data *vpo, int how)
|
||||
int error;
|
||||
int ret;
|
||||
|
||||
if ((error = ppb_request_bus(&vpo->vpo_dev, how)))
|
||||
if ((error = ppb_request_bus(&vpo->vpo_dev, how))) {
|
||||
|
||||
#ifdef VP0_DEBUG
|
||||
printf("%s: can't request bus!\n", __FUNCTION__);
|
||||
#endif
|
||||
return error;
|
||||
}
|
||||
|
||||
if (PPB_IN_EPP_MODE(&vpo->vpo_dev))
|
||||
ppb_MS_microseq(&vpo->vpo_dev, connect_epp_microseq, &ret);
|
||||
@ -437,8 +444,8 @@ vpoio_outstr(struct vpoio_data *vpo, char *buffer, int size)
|
||||
ppb_wctr(&vpo->vpo_dev,
|
||||
H_AUTO | H_nSELIN | H_INIT | H_STROBE);
|
||||
}
|
||||
/* ppb_ecp_sync(&vpo->vpo_dev); */
|
||||
#endif
|
||||
ppb_ecp_sync(&vpo->vpo_dev);
|
||||
|
||||
return (error);
|
||||
}
|
||||
@ -476,8 +483,8 @@ vpoio_instr(struct vpoio_data *vpo, char *buffer, int size)
|
||||
ppb_wctr(&vpo->vpo_dev, PCD |
|
||||
H_AUTO | H_nSELIN | H_INIT | H_STROBE);
|
||||
}
|
||||
/* ppb_ecp_sync(&vpo->vpo_dev); */
|
||||
#endif
|
||||
ppb_ecp_sync(&vpo->vpo_dev);
|
||||
|
||||
return (error);
|
||||
}
|
||||
@ -701,6 +708,10 @@ vpoio_reset_bus(struct vpoio_data *vpo)
|
||||
{
|
||||
/* first, connect to the drive */
|
||||
if (vpoio_connect(vpo, PPB_WAIT|PPB_INTR) || !vpoio_in_disk_mode(vpo)) {
|
||||
|
||||
#ifdef VP0_DEBUG
|
||||
printf("%s: not in disk mode!\n", __FUNCTION__);
|
||||
#endif
|
||||
/* release ppbus */
|
||||
vpoio_disconnect(vpo);
|
||||
return (1);
|
||||
|
@ -23,7 +23,7 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: ppc.c,v 1.12 1998/12/07 21:58:22 archie Exp $
|
||||
* $Id: ppc.c,v 1.13 1998/12/30 00:37:42 hoek Exp $
|
||||
*
|
||||
*/
|
||||
#include "ppc.h"
|
||||
@ -49,6 +49,11 @@
|
||||
|
||||
#include <i386/isa/ppcreg.h>
|
||||
|
||||
#include "opt_ppc.h"
|
||||
|
||||
#define LOG_PPC(function, ppc, string) \
|
||||
if (bootverbose) printf("%s: %s\n", function, string)
|
||||
|
||||
static int ppcprobe(struct isa_device *);
|
||||
static int ppcattach(struct isa_device *);
|
||||
|
||||
@ -130,6 +135,9 @@ static int ppc_exec_microseq(int, struct ppb_microseq **);
|
||||
static int ppc_generic_setmode(int, int);
|
||||
static int ppc_smclike_setmode(int, int);
|
||||
|
||||
static int ppc_read(int, char *, int, int);
|
||||
static int ppc_write(int, char *, int, int);
|
||||
|
||||
static struct ppb_adapter ppc_smclike_adapter = {
|
||||
|
||||
0, /* no intr handler, filled by chipset dependent code */
|
||||
@ -138,7 +146,7 @@ static struct ppb_adapter ppc_smclike_adapter = {
|
||||
|
||||
ppc_exec_microseq,
|
||||
|
||||
ppc_smclike_setmode,
|
||||
ppc_smclike_setmode, ppc_read, ppc_write,
|
||||
|
||||
ppc_outsb_epp, ppc_outsw_epp, ppc_outsl_epp,
|
||||
ppc_insb_epp, ppc_insw_epp, ppc_insl_epp,
|
||||
@ -155,7 +163,7 @@ static struct ppb_adapter ppc_generic_adapter = {
|
||||
|
||||
ppc_exec_microseq,
|
||||
|
||||
ppc_generic_setmode,
|
||||
ppc_generic_setmode, ppc_read, ppc_write,
|
||||
|
||||
ppc_outsb_epp, ppc_outsw_epp, ppc_outsl_epp,
|
||||
ppc_insb_epp, ppc_insw_epp, ppc_insl_epp,
|
||||
@ -173,8 +181,11 @@ ppc_ecp_sync(int unit) {
|
||||
struct ppc_data *ppc = ppcdata[unit];
|
||||
int i, r;
|
||||
|
||||
if (!(ppc->ppc_avm & PPB_ECP))
|
||||
return;
|
||||
|
||||
r = r_ecr(ppc);
|
||||
if ((r & 0xe0) != 0x80)
|
||||
if ((r & 0xe0) != PPC_ECR_EPP)
|
||||
return;
|
||||
|
||||
for (i = 0; i < 100; i++) {
|
||||
@ -190,13 +201,115 @@ ppc_ecp_sync(int unit) {
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
ppcintr(int unit)
|
||||
/*
|
||||
* ppc_detect_fifo()
|
||||
*
|
||||
* Detect parallel port FIFO
|
||||
*/
|
||||
static int
|
||||
ppc_detect_fifo(struct ppc_data *ppc)
|
||||
{
|
||||
/* call directly upper code */
|
||||
ppb_intr(&ppcdata[unit]->ppc_link);
|
||||
char ecr_sav;
|
||||
char ctr_sav, ctr, cc;
|
||||
short i;
|
||||
|
||||
/* save registers */
|
||||
ecr_sav = r_ecr(ppc);
|
||||
ctr_sav = r_ctr(ppc);
|
||||
|
||||
return;
|
||||
/* enter ECP configuration mode, no interrupt, no DMA */
|
||||
w_ecr(ppc, 0xf4);
|
||||
|
||||
/* read PWord size - transfers in FIFO mode must be PWord aligned */
|
||||
ppc->ppc_pword = (r_cnfgA(ppc) & PPC_PWORD_MASK);
|
||||
|
||||
/* XXX 16 and 32 bits implementations not supported */
|
||||
if (ppc->ppc_pword != PPC_PWORD_8) {
|
||||
LOG_PPC(__FUNCTION__, ppc, "PWord not supported");
|
||||
goto error;
|
||||
}
|
||||
|
||||
w_ecr(ppc, 0x34); /* byte mode, no interrupt, no DMA */
|
||||
ctr = r_ctr(ppc);
|
||||
w_ctr(ppc, ctr | PCD); /* set direction to 1 */
|
||||
|
||||
/* enter ECP test mode, no interrupt, no DMA */
|
||||
w_ecr(ppc, 0xd4);
|
||||
|
||||
/* flush the FIFO */
|
||||
for (i=0; i<1024; i++) {
|
||||
if (r_ecr(ppc) & PPC_FIFO_EMPTY)
|
||||
break;
|
||||
cc = r_fifo(ppc);
|
||||
}
|
||||
|
||||
if (i >= 1024) {
|
||||
LOG_PPC(__FUNCTION__, ppc, "can't flush FIFO");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* enable interrupts, no DMA */
|
||||
w_ecr(ppc, 0xd0);
|
||||
|
||||
/* determine readIntrThreshold
|
||||
* fill the FIFO until serviceIntr is set
|
||||
*/
|
||||
for (i=0; i<1024; i++) {
|
||||
w_fifo(ppc, (char)i);
|
||||
if (!ppc->ppc_rthr && (r_ecr(ppc) & PPC_SERVICE_INTR)) {
|
||||
/* readThreshold reached */
|
||||
ppc->ppc_rthr = i+1;
|
||||
}
|
||||
if (r_ecr(ppc) & PPC_FIFO_FULL) {
|
||||
ppc->ppc_fifo = i+1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i >= 1024) {
|
||||
LOG_PPC(__FUNCTION__, ppc, "can't fill FIFO");
|
||||
goto error;
|
||||
}
|
||||
|
||||
w_ecr(ppc, 0xd4); /* test mode, no interrupt, no DMA */
|
||||
w_ctr(ppc, ctr & ~PCD); /* set direction to 0 */
|
||||
w_ecr(ppc, 0xd0); /* enable interrupts */
|
||||
|
||||
/* determine writeIntrThreshold
|
||||
* empty the FIFO until serviceIntr is set
|
||||
*/
|
||||
for (i=ppc->ppc_fifo; i>0; i--) {
|
||||
if (r_fifo(ppc) != (char)(ppc->ppc_fifo-i)) {
|
||||
LOG_PPC(__FUNCTION__, ppc, "invalid data in FIFO");
|
||||
goto error;
|
||||
}
|
||||
if (r_ecr(ppc) & PPC_SERVICE_INTR) {
|
||||
/* writeIntrThreshold reached */
|
||||
ppc->ppc_wthr = ppc->ppc_fifo - i+1;
|
||||
}
|
||||
/* if FIFO empty before the last byte, error */
|
||||
if (i>1 && (r_ecr(ppc) & PPC_FIFO_EMPTY)) {
|
||||
LOG_PPC(__FUNCTION__, ppc, "data lost in FIFO");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
/* FIFO must be empty after the last byte */
|
||||
if (!(r_ecr(ppc) & PPC_FIFO_EMPTY)) {
|
||||
LOG_PPC(__FUNCTION__, ppc, "can't empty the FIFO");
|
||||
goto error;
|
||||
}
|
||||
|
||||
w_ctr(ppc, ctr_sav);
|
||||
w_ecr(ppc, ecr_sav);
|
||||
|
||||
return (0);
|
||||
|
||||
error:
|
||||
w_ctr(ppc, ctr_sav);
|
||||
w_ecr(ppc, ecr_sav);
|
||||
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -654,6 +767,13 @@ ppc_smc37c66xgt_detect(struct ppc_data *ppc, int chipset_mode)
|
||||
ppc->ppc_avm = chipset_mode;
|
||||
}
|
||||
|
||||
/* set FIFO threshold to 16 */
|
||||
if (ppc->ppc_avm & PPB_ECP) {
|
||||
/* select CRA */
|
||||
outb(csr, 0xa);
|
||||
outb(cio, 16);
|
||||
}
|
||||
|
||||
end_detect:
|
||||
|
||||
if (bootverbose)
|
||||
@ -884,14 +1004,14 @@ ppc_generic_detect(struct ppc_data *ppc, int chipset_mode)
|
||||
|
||||
if (!chipset_mode) {
|
||||
/* first, check for ECP */
|
||||
w_ecr(ppc, 0x20);
|
||||
if ((r_ecr(ppc) & 0xe0) == 0x20) {
|
||||
w_ecr(ppc, PPC_ECR_PS2);
|
||||
if ((r_ecr(ppc) & 0xe0) == PPC_ECR_PS2) {
|
||||
ppc->ppc_avm |= PPB_ECP | PPB_SPP;
|
||||
if (bootverbose)
|
||||
printf(" ECP SPP");
|
||||
|
||||
/* search for SMC style ECP+EPP mode */
|
||||
w_ecr(ppc, 0x80);
|
||||
w_ecr(ppc, PPC_ECR_EPP);
|
||||
}
|
||||
|
||||
/* try to reset EPP timeout bit */
|
||||
@ -911,7 +1031,7 @@ ppc_generic_detect(struct ppc_data *ppc, int chipset_mode)
|
||||
}
|
||||
} else {
|
||||
/* restore to standard mode */
|
||||
w_ecr(ppc, 0x0);
|
||||
w_ecr(ppc, PPC_ECR_STD);
|
||||
}
|
||||
|
||||
/* XXX try to detect NIBBLE and PS2 modes */
|
||||
@ -978,6 +1098,10 @@ ppc_detect(struct ppc_data *ppc, int chipset_mode) {
|
||||
}
|
||||
}
|
||||
|
||||
/* configure/detect ECP FIFO */
|
||||
if ((ppc->ppc_avm & PPB_ECP) && !(ppc->ppc_flags & 0x80))
|
||||
ppc_detect_fifo(ppc);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -1202,6 +1326,244 @@ ppc_exec_microseq(int unit, struct ppb_microseq **p_msq)
|
||||
/* unreached */
|
||||
}
|
||||
|
||||
static void
|
||||
ppcintr(int unit)
|
||||
{
|
||||
struct ppc_data *ppc = ppcdata[unit];
|
||||
char ctr, ecr;
|
||||
|
||||
ctr = r_ctr(ppc);
|
||||
ecr = r_ecr(ppc);
|
||||
|
||||
#ifdef PPC_DEBUG
|
||||
printf("!");
|
||||
#endif
|
||||
|
||||
/* don't use ecp mode with IRQENABLE set */
|
||||
if (ctr & IRQENABLE) {
|
||||
/* call upper code */
|
||||
ppb_intr(&ppc->ppc_link);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctr & nFAULT) {
|
||||
if (ppc->ppc_irqstat & PPC_IRQ_nFAULT) {
|
||||
|
||||
w_ecr(ppc, ecr | PPC_nFAULT_INTR);
|
||||
ppc->ppc_irqstat &= ~PPC_IRQ_nFAULT;
|
||||
} else {
|
||||
/* call upper code */
|
||||
ppb_intr(&ppc->ppc_link);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (ppc->ppc_irqstat & PPC_IRQ_DMA) {
|
||||
/* disable interrupts (should be done by hardware though) */
|
||||
w_ecr(ppc, ecr | PPC_SERVICE_INTR);
|
||||
ppc->ppc_irqstat &= ~PPC_IRQ_DMA;
|
||||
ecr = r_ecr(ppc);
|
||||
|
||||
/* check if DMA completed */
|
||||
if ((ppc->ppc_avm & PPB_ECP) && (ecr & PPC_ENABLE_DMA)) {
|
||||
#ifdef PPC_DEBUG
|
||||
printf("a");
|
||||
#endif
|
||||
/* stop DMA */
|
||||
w_ecr(ppc, ecr & ~PPC_ENABLE_DMA);
|
||||
ecr = r_ecr(ppc);
|
||||
|
||||
if (ppc->ppc_dmastat == PPC_DMA_STARTED) {
|
||||
#ifdef PPC_DEBUG
|
||||
printf("d");
|
||||
#endif
|
||||
isa_dmadone(
|
||||
ppc->ppc_dmaflags,
|
||||
ppc->ppc_dmaddr,
|
||||
ppc->ppc_dmacnt,
|
||||
ppc->ppc_dmachan);
|
||||
|
||||
ppc->ppc_dmastat = PPC_DMA_COMPLETE;
|
||||
|
||||
/* wakeup the waiting process */
|
||||
wakeup((caddr_t)ppc);
|
||||
}
|
||||
}
|
||||
} else if (ppc->ppc_irqstat & PPC_IRQ_FIFO) {
|
||||
|
||||
/* classic interrupt I/O */
|
||||
ppc->ppc_irqstat &= ~PPC_IRQ_FIFO;
|
||||
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int
|
||||
ppc_read(int unit, char *buf, int len, int mode)
|
||||
{
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Call this function if you want to send data in any advanced mode
|
||||
* of your parallel port: FIFO, DMA
|
||||
*
|
||||
* If what you want is not possible (no ECP, no DMA...),
|
||||
* EINVAL is returned
|
||||
*/
|
||||
static int
|
||||
ppc_write(int unit, char *buf, int len, int how)
|
||||
{
|
||||
struct ppc_data *ppc = ppcdata[unit];
|
||||
char ecr, ecr_sav, ctr, ctr_sav;
|
||||
int s, error = 0;
|
||||
int spin;
|
||||
|
||||
#ifdef PPC_DEBUG
|
||||
printf("w");
|
||||
#endif
|
||||
|
||||
ecr_sav = r_ecr(ppc);
|
||||
ctr_sav = r_ctr(ppc);
|
||||
|
||||
/*
|
||||
* Send buffer with DMA, FIFO and interrupts
|
||||
*/
|
||||
if (ppc->ppc_avm & PPB_ECP) {
|
||||
|
||||
if (ppc->ppc_dmachan >= 0) {
|
||||
|
||||
/* byte mode, no intr, no DMA, dir=0, flush fifo
|
||||
*/
|
||||
ecr = PPC_ECR_STD | PPC_DISABLE_INTR;
|
||||
w_ecr(ppc, ecr);
|
||||
|
||||
/* disable nAck interrupts */
|
||||
ctr = r_ctr(ppc);
|
||||
ctr &= ~IRQENABLE;
|
||||
w_ctr(ppc, ctr);
|
||||
|
||||
ppc->ppc_dmaflags = 0;
|
||||
ppc->ppc_dmaddr = (caddr_t)buf;
|
||||
ppc->ppc_dmacnt = (u_int)len;
|
||||
|
||||
switch (ppc->ppc_mode) {
|
||||
case PPB_COMPATIBLE:
|
||||
/* compatible mode with FIFO, no intr, DMA, dir=0 */
|
||||
ecr = PPC_ECR_FIFO | PPC_DISABLE_INTR | PPC_ENABLE_DMA;
|
||||
break;
|
||||
case PPB_ECP:
|
||||
ecr = PPC_ECR_ECP | PPC_DISABLE_INTR | PPC_ENABLE_DMA;
|
||||
break;
|
||||
default:
|
||||
error = EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
w_ecr(ppc, ecr);
|
||||
ecr = r_ecr(ppc);
|
||||
|
||||
/* enter splhigh() not to be preempted
|
||||
* by the dma interrupt, we may miss
|
||||
* the wakeup otherwise
|
||||
*/
|
||||
s = splhigh();
|
||||
|
||||
ppc->ppc_dmastat = PPC_DMA_INIT;
|
||||
|
||||
/* enable interrupts */
|
||||
ecr &= ~PPC_SERVICE_INTR;
|
||||
ppc->ppc_irqstat = PPC_IRQ_DMA;
|
||||
w_ecr(ppc, ecr);
|
||||
|
||||
isa_dmastart(
|
||||
ppc->ppc_dmaflags,
|
||||
ppc->ppc_dmaddr,
|
||||
ppc->ppc_dmacnt,
|
||||
ppc->ppc_dmachan);
|
||||
#ifdef PPC_DEBUG
|
||||
printf("s%d", ppc->ppc_dmacnt);
|
||||
#endif
|
||||
ppc->ppc_dmastat = PPC_DMA_STARTED;
|
||||
|
||||
/* Wait for the DMA completed interrupt. We hope we won't
|
||||
* miss it, otherwise a signal will be necessary to unlock the
|
||||
* process.
|
||||
*/
|
||||
do {
|
||||
/* release CPU */
|
||||
error = tsleep((caddr_t)ppc,
|
||||
PPBPRI | PCATCH, "ppcdma", 0);
|
||||
|
||||
} while (error == EWOULDBLOCK);
|
||||
|
||||
splx(s);
|
||||
|
||||
if (error) {
|
||||
#ifdef PPC_DEBUG
|
||||
printf("i");
|
||||
#endif
|
||||
/* stop DMA */
|
||||
isa_dmadone(
|
||||
ppc->ppc_dmaflags, ppc->ppc_dmaddr,
|
||||
ppc->ppc_dmacnt, ppc->ppc_dmachan);
|
||||
|
||||
/* no dma, no interrupt, flush the fifo */
|
||||
w_ecr(ppc, PPC_ECR_RESET);
|
||||
|
||||
ppc->ppc_dmastat = PPC_DMA_INTERRUPTED;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* wait for an empty fifo */
|
||||
while (!(r_ecr(ppc) & PPC_FIFO_EMPTY)) {
|
||||
|
||||
for (spin=100; spin; spin--)
|
||||
if (r_ecr(ppc) & PPC_FIFO_EMPTY)
|
||||
goto fifo_empty;
|
||||
#ifdef PPC_DEBUG
|
||||
printf("Z");
|
||||
#endif
|
||||
error = tsleep((caddr_t)ppc, PPBPRI | PCATCH, "ppcfifo", hz/100);
|
||||
if (error != EWOULDBLOCK) {
|
||||
#ifdef PPC_DEBUG
|
||||
printf("I");
|
||||
#endif
|
||||
/* no dma, no interrupt, flush the fifo */
|
||||
w_ecr(ppc, PPC_ECR_RESET);
|
||||
|
||||
ppc->ppc_dmastat = PPC_DMA_INTERRUPTED;
|
||||
error = EINTR;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
fifo_empty:
|
||||
/* no dma, no interrupt, flush the fifo */
|
||||
w_ecr(ppc, PPC_ECR_RESET);
|
||||
|
||||
} else
|
||||
error = EINVAL; /* XXX we should FIFO and
|
||||
* interrupts */
|
||||
} else
|
||||
error = EINVAL;
|
||||
|
||||
error:
|
||||
|
||||
/* PDRQ must be kept unasserted until nPDACK is
|
||||
* deasserted for a minimum of 350ns (SMC datasheet)
|
||||
*
|
||||
* Consequence may be a FIFO that never empty
|
||||
*/
|
||||
DELAY(1);
|
||||
|
||||
w_ecr(ppc, ecr_sav);
|
||||
w_ctr(ppc, ctr_sav);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Configure current operating mode
|
||||
*/
|
||||
@ -1209,32 +1571,34 @@ static int
|
||||
ppc_generic_setmode(int unit, int mode)
|
||||
{
|
||||
struct ppc_data *ppc = ppcdata[unit];
|
||||
|
||||
/* back to compatible mode, XXX don't know yet what to do here */
|
||||
if (mode == 0) {
|
||||
ppc->ppc_mode = PPB_COMPATIBLE;
|
||||
return (0);
|
||||
}
|
||||
u_char ecr = 0;
|
||||
|
||||
/* check if mode is available */
|
||||
if (!(ppc->ppc_avm & mode))
|
||||
return (EOPNOTSUPP);
|
||||
if (mode && !(ppc->ppc_avm & mode))
|
||||
return (EINVAL);
|
||||
|
||||
/* if ECP mode, configure ecr register */
|
||||
if (ppc->ppc_avm & PPB_ECP) {
|
||||
/* return to byte mode (keeping direction bit),
|
||||
* no interrupt, no DMA to be able to change to
|
||||
* ECP
|
||||
*/
|
||||
w_ecr(ppc, PPC_ECR_RESET);
|
||||
ecr = PPC_DISABLE_INTR;
|
||||
|
||||
/* XXX disable DMA, enable interrupts */
|
||||
if (mode & PPB_EPP)
|
||||
return (EOPNOTSUPP);
|
||||
else if (mode & PPB_PS2)
|
||||
/* select PS2 mode with ECP */
|
||||
w_ecr(ppc, 0x20);
|
||||
return (EINVAL);
|
||||
else if (mode & PPB_ECP)
|
||||
/* select ECP mode */
|
||||
w_ecr(ppc, 0x60);
|
||||
ecr |= PPC_ECR_ECP;
|
||||
else if (mode & PPB_PS2)
|
||||
/* select PS2 mode with ECP */
|
||||
ecr |= PPC_ECR_PS2;
|
||||
else
|
||||
/* select standard parallel port mode */
|
||||
w_ecr(ppc, 0x00);
|
||||
/* select COMPATIBLE/NIBBLE mode */
|
||||
ecr |= PPC_ECR_STD;
|
||||
|
||||
w_ecr(ppc, ecr);
|
||||
}
|
||||
|
||||
ppc->ppc_mode = mode;
|
||||
@ -1242,42 +1606,50 @@ ppc_generic_setmode(int unit, int mode)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* The ppc driver is free to choose options like FIFO or DMA
|
||||
* if ECP mode is available.
|
||||
*
|
||||
* The 'RAW' option allows the upper drivers to force the ppc mode
|
||||
* even with FIFO, DMA available.
|
||||
*/
|
||||
int
|
||||
ppc_smclike_setmode(int unit, int mode)
|
||||
{
|
||||
struct ppc_data *ppc = ppcdata[unit];
|
||||
|
||||
/* back to compatible mode, XXX don't know yet what to do here */
|
||||
if (mode == 0) {
|
||||
ppc->ppc_mode = PPB_COMPATIBLE;
|
||||
return (0);
|
||||
}
|
||||
u_char ecr = 0;
|
||||
|
||||
/* check if mode is available */
|
||||
if (!(ppc->ppc_avm & mode))
|
||||
return (EOPNOTSUPP);
|
||||
if (mode && !(ppc->ppc_avm & mode))
|
||||
return (EINVAL);
|
||||
|
||||
/* if ECP mode, configure ecr register */
|
||||
if (ppc->ppc_avm & PPB_ECP) {
|
||||
/* return to byte mode (keeping direction bit),
|
||||
* no interrupt, no DMA to be able to change to
|
||||
* ECP or EPP mode
|
||||
*/
|
||||
w_ecr(ppc, PPC_ECR_RESET);
|
||||
ecr = PPC_DISABLE_INTR;
|
||||
|
||||
/* XXX disable DMA, enable interrupts */
|
||||
if (mode & PPB_EPP)
|
||||
/* select EPP mode */
|
||||
w_ecr(ppc, 0x80);
|
||||
else if (mode & PPB_PS2)
|
||||
/* select PS2 mode with ECP */
|
||||
w_ecr(ppc, 0x20);
|
||||
ecr |= PPC_ECR_EPP;
|
||||
else if (mode & PPB_ECP)
|
||||
/* select ECP mode */
|
||||
w_ecr(ppc, 0x60);
|
||||
ecr |= PPC_ECR_ECP;
|
||||
else if (mode & PPB_PS2)
|
||||
/* select PS2 mode with ECP */
|
||||
ecr |= PPC_ECR_PS2;
|
||||
else
|
||||
/* select standard parallel port mode */
|
||||
w_ecr(ppc, 0x00);
|
||||
/* select COMPATIBLE/NIBBLE mode */
|
||||
ecr |= PPC_ECR_STD;
|
||||
|
||||
w_ecr(ppc, ecr);
|
||||
}
|
||||
|
||||
ppc->ppc_mode = mode;
|
||||
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -1314,8 +1686,9 @@ ppcprobe(struct isa_device *dvp)
|
||||
if((next_bios_ppc < BIOS_MAX_PPC) &&
|
||||
(*(BIOS_PORTS+next_bios_ppc) != 0) ) {
|
||||
dvp->id_iobase = *(BIOS_PORTS+next_bios_ppc++);
|
||||
printf("ppc: parallel port found at 0x%x\n",
|
||||
dvp->id_iobase);
|
||||
if (bootverbose)
|
||||
printf("ppc: parallel port found at 0x%x\n",
|
||||
dvp->id_iobase);
|
||||
} else
|
||||
return (0);
|
||||
}
|
||||
@ -1351,6 +1724,8 @@ ppcprobe(struct isa_device *dvp)
|
||||
if (!(dvp->id_flags & 0x20))
|
||||
ppc->ppc_irq = ffs(dvp->id_irq) - 1;
|
||||
|
||||
ppc->ppc_dmachan = dvp->id_drq;
|
||||
|
||||
ppcdata[ppc->ppc_unit] = ppc;
|
||||
nppc ++;
|
||||
|
||||
@ -1384,6 +1759,11 @@ ppcattach(struct isa_device *isdp)
|
||||
ppc_modes[ppc->ppc_mode], (PPB_IS_EPP(ppc->ppc_mode)) ?
|
||||
ppc_epp_protocol[ppc->ppc_epp] : "");
|
||||
|
||||
if (ppc->ppc_fifo)
|
||||
printf("ppc%d: FIFO with %d/%d/%d bytes threshold\n",
|
||||
ppc->ppc_unit, ppc->ppc_fifo, ppc->ppc_wthr,
|
||||
ppc->ppc_rthr);
|
||||
|
||||
isdp->id_ointr = ppcintr;
|
||||
|
||||
/*
|
||||
@ -1397,6 +1777,13 @@ ppcattach(struct isa_device *isdp)
|
||||
ppc->ppc_link.ppbus = ppbus;
|
||||
ppbus->ppb_link = &ppc->ppc_link;
|
||||
|
||||
if ((ppc->ppc_avm & PPB_ECP) && (ppc->ppc_dmachan > 0)) {
|
||||
|
||||
/* acquire the DMA channel forever */
|
||||
isa_dma_acquire(ppc->ppc_dmachan);
|
||||
isa_dmainit(ppc->ppc_dmachan, 1024); /* nlpt.BUFSIZE */
|
||||
}
|
||||
|
||||
/*
|
||||
* Probe the ppbus and attach devices found.
|
||||
*/
|
||||
|
@ -23,7 +23,7 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: ppcreg.h,v 1.4 1998/09/13 18:26:44 nsouch Exp $
|
||||
* $Id: ppcreg.h,v 1.5 1998/10/31 11:37:09 nsouch Exp $
|
||||
*
|
||||
*/
|
||||
#ifndef __PPCREG_H
|
||||
@ -55,6 +55,34 @@ struct ppc_data {
|
||||
int ppc_mode; /* chipset current mode */
|
||||
int ppc_avm; /* chipset available modes */
|
||||
|
||||
#define PPC_IRQ_NONE 0x0
|
||||
#define PPC_IRQ_nACK 0x1
|
||||
#define PPC_IRQ_DMA 0x2
|
||||
#define PPC_IRQ_FIFO 0x4
|
||||
#define PPC_IRQ_nFAULT 0x8
|
||||
int ppc_irqstat; /* remind irq settings */
|
||||
|
||||
#define PPC_DMA_INIT 0x01
|
||||
#define PPC_DMA_STARTED 0x02
|
||||
#define PPC_DMA_COMPLETE 0x03
|
||||
#define PPC_DMA_INTERRUPTED 0x04
|
||||
#define PPC_DMA_ERROR 0x05
|
||||
int ppc_dmastat; /* dma state */
|
||||
int ppc_dmachan; /* dma channel */
|
||||
int ppc_dmaflags; /* dma transfer flags */
|
||||
caddr_t ppc_dmaddr; /* buffer address */
|
||||
u_int ppc_dmacnt; /* count of bytes sent with dma */
|
||||
|
||||
#define PPC_PWORD_MASK 0x30
|
||||
#define PPC_PWORD_16 0x00
|
||||
#define PPC_PWORD_8 0x10
|
||||
#define PPC_PWORD_32 0x20
|
||||
char ppc_pword; /* PWord size */
|
||||
short ppc_fifo; /* FIFO threshold */
|
||||
|
||||
short ppc_wthr; /* writeIntrThresold */
|
||||
short ppc_rthr; /* readIntrThresold */
|
||||
|
||||
#define ppc_base ppc_link.base
|
||||
#define ppc_epp ppc_link.epp_protocol
|
||||
#define ppc_irq ppc_link.id_irq
|
||||
@ -71,25 +99,44 @@ struct ppc_data {
|
||||
* Parallel Port Chipset registers.
|
||||
*/
|
||||
#define PPC_SPP_DTR 0 /* SPP data register */
|
||||
#define PPC_ECP_A_FIFO 0 /* ECP Address fifo register */
|
||||
#define PPC_SPP_STR 1 /* SPP status register */
|
||||
#define PPC_SPP_CTR 2 /* SPP control register */
|
||||
#define PPC_EPP_DATA 4 /* EPP data register (8, 16 or 32 bit) */
|
||||
#define PPC_ECP_FIFO 0x400 /* ECP fifo register */
|
||||
#define PPC_ECP_D_FIFO 0x400 /* ECP Data fifo register */
|
||||
#define PPC_ECP_CNFGA 0x400 /* Configuration register A */
|
||||
#define PPC_ECP_CNFGB 0x401 /* Configuration register B */
|
||||
#define PPC_ECP_ECR 0x402 /* ECP extended control register */
|
||||
|
||||
#define PPC_FIFO_EMPTY 0x1 /* ecr register - bit 0 */
|
||||
#define PPC_FIFO_FULL 0x2 /* ecr register - bit 1 */
|
||||
#define PPC_SERVICE_INTR 0x4 /* ecr register - bit 2 */
|
||||
#define PPC_ENABLE_DMA 0x8 /* ecr register - bit 3 */
|
||||
#define PPC_nFAULT_INTR 0x10 /* ecr register - bit 4 */
|
||||
#define PPC_ECR_STD 0x0
|
||||
#define PPC_ECR_PS2 0x20
|
||||
#define PPC_ECR_FIFO 0x40
|
||||
#define PPC_ECR_ECP 0x60
|
||||
#define PPC_ECR_EPP 0x80
|
||||
|
||||
#define PPC_DISABLE_INTR (PPC_SERVICE_INTR | PPC_nFAULT_INTR)
|
||||
#define PPC_ECR_RESET (PPC_ECR_PS2 | PPC_DISABLE_INTR)
|
||||
|
||||
#define r_dtr(ppc) ((char)inb((ppc)->ppc_base + PPC_SPP_DTR))
|
||||
#define r_str(ppc) ((char)inb((ppc)->ppc_base + PPC_SPP_STR))
|
||||
#define r_ctr(ppc) ((char)inb((ppc)->ppc_base + PPC_SPP_CTR))
|
||||
#define r_epp(ppc) ((char)inb((ppc)->ppc_base + PPC_EPP_DATA))
|
||||
#define r_cnfgA(ppc) ((char)inb((ppc)->ppc_base + PPC_ECP_CNFGA))
|
||||
#define r_cnfgB(ppc) ((char)inb((ppc)->ppc_base + PPC_ECP_CNFGB))
|
||||
#define r_ecr(ppc) ((char)inb((ppc)->ppc_base + PPC_ECP_ECR))
|
||||
#define r_fifo(ppc) ((char)inb((ppc)->ppc_base + PPC_ECP_FIFO))
|
||||
#define r_fifo(ppc) ((char)inb((ppc)->ppc_base + PPC_ECP_D_FIFO))
|
||||
|
||||
#define w_dtr(ppc,byte) outb((ppc)->ppc_base + PPC_SPP_DTR, byte)
|
||||
#define w_str(ppc,byte) outb((ppc)->ppc_base + PPC_SPP_STR, byte)
|
||||
#define w_ctr(ppc,byte) outb((ppc)->ppc_base + PPC_SPP_CTR, byte)
|
||||
#define w_epp(ppc,byte) outb((ppc)->ppc_base + PPC_EPP_DATA, byte)
|
||||
#define w_ecr(ppc,byte) outb((ppc)->ppc_base + PPC_ECP_ECR, byte)
|
||||
#define w_fifo(ppc,byte) outb((ppc)->ppc_base + PPC_ECP_FIFO, byte)
|
||||
#define w_fifo(ppc,byte) outb((ppc)->ppc_base + PPC_ECP_D_FIFO, byte)
|
||||
|
||||
/*
|
||||
* Register defines for the PC873xx parts
|
||||
|
@ -23,7 +23,7 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: ppc.c,v 1.12 1998/12/07 21:58:22 archie Exp $
|
||||
* $Id: ppc.c,v 1.13 1998/12/30 00:37:42 hoek Exp $
|
||||
*
|
||||
*/
|
||||
#include "ppc.h"
|
||||
@ -49,6 +49,11 @@
|
||||
|
||||
#include <i386/isa/ppcreg.h>
|
||||
|
||||
#include "opt_ppc.h"
|
||||
|
||||
#define LOG_PPC(function, ppc, string) \
|
||||
if (bootverbose) printf("%s: %s\n", function, string)
|
||||
|
||||
static int ppcprobe(struct isa_device *);
|
||||
static int ppcattach(struct isa_device *);
|
||||
|
||||
@ -130,6 +135,9 @@ static int ppc_exec_microseq(int, struct ppb_microseq **);
|
||||
static int ppc_generic_setmode(int, int);
|
||||
static int ppc_smclike_setmode(int, int);
|
||||
|
||||
static int ppc_read(int, char *, int, int);
|
||||
static int ppc_write(int, char *, int, int);
|
||||
|
||||
static struct ppb_adapter ppc_smclike_adapter = {
|
||||
|
||||
0, /* no intr handler, filled by chipset dependent code */
|
||||
@ -138,7 +146,7 @@ static struct ppb_adapter ppc_smclike_adapter = {
|
||||
|
||||
ppc_exec_microseq,
|
||||
|
||||
ppc_smclike_setmode,
|
||||
ppc_smclike_setmode, ppc_read, ppc_write,
|
||||
|
||||
ppc_outsb_epp, ppc_outsw_epp, ppc_outsl_epp,
|
||||
ppc_insb_epp, ppc_insw_epp, ppc_insl_epp,
|
||||
@ -155,7 +163,7 @@ static struct ppb_adapter ppc_generic_adapter = {
|
||||
|
||||
ppc_exec_microseq,
|
||||
|
||||
ppc_generic_setmode,
|
||||
ppc_generic_setmode, ppc_read, ppc_write,
|
||||
|
||||
ppc_outsb_epp, ppc_outsw_epp, ppc_outsl_epp,
|
||||
ppc_insb_epp, ppc_insw_epp, ppc_insl_epp,
|
||||
@ -173,8 +181,11 @@ ppc_ecp_sync(int unit) {
|
||||
struct ppc_data *ppc = ppcdata[unit];
|
||||
int i, r;
|
||||
|
||||
if (!(ppc->ppc_avm & PPB_ECP))
|
||||
return;
|
||||
|
||||
r = r_ecr(ppc);
|
||||
if ((r & 0xe0) != 0x80)
|
||||
if ((r & 0xe0) != PPC_ECR_EPP)
|
||||
return;
|
||||
|
||||
for (i = 0; i < 100; i++) {
|
||||
@ -190,13 +201,115 @@ ppc_ecp_sync(int unit) {
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
ppcintr(int unit)
|
||||
/*
|
||||
* ppc_detect_fifo()
|
||||
*
|
||||
* Detect parallel port FIFO
|
||||
*/
|
||||
static int
|
||||
ppc_detect_fifo(struct ppc_data *ppc)
|
||||
{
|
||||
/* call directly upper code */
|
||||
ppb_intr(&ppcdata[unit]->ppc_link);
|
||||
char ecr_sav;
|
||||
char ctr_sav, ctr, cc;
|
||||
short i;
|
||||
|
||||
/* save registers */
|
||||
ecr_sav = r_ecr(ppc);
|
||||
ctr_sav = r_ctr(ppc);
|
||||
|
||||
return;
|
||||
/* enter ECP configuration mode, no interrupt, no DMA */
|
||||
w_ecr(ppc, 0xf4);
|
||||
|
||||
/* read PWord size - transfers in FIFO mode must be PWord aligned */
|
||||
ppc->ppc_pword = (r_cnfgA(ppc) & PPC_PWORD_MASK);
|
||||
|
||||
/* XXX 16 and 32 bits implementations not supported */
|
||||
if (ppc->ppc_pword != PPC_PWORD_8) {
|
||||
LOG_PPC(__FUNCTION__, ppc, "PWord not supported");
|
||||
goto error;
|
||||
}
|
||||
|
||||
w_ecr(ppc, 0x34); /* byte mode, no interrupt, no DMA */
|
||||
ctr = r_ctr(ppc);
|
||||
w_ctr(ppc, ctr | PCD); /* set direction to 1 */
|
||||
|
||||
/* enter ECP test mode, no interrupt, no DMA */
|
||||
w_ecr(ppc, 0xd4);
|
||||
|
||||
/* flush the FIFO */
|
||||
for (i=0; i<1024; i++) {
|
||||
if (r_ecr(ppc) & PPC_FIFO_EMPTY)
|
||||
break;
|
||||
cc = r_fifo(ppc);
|
||||
}
|
||||
|
||||
if (i >= 1024) {
|
||||
LOG_PPC(__FUNCTION__, ppc, "can't flush FIFO");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* enable interrupts, no DMA */
|
||||
w_ecr(ppc, 0xd0);
|
||||
|
||||
/* determine readIntrThreshold
|
||||
* fill the FIFO until serviceIntr is set
|
||||
*/
|
||||
for (i=0; i<1024; i++) {
|
||||
w_fifo(ppc, (char)i);
|
||||
if (!ppc->ppc_rthr && (r_ecr(ppc) & PPC_SERVICE_INTR)) {
|
||||
/* readThreshold reached */
|
||||
ppc->ppc_rthr = i+1;
|
||||
}
|
||||
if (r_ecr(ppc) & PPC_FIFO_FULL) {
|
||||
ppc->ppc_fifo = i+1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i >= 1024) {
|
||||
LOG_PPC(__FUNCTION__, ppc, "can't fill FIFO");
|
||||
goto error;
|
||||
}
|
||||
|
||||
w_ecr(ppc, 0xd4); /* test mode, no interrupt, no DMA */
|
||||
w_ctr(ppc, ctr & ~PCD); /* set direction to 0 */
|
||||
w_ecr(ppc, 0xd0); /* enable interrupts */
|
||||
|
||||
/* determine writeIntrThreshold
|
||||
* empty the FIFO until serviceIntr is set
|
||||
*/
|
||||
for (i=ppc->ppc_fifo; i>0; i--) {
|
||||
if (r_fifo(ppc) != (char)(ppc->ppc_fifo-i)) {
|
||||
LOG_PPC(__FUNCTION__, ppc, "invalid data in FIFO");
|
||||
goto error;
|
||||
}
|
||||
if (r_ecr(ppc) & PPC_SERVICE_INTR) {
|
||||
/* writeIntrThreshold reached */
|
||||
ppc->ppc_wthr = ppc->ppc_fifo - i+1;
|
||||
}
|
||||
/* if FIFO empty before the last byte, error */
|
||||
if (i>1 && (r_ecr(ppc) & PPC_FIFO_EMPTY)) {
|
||||
LOG_PPC(__FUNCTION__, ppc, "data lost in FIFO");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
/* FIFO must be empty after the last byte */
|
||||
if (!(r_ecr(ppc) & PPC_FIFO_EMPTY)) {
|
||||
LOG_PPC(__FUNCTION__, ppc, "can't empty the FIFO");
|
||||
goto error;
|
||||
}
|
||||
|
||||
w_ctr(ppc, ctr_sav);
|
||||
w_ecr(ppc, ecr_sav);
|
||||
|
||||
return (0);
|
||||
|
||||
error:
|
||||
w_ctr(ppc, ctr_sav);
|
||||
w_ecr(ppc, ecr_sav);
|
||||
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -654,6 +767,13 @@ ppc_smc37c66xgt_detect(struct ppc_data *ppc, int chipset_mode)
|
||||
ppc->ppc_avm = chipset_mode;
|
||||
}
|
||||
|
||||
/* set FIFO threshold to 16 */
|
||||
if (ppc->ppc_avm & PPB_ECP) {
|
||||
/* select CRA */
|
||||
outb(csr, 0xa);
|
||||
outb(cio, 16);
|
||||
}
|
||||
|
||||
end_detect:
|
||||
|
||||
if (bootverbose)
|
||||
@ -884,14 +1004,14 @@ ppc_generic_detect(struct ppc_data *ppc, int chipset_mode)
|
||||
|
||||
if (!chipset_mode) {
|
||||
/* first, check for ECP */
|
||||
w_ecr(ppc, 0x20);
|
||||
if ((r_ecr(ppc) & 0xe0) == 0x20) {
|
||||
w_ecr(ppc, PPC_ECR_PS2);
|
||||
if ((r_ecr(ppc) & 0xe0) == PPC_ECR_PS2) {
|
||||
ppc->ppc_avm |= PPB_ECP | PPB_SPP;
|
||||
if (bootverbose)
|
||||
printf(" ECP SPP");
|
||||
|
||||
/* search for SMC style ECP+EPP mode */
|
||||
w_ecr(ppc, 0x80);
|
||||
w_ecr(ppc, PPC_ECR_EPP);
|
||||
}
|
||||
|
||||
/* try to reset EPP timeout bit */
|
||||
@ -911,7 +1031,7 @@ ppc_generic_detect(struct ppc_data *ppc, int chipset_mode)
|
||||
}
|
||||
} else {
|
||||
/* restore to standard mode */
|
||||
w_ecr(ppc, 0x0);
|
||||
w_ecr(ppc, PPC_ECR_STD);
|
||||
}
|
||||
|
||||
/* XXX try to detect NIBBLE and PS2 modes */
|
||||
@ -978,6 +1098,10 @@ ppc_detect(struct ppc_data *ppc, int chipset_mode) {
|
||||
}
|
||||
}
|
||||
|
||||
/* configure/detect ECP FIFO */
|
||||
if ((ppc->ppc_avm & PPB_ECP) && !(ppc->ppc_flags & 0x80))
|
||||
ppc_detect_fifo(ppc);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -1202,6 +1326,244 @@ ppc_exec_microseq(int unit, struct ppb_microseq **p_msq)
|
||||
/* unreached */
|
||||
}
|
||||
|
||||
static void
|
||||
ppcintr(int unit)
|
||||
{
|
||||
struct ppc_data *ppc = ppcdata[unit];
|
||||
char ctr, ecr;
|
||||
|
||||
ctr = r_ctr(ppc);
|
||||
ecr = r_ecr(ppc);
|
||||
|
||||
#ifdef PPC_DEBUG
|
||||
printf("!");
|
||||
#endif
|
||||
|
||||
/* don't use ecp mode with IRQENABLE set */
|
||||
if (ctr & IRQENABLE) {
|
||||
/* call upper code */
|
||||
ppb_intr(&ppc->ppc_link);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctr & nFAULT) {
|
||||
if (ppc->ppc_irqstat & PPC_IRQ_nFAULT) {
|
||||
|
||||
w_ecr(ppc, ecr | PPC_nFAULT_INTR);
|
||||
ppc->ppc_irqstat &= ~PPC_IRQ_nFAULT;
|
||||
} else {
|
||||
/* call upper code */
|
||||
ppb_intr(&ppc->ppc_link);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (ppc->ppc_irqstat & PPC_IRQ_DMA) {
|
||||
/* disable interrupts (should be done by hardware though) */
|
||||
w_ecr(ppc, ecr | PPC_SERVICE_INTR);
|
||||
ppc->ppc_irqstat &= ~PPC_IRQ_DMA;
|
||||
ecr = r_ecr(ppc);
|
||||
|
||||
/* check if DMA completed */
|
||||
if ((ppc->ppc_avm & PPB_ECP) && (ecr & PPC_ENABLE_DMA)) {
|
||||
#ifdef PPC_DEBUG
|
||||
printf("a");
|
||||
#endif
|
||||
/* stop DMA */
|
||||
w_ecr(ppc, ecr & ~PPC_ENABLE_DMA);
|
||||
ecr = r_ecr(ppc);
|
||||
|
||||
if (ppc->ppc_dmastat == PPC_DMA_STARTED) {
|
||||
#ifdef PPC_DEBUG
|
||||
printf("d");
|
||||
#endif
|
||||
isa_dmadone(
|
||||
ppc->ppc_dmaflags,
|
||||
ppc->ppc_dmaddr,
|
||||
ppc->ppc_dmacnt,
|
||||
ppc->ppc_dmachan);
|
||||
|
||||
ppc->ppc_dmastat = PPC_DMA_COMPLETE;
|
||||
|
||||
/* wakeup the waiting process */
|
||||
wakeup((caddr_t)ppc);
|
||||
}
|
||||
}
|
||||
} else if (ppc->ppc_irqstat & PPC_IRQ_FIFO) {
|
||||
|
||||
/* classic interrupt I/O */
|
||||
ppc->ppc_irqstat &= ~PPC_IRQ_FIFO;
|
||||
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int
|
||||
ppc_read(int unit, char *buf, int len, int mode)
|
||||
{
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Call this function if you want to send data in any advanced mode
|
||||
* of your parallel port: FIFO, DMA
|
||||
*
|
||||
* If what you want is not possible (no ECP, no DMA...),
|
||||
* EINVAL is returned
|
||||
*/
|
||||
static int
|
||||
ppc_write(int unit, char *buf, int len, int how)
|
||||
{
|
||||
struct ppc_data *ppc = ppcdata[unit];
|
||||
char ecr, ecr_sav, ctr, ctr_sav;
|
||||
int s, error = 0;
|
||||
int spin;
|
||||
|
||||
#ifdef PPC_DEBUG
|
||||
printf("w");
|
||||
#endif
|
||||
|
||||
ecr_sav = r_ecr(ppc);
|
||||
ctr_sav = r_ctr(ppc);
|
||||
|
||||
/*
|
||||
* Send buffer with DMA, FIFO and interrupts
|
||||
*/
|
||||
if (ppc->ppc_avm & PPB_ECP) {
|
||||
|
||||
if (ppc->ppc_dmachan >= 0) {
|
||||
|
||||
/* byte mode, no intr, no DMA, dir=0, flush fifo
|
||||
*/
|
||||
ecr = PPC_ECR_STD | PPC_DISABLE_INTR;
|
||||
w_ecr(ppc, ecr);
|
||||
|
||||
/* disable nAck interrupts */
|
||||
ctr = r_ctr(ppc);
|
||||
ctr &= ~IRQENABLE;
|
||||
w_ctr(ppc, ctr);
|
||||
|
||||
ppc->ppc_dmaflags = 0;
|
||||
ppc->ppc_dmaddr = (caddr_t)buf;
|
||||
ppc->ppc_dmacnt = (u_int)len;
|
||||
|
||||
switch (ppc->ppc_mode) {
|
||||
case PPB_COMPATIBLE:
|
||||
/* compatible mode with FIFO, no intr, DMA, dir=0 */
|
||||
ecr = PPC_ECR_FIFO | PPC_DISABLE_INTR | PPC_ENABLE_DMA;
|
||||
break;
|
||||
case PPB_ECP:
|
||||
ecr = PPC_ECR_ECP | PPC_DISABLE_INTR | PPC_ENABLE_DMA;
|
||||
break;
|
||||
default:
|
||||
error = EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
w_ecr(ppc, ecr);
|
||||
ecr = r_ecr(ppc);
|
||||
|
||||
/* enter splhigh() not to be preempted
|
||||
* by the dma interrupt, we may miss
|
||||
* the wakeup otherwise
|
||||
*/
|
||||
s = splhigh();
|
||||
|
||||
ppc->ppc_dmastat = PPC_DMA_INIT;
|
||||
|
||||
/* enable interrupts */
|
||||
ecr &= ~PPC_SERVICE_INTR;
|
||||
ppc->ppc_irqstat = PPC_IRQ_DMA;
|
||||
w_ecr(ppc, ecr);
|
||||
|
||||
isa_dmastart(
|
||||
ppc->ppc_dmaflags,
|
||||
ppc->ppc_dmaddr,
|
||||
ppc->ppc_dmacnt,
|
||||
ppc->ppc_dmachan);
|
||||
#ifdef PPC_DEBUG
|
||||
printf("s%d", ppc->ppc_dmacnt);
|
||||
#endif
|
||||
ppc->ppc_dmastat = PPC_DMA_STARTED;
|
||||
|
||||
/* Wait for the DMA completed interrupt. We hope we won't
|
||||
* miss it, otherwise a signal will be necessary to unlock the
|
||||
* process.
|
||||
*/
|
||||
do {
|
||||
/* release CPU */
|
||||
error = tsleep((caddr_t)ppc,
|
||||
PPBPRI | PCATCH, "ppcdma", 0);
|
||||
|
||||
} while (error == EWOULDBLOCK);
|
||||
|
||||
splx(s);
|
||||
|
||||
if (error) {
|
||||
#ifdef PPC_DEBUG
|
||||
printf("i");
|
||||
#endif
|
||||
/* stop DMA */
|
||||
isa_dmadone(
|
||||
ppc->ppc_dmaflags, ppc->ppc_dmaddr,
|
||||
ppc->ppc_dmacnt, ppc->ppc_dmachan);
|
||||
|
||||
/* no dma, no interrupt, flush the fifo */
|
||||
w_ecr(ppc, PPC_ECR_RESET);
|
||||
|
||||
ppc->ppc_dmastat = PPC_DMA_INTERRUPTED;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* wait for an empty fifo */
|
||||
while (!(r_ecr(ppc) & PPC_FIFO_EMPTY)) {
|
||||
|
||||
for (spin=100; spin; spin--)
|
||||
if (r_ecr(ppc) & PPC_FIFO_EMPTY)
|
||||
goto fifo_empty;
|
||||
#ifdef PPC_DEBUG
|
||||
printf("Z");
|
||||
#endif
|
||||
error = tsleep((caddr_t)ppc, PPBPRI | PCATCH, "ppcfifo", hz/100);
|
||||
if (error != EWOULDBLOCK) {
|
||||
#ifdef PPC_DEBUG
|
||||
printf("I");
|
||||
#endif
|
||||
/* no dma, no interrupt, flush the fifo */
|
||||
w_ecr(ppc, PPC_ECR_RESET);
|
||||
|
||||
ppc->ppc_dmastat = PPC_DMA_INTERRUPTED;
|
||||
error = EINTR;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
fifo_empty:
|
||||
/* no dma, no interrupt, flush the fifo */
|
||||
w_ecr(ppc, PPC_ECR_RESET);
|
||||
|
||||
} else
|
||||
error = EINVAL; /* XXX we should FIFO and
|
||||
* interrupts */
|
||||
} else
|
||||
error = EINVAL;
|
||||
|
||||
error:
|
||||
|
||||
/* PDRQ must be kept unasserted until nPDACK is
|
||||
* deasserted for a minimum of 350ns (SMC datasheet)
|
||||
*
|
||||
* Consequence may be a FIFO that never empty
|
||||
*/
|
||||
DELAY(1);
|
||||
|
||||
w_ecr(ppc, ecr_sav);
|
||||
w_ctr(ppc, ctr_sav);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Configure current operating mode
|
||||
*/
|
||||
@ -1209,32 +1571,34 @@ static int
|
||||
ppc_generic_setmode(int unit, int mode)
|
||||
{
|
||||
struct ppc_data *ppc = ppcdata[unit];
|
||||
|
||||
/* back to compatible mode, XXX don't know yet what to do here */
|
||||
if (mode == 0) {
|
||||
ppc->ppc_mode = PPB_COMPATIBLE;
|
||||
return (0);
|
||||
}
|
||||
u_char ecr = 0;
|
||||
|
||||
/* check if mode is available */
|
||||
if (!(ppc->ppc_avm & mode))
|
||||
return (EOPNOTSUPP);
|
||||
if (mode && !(ppc->ppc_avm & mode))
|
||||
return (EINVAL);
|
||||
|
||||
/* if ECP mode, configure ecr register */
|
||||
if (ppc->ppc_avm & PPB_ECP) {
|
||||
/* return to byte mode (keeping direction bit),
|
||||
* no interrupt, no DMA to be able to change to
|
||||
* ECP
|
||||
*/
|
||||
w_ecr(ppc, PPC_ECR_RESET);
|
||||
ecr = PPC_DISABLE_INTR;
|
||||
|
||||
/* XXX disable DMA, enable interrupts */
|
||||
if (mode & PPB_EPP)
|
||||
return (EOPNOTSUPP);
|
||||
else if (mode & PPB_PS2)
|
||||
/* select PS2 mode with ECP */
|
||||
w_ecr(ppc, 0x20);
|
||||
return (EINVAL);
|
||||
else if (mode & PPB_ECP)
|
||||
/* select ECP mode */
|
||||
w_ecr(ppc, 0x60);
|
||||
ecr |= PPC_ECR_ECP;
|
||||
else if (mode & PPB_PS2)
|
||||
/* select PS2 mode with ECP */
|
||||
ecr |= PPC_ECR_PS2;
|
||||
else
|
||||
/* select standard parallel port mode */
|
||||
w_ecr(ppc, 0x00);
|
||||
/* select COMPATIBLE/NIBBLE mode */
|
||||
ecr |= PPC_ECR_STD;
|
||||
|
||||
w_ecr(ppc, ecr);
|
||||
}
|
||||
|
||||
ppc->ppc_mode = mode;
|
||||
@ -1242,42 +1606,50 @@ ppc_generic_setmode(int unit, int mode)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* The ppc driver is free to choose options like FIFO or DMA
|
||||
* if ECP mode is available.
|
||||
*
|
||||
* The 'RAW' option allows the upper drivers to force the ppc mode
|
||||
* even with FIFO, DMA available.
|
||||
*/
|
||||
int
|
||||
ppc_smclike_setmode(int unit, int mode)
|
||||
{
|
||||
struct ppc_data *ppc = ppcdata[unit];
|
||||
|
||||
/* back to compatible mode, XXX don't know yet what to do here */
|
||||
if (mode == 0) {
|
||||
ppc->ppc_mode = PPB_COMPATIBLE;
|
||||
return (0);
|
||||
}
|
||||
u_char ecr = 0;
|
||||
|
||||
/* check if mode is available */
|
||||
if (!(ppc->ppc_avm & mode))
|
||||
return (EOPNOTSUPP);
|
||||
if (mode && !(ppc->ppc_avm & mode))
|
||||
return (EINVAL);
|
||||
|
||||
/* if ECP mode, configure ecr register */
|
||||
if (ppc->ppc_avm & PPB_ECP) {
|
||||
/* return to byte mode (keeping direction bit),
|
||||
* no interrupt, no DMA to be able to change to
|
||||
* ECP or EPP mode
|
||||
*/
|
||||
w_ecr(ppc, PPC_ECR_RESET);
|
||||
ecr = PPC_DISABLE_INTR;
|
||||
|
||||
/* XXX disable DMA, enable interrupts */
|
||||
if (mode & PPB_EPP)
|
||||
/* select EPP mode */
|
||||
w_ecr(ppc, 0x80);
|
||||
else if (mode & PPB_PS2)
|
||||
/* select PS2 mode with ECP */
|
||||
w_ecr(ppc, 0x20);
|
||||
ecr |= PPC_ECR_EPP;
|
||||
else if (mode & PPB_ECP)
|
||||
/* select ECP mode */
|
||||
w_ecr(ppc, 0x60);
|
||||
ecr |= PPC_ECR_ECP;
|
||||
else if (mode & PPB_PS2)
|
||||
/* select PS2 mode with ECP */
|
||||
ecr |= PPC_ECR_PS2;
|
||||
else
|
||||
/* select standard parallel port mode */
|
||||
w_ecr(ppc, 0x00);
|
||||
/* select COMPATIBLE/NIBBLE mode */
|
||||
ecr |= PPC_ECR_STD;
|
||||
|
||||
w_ecr(ppc, ecr);
|
||||
}
|
||||
|
||||
ppc->ppc_mode = mode;
|
||||
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -1314,8 +1686,9 @@ ppcprobe(struct isa_device *dvp)
|
||||
if((next_bios_ppc < BIOS_MAX_PPC) &&
|
||||
(*(BIOS_PORTS+next_bios_ppc) != 0) ) {
|
||||
dvp->id_iobase = *(BIOS_PORTS+next_bios_ppc++);
|
||||
printf("ppc: parallel port found at 0x%x\n",
|
||||
dvp->id_iobase);
|
||||
if (bootverbose)
|
||||
printf("ppc: parallel port found at 0x%x\n",
|
||||
dvp->id_iobase);
|
||||
} else
|
||||
return (0);
|
||||
}
|
||||
@ -1351,6 +1724,8 @@ ppcprobe(struct isa_device *dvp)
|
||||
if (!(dvp->id_flags & 0x20))
|
||||
ppc->ppc_irq = ffs(dvp->id_irq) - 1;
|
||||
|
||||
ppc->ppc_dmachan = dvp->id_drq;
|
||||
|
||||
ppcdata[ppc->ppc_unit] = ppc;
|
||||
nppc ++;
|
||||
|
||||
@ -1384,6 +1759,11 @@ ppcattach(struct isa_device *isdp)
|
||||
ppc_modes[ppc->ppc_mode], (PPB_IS_EPP(ppc->ppc_mode)) ?
|
||||
ppc_epp_protocol[ppc->ppc_epp] : "");
|
||||
|
||||
if (ppc->ppc_fifo)
|
||||
printf("ppc%d: FIFO with %d/%d/%d bytes threshold\n",
|
||||
ppc->ppc_unit, ppc->ppc_fifo, ppc->ppc_wthr,
|
||||
ppc->ppc_rthr);
|
||||
|
||||
isdp->id_ointr = ppcintr;
|
||||
|
||||
/*
|
||||
@ -1397,6 +1777,13 @@ ppcattach(struct isa_device *isdp)
|
||||
ppc->ppc_link.ppbus = ppbus;
|
||||
ppbus->ppb_link = &ppc->ppc_link;
|
||||
|
||||
if ((ppc->ppc_avm & PPB_ECP) && (ppc->ppc_dmachan > 0)) {
|
||||
|
||||
/* acquire the DMA channel forever */
|
||||
isa_dma_acquire(ppc->ppc_dmachan);
|
||||
isa_dmainit(ppc->ppc_dmachan, 1024); /* nlpt.BUFSIZE */
|
||||
}
|
||||
|
||||
/*
|
||||
* Probe the ppbus and attach devices found.
|
||||
*/
|
||||
|
@ -23,7 +23,7 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: ppcreg.h,v 1.4 1998/09/13 18:26:44 nsouch Exp $
|
||||
* $Id: ppcreg.h,v 1.5 1998/10/31 11:37:09 nsouch Exp $
|
||||
*
|
||||
*/
|
||||
#ifndef __PPCREG_H
|
||||
@ -55,6 +55,34 @@ struct ppc_data {
|
||||
int ppc_mode; /* chipset current mode */
|
||||
int ppc_avm; /* chipset available modes */
|
||||
|
||||
#define PPC_IRQ_NONE 0x0
|
||||
#define PPC_IRQ_nACK 0x1
|
||||
#define PPC_IRQ_DMA 0x2
|
||||
#define PPC_IRQ_FIFO 0x4
|
||||
#define PPC_IRQ_nFAULT 0x8
|
||||
int ppc_irqstat; /* remind irq settings */
|
||||
|
||||
#define PPC_DMA_INIT 0x01
|
||||
#define PPC_DMA_STARTED 0x02
|
||||
#define PPC_DMA_COMPLETE 0x03
|
||||
#define PPC_DMA_INTERRUPTED 0x04
|
||||
#define PPC_DMA_ERROR 0x05
|
||||
int ppc_dmastat; /* dma state */
|
||||
int ppc_dmachan; /* dma channel */
|
||||
int ppc_dmaflags; /* dma transfer flags */
|
||||
caddr_t ppc_dmaddr; /* buffer address */
|
||||
u_int ppc_dmacnt; /* count of bytes sent with dma */
|
||||
|
||||
#define PPC_PWORD_MASK 0x30
|
||||
#define PPC_PWORD_16 0x00
|
||||
#define PPC_PWORD_8 0x10
|
||||
#define PPC_PWORD_32 0x20
|
||||
char ppc_pword; /* PWord size */
|
||||
short ppc_fifo; /* FIFO threshold */
|
||||
|
||||
short ppc_wthr; /* writeIntrThresold */
|
||||
short ppc_rthr; /* readIntrThresold */
|
||||
|
||||
#define ppc_base ppc_link.base
|
||||
#define ppc_epp ppc_link.epp_protocol
|
||||
#define ppc_irq ppc_link.id_irq
|
||||
@ -71,25 +99,44 @@ struct ppc_data {
|
||||
* Parallel Port Chipset registers.
|
||||
*/
|
||||
#define PPC_SPP_DTR 0 /* SPP data register */
|
||||
#define PPC_ECP_A_FIFO 0 /* ECP Address fifo register */
|
||||
#define PPC_SPP_STR 1 /* SPP status register */
|
||||
#define PPC_SPP_CTR 2 /* SPP control register */
|
||||
#define PPC_EPP_DATA 4 /* EPP data register (8, 16 or 32 bit) */
|
||||
#define PPC_ECP_FIFO 0x400 /* ECP fifo register */
|
||||
#define PPC_ECP_D_FIFO 0x400 /* ECP Data fifo register */
|
||||
#define PPC_ECP_CNFGA 0x400 /* Configuration register A */
|
||||
#define PPC_ECP_CNFGB 0x401 /* Configuration register B */
|
||||
#define PPC_ECP_ECR 0x402 /* ECP extended control register */
|
||||
|
||||
#define PPC_FIFO_EMPTY 0x1 /* ecr register - bit 0 */
|
||||
#define PPC_FIFO_FULL 0x2 /* ecr register - bit 1 */
|
||||
#define PPC_SERVICE_INTR 0x4 /* ecr register - bit 2 */
|
||||
#define PPC_ENABLE_DMA 0x8 /* ecr register - bit 3 */
|
||||
#define PPC_nFAULT_INTR 0x10 /* ecr register - bit 4 */
|
||||
#define PPC_ECR_STD 0x0
|
||||
#define PPC_ECR_PS2 0x20
|
||||
#define PPC_ECR_FIFO 0x40
|
||||
#define PPC_ECR_ECP 0x60
|
||||
#define PPC_ECR_EPP 0x80
|
||||
|
||||
#define PPC_DISABLE_INTR (PPC_SERVICE_INTR | PPC_nFAULT_INTR)
|
||||
#define PPC_ECR_RESET (PPC_ECR_PS2 | PPC_DISABLE_INTR)
|
||||
|
||||
#define r_dtr(ppc) ((char)inb((ppc)->ppc_base + PPC_SPP_DTR))
|
||||
#define r_str(ppc) ((char)inb((ppc)->ppc_base + PPC_SPP_STR))
|
||||
#define r_ctr(ppc) ((char)inb((ppc)->ppc_base + PPC_SPP_CTR))
|
||||
#define r_epp(ppc) ((char)inb((ppc)->ppc_base + PPC_EPP_DATA))
|
||||
#define r_cnfgA(ppc) ((char)inb((ppc)->ppc_base + PPC_ECP_CNFGA))
|
||||
#define r_cnfgB(ppc) ((char)inb((ppc)->ppc_base + PPC_ECP_CNFGB))
|
||||
#define r_ecr(ppc) ((char)inb((ppc)->ppc_base + PPC_ECP_ECR))
|
||||
#define r_fifo(ppc) ((char)inb((ppc)->ppc_base + PPC_ECP_FIFO))
|
||||
#define r_fifo(ppc) ((char)inb((ppc)->ppc_base + PPC_ECP_D_FIFO))
|
||||
|
||||
#define w_dtr(ppc,byte) outb((ppc)->ppc_base + PPC_SPP_DTR, byte)
|
||||
#define w_str(ppc,byte) outb((ppc)->ppc_base + PPC_SPP_STR, byte)
|
||||
#define w_ctr(ppc,byte) outb((ppc)->ppc_base + PPC_SPP_CTR, byte)
|
||||
#define w_epp(ppc,byte) outb((ppc)->ppc_base + PPC_EPP_DATA, byte)
|
||||
#define w_ecr(ppc,byte) outb((ppc)->ppc_base + PPC_ECP_ECR, byte)
|
||||
#define w_fifo(ppc,byte) outb((ppc)->ppc_base + PPC_ECP_FIFO, byte)
|
||||
#define w_fifo(ppc,byte) outb((ppc)->ppc_base + PPC_ECP_D_FIFO, byte)
|
||||
|
||||
/*
|
||||
* Register defines for the PC873xx parts
|
||||
|
483
sys/isa/ppc.c
483
sys/isa/ppc.c
@ -23,7 +23,7 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: ppc.c,v 1.12 1998/12/07 21:58:22 archie Exp $
|
||||
* $Id: ppc.c,v 1.13 1998/12/30 00:37:42 hoek Exp $
|
||||
*
|
||||
*/
|
||||
#include "ppc.h"
|
||||
@ -49,6 +49,11 @@
|
||||
|
||||
#include <i386/isa/ppcreg.h>
|
||||
|
||||
#include "opt_ppc.h"
|
||||
|
||||
#define LOG_PPC(function, ppc, string) \
|
||||
if (bootverbose) printf("%s: %s\n", function, string)
|
||||
|
||||
static int ppcprobe(struct isa_device *);
|
||||
static int ppcattach(struct isa_device *);
|
||||
|
||||
@ -130,6 +135,9 @@ static int ppc_exec_microseq(int, struct ppb_microseq **);
|
||||
static int ppc_generic_setmode(int, int);
|
||||
static int ppc_smclike_setmode(int, int);
|
||||
|
||||
static int ppc_read(int, char *, int, int);
|
||||
static int ppc_write(int, char *, int, int);
|
||||
|
||||
static struct ppb_adapter ppc_smclike_adapter = {
|
||||
|
||||
0, /* no intr handler, filled by chipset dependent code */
|
||||
@ -138,7 +146,7 @@ static struct ppb_adapter ppc_smclike_adapter = {
|
||||
|
||||
ppc_exec_microseq,
|
||||
|
||||
ppc_smclike_setmode,
|
||||
ppc_smclike_setmode, ppc_read, ppc_write,
|
||||
|
||||
ppc_outsb_epp, ppc_outsw_epp, ppc_outsl_epp,
|
||||
ppc_insb_epp, ppc_insw_epp, ppc_insl_epp,
|
||||
@ -155,7 +163,7 @@ static struct ppb_adapter ppc_generic_adapter = {
|
||||
|
||||
ppc_exec_microseq,
|
||||
|
||||
ppc_generic_setmode,
|
||||
ppc_generic_setmode, ppc_read, ppc_write,
|
||||
|
||||
ppc_outsb_epp, ppc_outsw_epp, ppc_outsl_epp,
|
||||
ppc_insb_epp, ppc_insw_epp, ppc_insl_epp,
|
||||
@ -173,8 +181,11 @@ ppc_ecp_sync(int unit) {
|
||||
struct ppc_data *ppc = ppcdata[unit];
|
||||
int i, r;
|
||||
|
||||
if (!(ppc->ppc_avm & PPB_ECP))
|
||||
return;
|
||||
|
||||
r = r_ecr(ppc);
|
||||
if ((r & 0xe0) != 0x80)
|
||||
if ((r & 0xe0) != PPC_ECR_EPP)
|
||||
return;
|
||||
|
||||
for (i = 0; i < 100; i++) {
|
||||
@ -190,13 +201,115 @@ ppc_ecp_sync(int unit) {
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
ppcintr(int unit)
|
||||
/*
|
||||
* ppc_detect_fifo()
|
||||
*
|
||||
* Detect parallel port FIFO
|
||||
*/
|
||||
static int
|
||||
ppc_detect_fifo(struct ppc_data *ppc)
|
||||
{
|
||||
/* call directly upper code */
|
||||
ppb_intr(&ppcdata[unit]->ppc_link);
|
||||
char ecr_sav;
|
||||
char ctr_sav, ctr, cc;
|
||||
short i;
|
||||
|
||||
/* save registers */
|
||||
ecr_sav = r_ecr(ppc);
|
||||
ctr_sav = r_ctr(ppc);
|
||||
|
||||
return;
|
||||
/* enter ECP configuration mode, no interrupt, no DMA */
|
||||
w_ecr(ppc, 0xf4);
|
||||
|
||||
/* read PWord size - transfers in FIFO mode must be PWord aligned */
|
||||
ppc->ppc_pword = (r_cnfgA(ppc) & PPC_PWORD_MASK);
|
||||
|
||||
/* XXX 16 and 32 bits implementations not supported */
|
||||
if (ppc->ppc_pword != PPC_PWORD_8) {
|
||||
LOG_PPC(__FUNCTION__, ppc, "PWord not supported");
|
||||
goto error;
|
||||
}
|
||||
|
||||
w_ecr(ppc, 0x34); /* byte mode, no interrupt, no DMA */
|
||||
ctr = r_ctr(ppc);
|
||||
w_ctr(ppc, ctr | PCD); /* set direction to 1 */
|
||||
|
||||
/* enter ECP test mode, no interrupt, no DMA */
|
||||
w_ecr(ppc, 0xd4);
|
||||
|
||||
/* flush the FIFO */
|
||||
for (i=0; i<1024; i++) {
|
||||
if (r_ecr(ppc) & PPC_FIFO_EMPTY)
|
||||
break;
|
||||
cc = r_fifo(ppc);
|
||||
}
|
||||
|
||||
if (i >= 1024) {
|
||||
LOG_PPC(__FUNCTION__, ppc, "can't flush FIFO");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* enable interrupts, no DMA */
|
||||
w_ecr(ppc, 0xd0);
|
||||
|
||||
/* determine readIntrThreshold
|
||||
* fill the FIFO until serviceIntr is set
|
||||
*/
|
||||
for (i=0; i<1024; i++) {
|
||||
w_fifo(ppc, (char)i);
|
||||
if (!ppc->ppc_rthr && (r_ecr(ppc) & PPC_SERVICE_INTR)) {
|
||||
/* readThreshold reached */
|
||||
ppc->ppc_rthr = i+1;
|
||||
}
|
||||
if (r_ecr(ppc) & PPC_FIFO_FULL) {
|
||||
ppc->ppc_fifo = i+1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i >= 1024) {
|
||||
LOG_PPC(__FUNCTION__, ppc, "can't fill FIFO");
|
||||
goto error;
|
||||
}
|
||||
|
||||
w_ecr(ppc, 0xd4); /* test mode, no interrupt, no DMA */
|
||||
w_ctr(ppc, ctr & ~PCD); /* set direction to 0 */
|
||||
w_ecr(ppc, 0xd0); /* enable interrupts */
|
||||
|
||||
/* determine writeIntrThreshold
|
||||
* empty the FIFO until serviceIntr is set
|
||||
*/
|
||||
for (i=ppc->ppc_fifo; i>0; i--) {
|
||||
if (r_fifo(ppc) != (char)(ppc->ppc_fifo-i)) {
|
||||
LOG_PPC(__FUNCTION__, ppc, "invalid data in FIFO");
|
||||
goto error;
|
||||
}
|
||||
if (r_ecr(ppc) & PPC_SERVICE_INTR) {
|
||||
/* writeIntrThreshold reached */
|
||||
ppc->ppc_wthr = ppc->ppc_fifo - i+1;
|
||||
}
|
||||
/* if FIFO empty before the last byte, error */
|
||||
if (i>1 && (r_ecr(ppc) & PPC_FIFO_EMPTY)) {
|
||||
LOG_PPC(__FUNCTION__, ppc, "data lost in FIFO");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
/* FIFO must be empty after the last byte */
|
||||
if (!(r_ecr(ppc) & PPC_FIFO_EMPTY)) {
|
||||
LOG_PPC(__FUNCTION__, ppc, "can't empty the FIFO");
|
||||
goto error;
|
||||
}
|
||||
|
||||
w_ctr(ppc, ctr_sav);
|
||||
w_ecr(ppc, ecr_sav);
|
||||
|
||||
return (0);
|
||||
|
||||
error:
|
||||
w_ctr(ppc, ctr_sav);
|
||||
w_ecr(ppc, ecr_sav);
|
||||
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -654,6 +767,13 @@ ppc_smc37c66xgt_detect(struct ppc_data *ppc, int chipset_mode)
|
||||
ppc->ppc_avm = chipset_mode;
|
||||
}
|
||||
|
||||
/* set FIFO threshold to 16 */
|
||||
if (ppc->ppc_avm & PPB_ECP) {
|
||||
/* select CRA */
|
||||
outb(csr, 0xa);
|
||||
outb(cio, 16);
|
||||
}
|
||||
|
||||
end_detect:
|
||||
|
||||
if (bootverbose)
|
||||
@ -884,14 +1004,14 @@ ppc_generic_detect(struct ppc_data *ppc, int chipset_mode)
|
||||
|
||||
if (!chipset_mode) {
|
||||
/* first, check for ECP */
|
||||
w_ecr(ppc, 0x20);
|
||||
if ((r_ecr(ppc) & 0xe0) == 0x20) {
|
||||
w_ecr(ppc, PPC_ECR_PS2);
|
||||
if ((r_ecr(ppc) & 0xe0) == PPC_ECR_PS2) {
|
||||
ppc->ppc_avm |= PPB_ECP | PPB_SPP;
|
||||
if (bootverbose)
|
||||
printf(" ECP SPP");
|
||||
|
||||
/* search for SMC style ECP+EPP mode */
|
||||
w_ecr(ppc, 0x80);
|
||||
w_ecr(ppc, PPC_ECR_EPP);
|
||||
}
|
||||
|
||||
/* try to reset EPP timeout bit */
|
||||
@ -911,7 +1031,7 @@ ppc_generic_detect(struct ppc_data *ppc, int chipset_mode)
|
||||
}
|
||||
} else {
|
||||
/* restore to standard mode */
|
||||
w_ecr(ppc, 0x0);
|
||||
w_ecr(ppc, PPC_ECR_STD);
|
||||
}
|
||||
|
||||
/* XXX try to detect NIBBLE and PS2 modes */
|
||||
@ -978,6 +1098,10 @@ ppc_detect(struct ppc_data *ppc, int chipset_mode) {
|
||||
}
|
||||
}
|
||||
|
||||
/* configure/detect ECP FIFO */
|
||||
if ((ppc->ppc_avm & PPB_ECP) && !(ppc->ppc_flags & 0x80))
|
||||
ppc_detect_fifo(ppc);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -1202,6 +1326,244 @@ ppc_exec_microseq(int unit, struct ppb_microseq **p_msq)
|
||||
/* unreached */
|
||||
}
|
||||
|
||||
static void
|
||||
ppcintr(int unit)
|
||||
{
|
||||
struct ppc_data *ppc = ppcdata[unit];
|
||||
char ctr, ecr;
|
||||
|
||||
ctr = r_ctr(ppc);
|
||||
ecr = r_ecr(ppc);
|
||||
|
||||
#ifdef PPC_DEBUG
|
||||
printf("!");
|
||||
#endif
|
||||
|
||||
/* don't use ecp mode with IRQENABLE set */
|
||||
if (ctr & IRQENABLE) {
|
||||
/* call upper code */
|
||||
ppb_intr(&ppc->ppc_link);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctr & nFAULT) {
|
||||
if (ppc->ppc_irqstat & PPC_IRQ_nFAULT) {
|
||||
|
||||
w_ecr(ppc, ecr | PPC_nFAULT_INTR);
|
||||
ppc->ppc_irqstat &= ~PPC_IRQ_nFAULT;
|
||||
} else {
|
||||
/* call upper code */
|
||||
ppb_intr(&ppc->ppc_link);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (ppc->ppc_irqstat & PPC_IRQ_DMA) {
|
||||
/* disable interrupts (should be done by hardware though) */
|
||||
w_ecr(ppc, ecr | PPC_SERVICE_INTR);
|
||||
ppc->ppc_irqstat &= ~PPC_IRQ_DMA;
|
||||
ecr = r_ecr(ppc);
|
||||
|
||||
/* check if DMA completed */
|
||||
if ((ppc->ppc_avm & PPB_ECP) && (ecr & PPC_ENABLE_DMA)) {
|
||||
#ifdef PPC_DEBUG
|
||||
printf("a");
|
||||
#endif
|
||||
/* stop DMA */
|
||||
w_ecr(ppc, ecr & ~PPC_ENABLE_DMA);
|
||||
ecr = r_ecr(ppc);
|
||||
|
||||
if (ppc->ppc_dmastat == PPC_DMA_STARTED) {
|
||||
#ifdef PPC_DEBUG
|
||||
printf("d");
|
||||
#endif
|
||||
isa_dmadone(
|
||||
ppc->ppc_dmaflags,
|
||||
ppc->ppc_dmaddr,
|
||||
ppc->ppc_dmacnt,
|
||||
ppc->ppc_dmachan);
|
||||
|
||||
ppc->ppc_dmastat = PPC_DMA_COMPLETE;
|
||||
|
||||
/* wakeup the waiting process */
|
||||
wakeup((caddr_t)ppc);
|
||||
}
|
||||
}
|
||||
} else if (ppc->ppc_irqstat & PPC_IRQ_FIFO) {
|
||||
|
||||
/* classic interrupt I/O */
|
||||
ppc->ppc_irqstat &= ~PPC_IRQ_FIFO;
|
||||
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int
|
||||
ppc_read(int unit, char *buf, int len, int mode)
|
||||
{
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Call this function if you want to send data in any advanced mode
|
||||
* of your parallel port: FIFO, DMA
|
||||
*
|
||||
* If what you want is not possible (no ECP, no DMA...),
|
||||
* EINVAL is returned
|
||||
*/
|
||||
static int
|
||||
ppc_write(int unit, char *buf, int len, int how)
|
||||
{
|
||||
struct ppc_data *ppc = ppcdata[unit];
|
||||
char ecr, ecr_sav, ctr, ctr_sav;
|
||||
int s, error = 0;
|
||||
int spin;
|
||||
|
||||
#ifdef PPC_DEBUG
|
||||
printf("w");
|
||||
#endif
|
||||
|
||||
ecr_sav = r_ecr(ppc);
|
||||
ctr_sav = r_ctr(ppc);
|
||||
|
||||
/*
|
||||
* Send buffer with DMA, FIFO and interrupts
|
||||
*/
|
||||
if (ppc->ppc_avm & PPB_ECP) {
|
||||
|
||||
if (ppc->ppc_dmachan >= 0) {
|
||||
|
||||
/* byte mode, no intr, no DMA, dir=0, flush fifo
|
||||
*/
|
||||
ecr = PPC_ECR_STD | PPC_DISABLE_INTR;
|
||||
w_ecr(ppc, ecr);
|
||||
|
||||
/* disable nAck interrupts */
|
||||
ctr = r_ctr(ppc);
|
||||
ctr &= ~IRQENABLE;
|
||||
w_ctr(ppc, ctr);
|
||||
|
||||
ppc->ppc_dmaflags = 0;
|
||||
ppc->ppc_dmaddr = (caddr_t)buf;
|
||||
ppc->ppc_dmacnt = (u_int)len;
|
||||
|
||||
switch (ppc->ppc_mode) {
|
||||
case PPB_COMPATIBLE:
|
||||
/* compatible mode with FIFO, no intr, DMA, dir=0 */
|
||||
ecr = PPC_ECR_FIFO | PPC_DISABLE_INTR | PPC_ENABLE_DMA;
|
||||
break;
|
||||
case PPB_ECP:
|
||||
ecr = PPC_ECR_ECP | PPC_DISABLE_INTR | PPC_ENABLE_DMA;
|
||||
break;
|
||||
default:
|
||||
error = EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
w_ecr(ppc, ecr);
|
||||
ecr = r_ecr(ppc);
|
||||
|
||||
/* enter splhigh() not to be preempted
|
||||
* by the dma interrupt, we may miss
|
||||
* the wakeup otherwise
|
||||
*/
|
||||
s = splhigh();
|
||||
|
||||
ppc->ppc_dmastat = PPC_DMA_INIT;
|
||||
|
||||
/* enable interrupts */
|
||||
ecr &= ~PPC_SERVICE_INTR;
|
||||
ppc->ppc_irqstat = PPC_IRQ_DMA;
|
||||
w_ecr(ppc, ecr);
|
||||
|
||||
isa_dmastart(
|
||||
ppc->ppc_dmaflags,
|
||||
ppc->ppc_dmaddr,
|
||||
ppc->ppc_dmacnt,
|
||||
ppc->ppc_dmachan);
|
||||
#ifdef PPC_DEBUG
|
||||
printf("s%d", ppc->ppc_dmacnt);
|
||||
#endif
|
||||
ppc->ppc_dmastat = PPC_DMA_STARTED;
|
||||
|
||||
/* Wait for the DMA completed interrupt. We hope we won't
|
||||
* miss it, otherwise a signal will be necessary to unlock the
|
||||
* process.
|
||||
*/
|
||||
do {
|
||||
/* release CPU */
|
||||
error = tsleep((caddr_t)ppc,
|
||||
PPBPRI | PCATCH, "ppcdma", 0);
|
||||
|
||||
} while (error == EWOULDBLOCK);
|
||||
|
||||
splx(s);
|
||||
|
||||
if (error) {
|
||||
#ifdef PPC_DEBUG
|
||||
printf("i");
|
||||
#endif
|
||||
/* stop DMA */
|
||||
isa_dmadone(
|
||||
ppc->ppc_dmaflags, ppc->ppc_dmaddr,
|
||||
ppc->ppc_dmacnt, ppc->ppc_dmachan);
|
||||
|
||||
/* no dma, no interrupt, flush the fifo */
|
||||
w_ecr(ppc, PPC_ECR_RESET);
|
||||
|
||||
ppc->ppc_dmastat = PPC_DMA_INTERRUPTED;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* wait for an empty fifo */
|
||||
while (!(r_ecr(ppc) & PPC_FIFO_EMPTY)) {
|
||||
|
||||
for (spin=100; spin; spin--)
|
||||
if (r_ecr(ppc) & PPC_FIFO_EMPTY)
|
||||
goto fifo_empty;
|
||||
#ifdef PPC_DEBUG
|
||||
printf("Z");
|
||||
#endif
|
||||
error = tsleep((caddr_t)ppc, PPBPRI | PCATCH, "ppcfifo", hz/100);
|
||||
if (error != EWOULDBLOCK) {
|
||||
#ifdef PPC_DEBUG
|
||||
printf("I");
|
||||
#endif
|
||||
/* no dma, no interrupt, flush the fifo */
|
||||
w_ecr(ppc, PPC_ECR_RESET);
|
||||
|
||||
ppc->ppc_dmastat = PPC_DMA_INTERRUPTED;
|
||||
error = EINTR;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
fifo_empty:
|
||||
/* no dma, no interrupt, flush the fifo */
|
||||
w_ecr(ppc, PPC_ECR_RESET);
|
||||
|
||||
} else
|
||||
error = EINVAL; /* XXX we should FIFO and
|
||||
* interrupts */
|
||||
} else
|
||||
error = EINVAL;
|
||||
|
||||
error:
|
||||
|
||||
/* PDRQ must be kept unasserted until nPDACK is
|
||||
* deasserted for a minimum of 350ns (SMC datasheet)
|
||||
*
|
||||
* Consequence may be a FIFO that never empty
|
||||
*/
|
||||
DELAY(1);
|
||||
|
||||
w_ecr(ppc, ecr_sav);
|
||||
w_ctr(ppc, ctr_sav);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Configure current operating mode
|
||||
*/
|
||||
@ -1209,32 +1571,34 @@ static int
|
||||
ppc_generic_setmode(int unit, int mode)
|
||||
{
|
||||
struct ppc_data *ppc = ppcdata[unit];
|
||||
|
||||
/* back to compatible mode, XXX don't know yet what to do here */
|
||||
if (mode == 0) {
|
||||
ppc->ppc_mode = PPB_COMPATIBLE;
|
||||
return (0);
|
||||
}
|
||||
u_char ecr = 0;
|
||||
|
||||
/* check if mode is available */
|
||||
if (!(ppc->ppc_avm & mode))
|
||||
return (EOPNOTSUPP);
|
||||
if (mode && !(ppc->ppc_avm & mode))
|
||||
return (EINVAL);
|
||||
|
||||
/* if ECP mode, configure ecr register */
|
||||
if (ppc->ppc_avm & PPB_ECP) {
|
||||
/* return to byte mode (keeping direction bit),
|
||||
* no interrupt, no DMA to be able to change to
|
||||
* ECP
|
||||
*/
|
||||
w_ecr(ppc, PPC_ECR_RESET);
|
||||
ecr = PPC_DISABLE_INTR;
|
||||
|
||||
/* XXX disable DMA, enable interrupts */
|
||||
if (mode & PPB_EPP)
|
||||
return (EOPNOTSUPP);
|
||||
else if (mode & PPB_PS2)
|
||||
/* select PS2 mode with ECP */
|
||||
w_ecr(ppc, 0x20);
|
||||
return (EINVAL);
|
||||
else if (mode & PPB_ECP)
|
||||
/* select ECP mode */
|
||||
w_ecr(ppc, 0x60);
|
||||
ecr |= PPC_ECR_ECP;
|
||||
else if (mode & PPB_PS2)
|
||||
/* select PS2 mode with ECP */
|
||||
ecr |= PPC_ECR_PS2;
|
||||
else
|
||||
/* select standard parallel port mode */
|
||||
w_ecr(ppc, 0x00);
|
||||
/* select COMPATIBLE/NIBBLE mode */
|
||||
ecr |= PPC_ECR_STD;
|
||||
|
||||
w_ecr(ppc, ecr);
|
||||
}
|
||||
|
||||
ppc->ppc_mode = mode;
|
||||
@ -1242,42 +1606,50 @@ ppc_generic_setmode(int unit, int mode)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* The ppc driver is free to choose options like FIFO or DMA
|
||||
* if ECP mode is available.
|
||||
*
|
||||
* The 'RAW' option allows the upper drivers to force the ppc mode
|
||||
* even with FIFO, DMA available.
|
||||
*/
|
||||
int
|
||||
ppc_smclike_setmode(int unit, int mode)
|
||||
{
|
||||
struct ppc_data *ppc = ppcdata[unit];
|
||||
|
||||
/* back to compatible mode, XXX don't know yet what to do here */
|
||||
if (mode == 0) {
|
||||
ppc->ppc_mode = PPB_COMPATIBLE;
|
||||
return (0);
|
||||
}
|
||||
u_char ecr = 0;
|
||||
|
||||
/* check if mode is available */
|
||||
if (!(ppc->ppc_avm & mode))
|
||||
return (EOPNOTSUPP);
|
||||
if (mode && !(ppc->ppc_avm & mode))
|
||||
return (EINVAL);
|
||||
|
||||
/* if ECP mode, configure ecr register */
|
||||
if (ppc->ppc_avm & PPB_ECP) {
|
||||
/* return to byte mode (keeping direction bit),
|
||||
* no interrupt, no DMA to be able to change to
|
||||
* ECP or EPP mode
|
||||
*/
|
||||
w_ecr(ppc, PPC_ECR_RESET);
|
||||
ecr = PPC_DISABLE_INTR;
|
||||
|
||||
/* XXX disable DMA, enable interrupts */
|
||||
if (mode & PPB_EPP)
|
||||
/* select EPP mode */
|
||||
w_ecr(ppc, 0x80);
|
||||
else if (mode & PPB_PS2)
|
||||
/* select PS2 mode with ECP */
|
||||
w_ecr(ppc, 0x20);
|
||||
ecr |= PPC_ECR_EPP;
|
||||
else if (mode & PPB_ECP)
|
||||
/* select ECP mode */
|
||||
w_ecr(ppc, 0x60);
|
||||
ecr |= PPC_ECR_ECP;
|
||||
else if (mode & PPB_PS2)
|
||||
/* select PS2 mode with ECP */
|
||||
ecr |= PPC_ECR_PS2;
|
||||
else
|
||||
/* select standard parallel port mode */
|
||||
w_ecr(ppc, 0x00);
|
||||
/* select COMPATIBLE/NIBBLE mode */
|
||||
ecr |= PPC_ECR_STD;
|
||||
|
||||
w_ecr(ppc, ecr);
|
||||
}
|
||||
|
||||
ppc->ppc_mode = mode;
|
||||
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -1314,8 +1686,9 @@ ppcprobe(struct isa_device *dvp)
|
||||
if((next_bios_ppc < BIOS_MAX_PPC) &&
|
||||
(*(BIOS_PORTS+next_bios_ppc) != 0) ) {
|
||||
dvp->id_iobase = *(BIOS_PORTS+next_bios_ppc++);
|
||||
printf("ppc: parallel port found at 0x%x\n",
|
||||
dvp->id_iobase);
|
||||
if (bootverbose)
|
||||
printf("ppc: parallel port found at 0x%x\n",
|
||||
dvp->id_iobase);
|
||||
} else
|
||||
return (0);
|
||||
}
|
||||
@ -1351,6 +1724,8 @@ ppcprobe(struct isa_device *dvp)
|
||||
if (!(dvp->id_flags & 0x20))
|
||||
ppc->ppc_irq = ffs(dvp->id_irq) - 1;
|
||||
|
||||
ppc->ppc_dmachan = dvp->id_drq;
|
||||
|
||||
ppcdata[ppc->ppc_unit] = ppc;
|
||||
nppc ++;
|
||||
|
||||
@ -1384,6 +1759,11 @@ ppcattach(struct isa_device *isdp)
|
||||
ppc_modes[ppc->ppc_mode], (PPB_IS_EPP(ppc->ppc_mode)) ?
|
||||
ppc_epp_protocol[ppc->ppc_epp] : "");
|
||||
|
||||
if (ppc->ppc_fifo)
|
||||
printf("ppc%d: FIFO with %d/%d/%d bytes threshold\n",
|
||||
ppc->ppc_unit, ppc->ppc_fifo, ppc->ppc_wthr,
|
||||
ppc->ppc_rthr);
|
||||
|
||||
isdp->id_ointr = ppcintr;
|
||||
|
||||
/*
|
||||
@ -1397,6 +1777,13 @@ ppcattach(struct isa_device *isdp)
|
||||
ppc->ppc_link.ppbus = ppbus;
|
||||
ppbus->ppb_link = &ppc->ppc_link;
|
||||
|
||||
if ((ppc->ppc_avm & PPB_ECP) && (ppc->ppc_dmachan > 0)) {
|
||||
|
||||
/* acquire the DMA channel forever */
|
||||
isa_dma_acquire(ppc->ppc_dmachan);
|
||||
isa_dmainit(ppc->ppc_dmachan, 1024); /* nlpt.BUFSIZE */
|
||||
}
|
||||
|
||||
/*
|
||||
* Probe the ppbus and attach devices found.
|
||||
*/
|
||||
|
@ -23,7 +23,7 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: ppcreg.h,v 1.4 1998/09/13 18:26:44 nsouch Exp $
|
||||
* $Id: ppcreg.h,v 1.5 1998/10/31 11:37:09 nsouch Exp $
|
||||
*
|
||||
*/
|
||||
#ifndef __PPCREG_H
|
||||
@ -55,6 +55,34 @@ struct ppc_data {
|
||||
int ppc_mode; /* chipset current mode */
|
||||
int ppc_avm; /* chipset available modes */
|
||||
|
||||
#define PPC_IRQ_NONE 0x0
|
||||
#define PPC_IRQ_nACK 0x1
|
||||
#define PPC_IRQ_DMA 0x2
|
||||
#define PPC_IRQ_FIFO 0x4
|
||||
#define PPC_IRQ_nFAULT 0x8
|
||||
int ppc_irqstat; /* remind irq settings */
|
||||
|
||||
#define PPC_DMA_INIT 0x01
|
||||
#define PPC_DMA_STARTED 0x02
|
||||
#define PPC_DMA_COMPLETE 0x03
|
||||
#define PPC_DMA_INTERRUPTED 0x04
|
||||
#define PPC_DMA_ERROR 0x05
|
||||
int ppc_dmastat; /* dma state */
|
||||
int ppc_dmachan; /* dma channel */
|
||||
int ppc_dmaflags; /* dma transfer flags */
|
||||
caddr_t ppc_dmaddr; /* buffer address */
|
||||
u_int ppc_dmacnt; /* count of bytes sent with dma */
|
||||
|
||||
#define PPC_PWORD_MASK 0x30
|
||||
#define PPC_PWORD_16 0x00
|
||||
#define PPC_PWORD_8 0x10
|
||||
#define PPC_PWORD_32 0x20
|
||||
char ppc_pword; /* PWord size */
|
||||
short ppc_fifo; /* FIFO threshold */
|
||||
|
||||
short ppc_wthr; /* writeIntrThresold */
|
||||
short ppc_rthr; /* readIntrThresold */
|
||||
|
||||
#define ppc_base ppc_link.base
|
||||
#define ppc_epp ppc_link.epp_protocol
|
||||
#define ppc_irq ppc_link.id_irq
|
||||
@ -71,25 +99,44 @@ struct ppc_data {
|
||||
* Parallel Port Chipset registers.
|
||||
*/
|
||||
#define PPC_SPP_DTR 0 /* SPP data register */
|
||||
#define PPC_ECP_A_FIFO 0 /* ECP Address fifo register */
|
||||
#define PPC_SPP_STR 1 /* SPP status register */
|
||||
#define PPC_SPP_CTR 2 /* SPP control register */
|
||||
#define PPC_EPP_DATA 4 /* EPP data register (8, 16 or 32 bit) */
|
||||
#define PPC_ECP_FIFO 0x400 /* ECP fifo register */
|
||||
#define PPC_ECP_D_FIFO 0x400 /* ECP Data fifo register */
|
||||
#define PPC_ECP_CNFGA 0x400 /* Configuration register A */
|
||||
#define PPC_ECP_CNFGB 0x401 /* Configuration register B */
|
||||
#define PPC_ECP_ECR 0x402 /* ECP extended control register */
|
||||
|
||||
#define PPC_FIFO_EMPTY 0x1 /* ecr register - bit 0 */
|
||||
#define PPC_FIFO_FULL 0x2 /* ecr register - bit 1 */
|
||||
#define PPC_SERVICE_INTR 0x4 /* ecr register - bit 2 */
|
||||
#define PPC_ENABLE_DMA 0x8 /* ecr register - bit 3 */
|
||||
#define PPC_nFAULT_INTR 0x10 /* ecr register - bit 4 */
|
||||
#define PPC_ECR_STD 0x0
|
||||
#define PPC_ECR_PS2 0x20
|
||||
#define PPC_ECR_FIFO 0x40
|
||||
#define PPC_ECR_ECP 0x60
|
||||
#define PPC_ECR_EPP 0x80
|
||||
|
||||
#define PPC_DISABLE_INTR (PPC_SERVICE_INTR | PPC_nFAULT_INTR)
|
||||
#define PPC_ECR_RESET (PPC_ECR_PS2 | PPC_DISABLE_INTR)
|
||||
|
||||
#define r_dtr(ppc) ((char)inb((ppc)->ppc_base + PPC_SPP_DTR))
|
||||
#define r_str(ppc) ((char)inb((ppc)->ppc_base + PPC_SPP_STR))
|
||||
#define r_ctr(ppc) ((char)inb((ppc)->ppc_base + PPC_SPP_CTR))
|
||||
#define r_epp(ppc) ((char)inb((ppc)->ppc_base + PPC_EPP_DATA))
|
||||
#define r_cnfgA(ppc) ((char)inb((ppc)->ppc_base + PPC_ECP_CNFGA))
|
||||
#define r_cnfgB(ppc) ((char)inb((ppc)->ppc_base + PPC_ECP_CNFGB))
|
||||
#define r_ecr(ppc) ((char)inb((ppc)->ppc_base + PPC_ECP_ECR))
|
||||
#define r_fifo(ppc) ((char)inb((ppc)->ppc_base + PPC_ECP_FIFO))
|
||||
#define r_fifo(ppc) ((char)inb((ppc)->ppc_base + PPC_ECP_D_FIFO))
|
||||
|
||||
#define w_dtr(ppc,byte) outb((ppc)->ppc_base + PPC_SPP_DTR, byte)
|
||||
#define w_str(ppc,byte) outb((ppc)->ppc_base + PPC_SPP_STR, byte)
|
||||
#define w_ctr(ppc,byte) outb((ppc)->ppc_base + PPC_SPP_CTR, byte)
|
||||
#define w_epp(ppc,byte) outb((ppc)->ppc_base + PPC_EPP_DATA, byte)
|
||||
#define w_ecr(ppc,byte) outb((ppc)->ppc_base + PPC_ECP_ECR, byte)
|
||||
#define w_fifo(ppc,byte) outb((ppc)->ppc_base + PPC_ECP_FIFO, byte)
|
||||
#define w_fifo(ppc,byte) outb((ppc)->ppc_base + PPC_ECP_D_FIFO, byte)
|
||||
|
||||
/*
|
||||
* Register defines for the PC873xx parts
|
||||
|
@ -30,7 +30,7 @@
|
||||
|
||||
#ifndef lint
|
||||
static const char rcsid[] =
|
||||
"$Id$";
|
||||
"$Id: lptcontrol.c,v 1.6 1997/09/25 06:36:29 charnier Exp $";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <ctype.h>
|
||||
@ -53,10 +53,12 @@ static const char rcsid[] =
|
||||
#define IRQ_INVALID -1
|
||||
#define DO_POLL 0
|
||||
#define USE_IRQ 1
|
||||
#define USE_EXT_MODE 2
|
||||
#define USE_STD_MODE 3
|
||||
|
||||
static void usage()
|
||||
{
|
||||
fprintf(stderr, "usage: lptcontrol -i | -p [-u <unit no.>]\n");
|
||||
fprintf(stderr, "usage: lptcontrol -i | -p | -s | -e [-u <unit no.>]\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@ -89,10 +91,12 @@ int main (int argc, char * argv[])
|
||||
int irq_status = IRQ_INVALID;
|
||||
char * unit = DEFAULT_UNIT;
|
||||
|
||||
while((opt = getopt(argc, argv, "ipu:")) != -1)
|
||||
while((opt = getopt(argc, argv, "ipesu:")) != -1)
|
||||
switch(opt) {
|
||||
case 'i': irq_status = USE_IRQ; break;
|
||||
case 'p': irq_status = DO_POLL; break;
|
||||
case 'e': irq_status = USE_EXT_MODE; break;
|
||||
case 's': irq_status = USE_STD_MODE; break;
|
||||
case 'u': unit = optarg;
|
||||
if(!isdigit(*unit))
|
||||
usage();
|
||||
|
Loading…
Reference in New Issue
Block a user