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:
Nicolas Souchu 1999-01-10 12:04:56 +00:00
parent b7fe2b6dab
commit bc35c17446
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=42475
22 changed files with 2939 additions and 375 deletions

View File

@ -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

View File

@ -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>

View File

@ -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)

View File

@ -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;

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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);
}

View File

@ -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);

View File

@ -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 */

View File

@ -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

View File

@ -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.

View File

@ -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;

View File

@ -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>

View File

@ -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);

View File

@ -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.
*/

View File

@ -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

View File

@ -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.
*/

View File

@ -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

View File

@ -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.
*/

View File

@ -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

View File

@ -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();