ppi.c revision 55977
128219Smsmith/*-
255939Snsouch * Copyright (c) 1997, 1998, 1999 Nicolas Souchu, Michael Smith
328219Smsmith * All rights reserved.
428219Smsmith *
528219Smsmith * Redistribution and use in source and binary forms, with or without
628219Smsmith * modification, are permitted provided that the following conditions
728219Smsmith * are met:
828219Smsmith * 1. Redistributions of source code must retain the above copyright
928219Smsmith *    notice, this list of conditions and the following disclaimer.
1028219Smsmith * 2. Redistributions in binary form must reproduce the above copyright
1128219Smsmith *    notice, this list of conditions and the following disclaimer in the
1228219Smsmith *    documentation and/or other materials provided with the distribution.
1328219Smsmith *
1428219Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1528219Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1628219Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1728219Smsmith * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1828219Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1928219Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2028219Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2128219Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2228219Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2328219Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2428219Smsmith * SUCH DAMAGE.
2528219Smsmith *
2650477Speter * $FreeBSD: head/sys/dev/ppbus/ppi.c 55977 2000-01-14 15:54:45Z peter $
2728219Smsmith *
2828219Smsmith */
2928257Smsmith#include "ppi.h"
3028257Smsmith
3128257Smsmith#if NPPI > 0
3228257Smsmith
3355939Snsouch#include "opt_ppb_1284.h"
3455939Snsouch
3528219Smsmith#include <sys/param.h>
3628219Smsmith#include <sys/systm.h>
3755939Snsouch#include <sys/module.h>
3855939Snsouch#include <sys/bus.h>
3928219Smsmith#include <sys/conf.h>
4028219Smsmith#include <sys/kernel.h>
4142475Snsouch#include <sys/uio.h>
4232178Smsmith#include <sys/fcntl.h>
4328219Smsmith
4442475Snsouch#include <machine/clock.h>
4555939Snsouch#include <machine/bus.h>
4655939Snsouch#include <machine/resource.h>
4755939Snsouch#include <sys/rman.h>
4842475Snsouch
4928219Smsmith#include <dev/ppbus/ppbconf.h>
5042475Snsouch#include <dev/ppbus/ppb_msq.h>
5142475Snsouch
5242475Snsouch#ifdef PERIPH_1284
5342475Snsouch#include <dev/ppbus/ppb_1284.h>
5442475Snsouch#endif
5542475Snsouch
5632178Smsmith#include <dev/ppbus/ppi.h>
5728219Smsmith
5855939Snsouch#include "ppbus_if.h"
5955939Snsouch
6055939Snsouch#include <dev/ppbus/ppbio.h>
6155939Snsouch
6242475Snsouch#define BUFSIZE		512
6332178Smsmith
6428257Smsmithstruct ppi_data {
6528257Smsmith
6632178Smsmith    int		ppi_unit;
6732178Smsmith    int		ppi_flags;
6832178Smsmith#define HAVE_PPBUS	(1<<0)
6942475Snsouch#define HAD_PPBUS	(1<<1)
7028257Smsmith
7142475Snsouch    int		ppi_count;
7242475Snsouch    int		ppi_mode;			/* IEEE1284 mode */
7342475Snsouch    char	ppi_buffer[BUFSIZE];
7442475Snsouch
7555939Snsouch    struct resource *intr_resource;	/* interrupt resource */
7655939Snsouch    void *intr_cookie;			/* interrupt registration cookie */
7728257Smsmith};
7828257Smsmith
7955939Snsouch#define DEVTOSOFTC(dev) \
8055939Snsouch	((struct ppi_data *)device_get_softc(dev))
8155939Snsouch#define UNITOSOFTC(unit) \
8255939Snsouch	((struct ppi_data *)devclass_get_softc(ppi_devclass, (unit)))
8355939Snsouch#define UNITODEVICE(unit) \
8455939Snsouch	(devclass_get_device(ppi_devclass, (unit)))
8528219Smsmith
8655939Snsouchstatic int ppi_probe(device_t);
8755939Snsouchstatic int ppi_attach(device_t);
8855939Snsouchstatic void ppiintr(void *arg);
8928219Smsmith
9055939Snsouchstatic devclass_t ppi_devclass;
9128219Smsmith
9255939Snsouchstatic device_method_t ppi_methods[] = {
9355939Snsouch	/* device interface */
9455939Snsouch	DEVMETHOD(device_probe,		ppi_probe),
9555939Snsouch	DEVMETHOD(device_attach,	ppi_attach),
9655939Snsouch
9755939Snsouch	{ 0, 0 }
9828219Smsmith};
9928219Smsmith
10055939Snsouchstatic driver_t ppi_driver = {
10155939Snsouch	"ppi",
10255939Snsouch	ppi_methods,
10355939Snsouch	sizeof(struct ppi_data),
10455939Snsouch};
10555939Snsouch
10628219Smsmithstatic	d_open_t	ppiopen;
10728219Smsmithstatic	d_close_t	ppiclose;
10828219Smsmithstatic	d_ioctl_t	ppiioctl;
10942475Snsouchstatic	d_write_t	ppiwrite;
11042475Snsouchstatic	d_read_t	ppiread;
11128219Smsmith
11228261Smsmith#define CDEV_MAJOR 82
11347625Sphkstatic struct cdevsw ppi_cdevsw = {
11447625Sphk	/* open */	ppiopen,
11547625Sphk	/* close */	ppiclose,
11647625Sphk	/* read */	ppiread,
11747625Sphk	/* write */	ppiwrite,
11847625Sphk	/* ioctl */	ppiioctl,
11947625Sphk	/* poll */	nopoll,
12047625Sphk	/* mmap */	nommap,
12147625Sphk	/* strategy */	nostrategy,
12247625Sphk	/* name */	"ppi",
12347625Sphk	/* maj */	CDEV_MAJOR,
12447625Sphk	/* dump */	nodump,
12547625Sphk	/* psize */	nopsize,
12647625Sphk	/* flags */	0,
12747625Sphk	/* bmaj */	-1
12847625Sphk};
12928219Smsmith
13042475Snsouch#ifdef PERIPH_1284
13142475Snsouch
13242475Snsouchstatic void
13355939Snsouchppi_enable_intr(device_t ppidev)
13442475Snsouch{
13542475Snsouch	char r;
13655939Snsouch	device_t ppbus = device_get_parent(ppidev);
13742475Snsouch
13855939Snsouch	r = ppb_rctr(ppbus);
13955939Snsouch	ppb_wctr(ppbus, r | IRQENABLE);
14042475Snsouch
14142475Snsouch	return;
14242475Snsouch}
14342475Snsouch
14442475Snsouchstatic void
14555939Snsouchppi_disable_intr(device_t ppidev)
14642475Snsouch{
14742475Snsouch	char r;
14855939Snsouch        device_t ppbus = device_get_parent(ppidev);
14942475Snsouch
15055939Snsouch	r = ppb_rctr(ppbus);
15155939Snsouch	ppb_wctr(ppbus, r & ~IRQENABLE);
15242475Snsouch
15342475Snsouch	return;
15442475Snsouch}
15542475Snsouch
15642475Snsouch#endif /* PERIPH_1284 */
15742475Snsouch
15828219Smsmith/*
15955939Snsouch * ppi_probe()
16028219Smsmith */
16155939Snsouchstatic int
16255939Snsouchppi_probe(device_t dev)
16328219Smsmith{
16428219Smsmith	struct ppi_data *ppi;
16547640Sphk	static int once;
16628219Smsmith
16755939Snsouch	/* probe is always ok */
16855939Snsouch	device_set_desc(dev, "Parallel I/O");
16955939Snsouch
17047640Sphk	if (!once++)
17147640Sphk		cdevsw_add(&ppi_cdevsw);
17247640Sphk
17355939Snsouch	ppi = DEVTOSOFTC(dev);
17428219Smsmith	bzero(ppi, sizeof(struct ppi_data));
17528219Smsmith
17655939Snsouch	return (0);
17755939Snsouch}
17828219Smsmith
17955939Snsouch/*
18055939Snsouch * ppi_attach()
18155939Snsouch */
18255939Snsouchstatic int
18355939Snsouchppi_attach(device_t dev)
18455939Snsouch{
18555939Snsouch	uintptr_t irq;
18655939Snsouch	int zero = 0;
18755939Snsouch	struct ppi_data *ppi = DEVTOSOFTC(dev);
18828219Smsmith
18955939Snsouch	/* retrive the irq */
19055939Snsouch	BUS_READ_IVAR(device_get_parent(dev), dev, PPBUS_IVAR_IRQ, &irq);
19128219Smsmith
19255939Snsouch	/* declare our interrupt handler */
19355939Snsouch	ppi->intr_resource = bus_alloc_resource(dev, SYS_RES_IRQ,
19455939Snsouch						&zero, irq, irq, 1, RF_ACTIVE);
19528219Smsmith
19655939Snsouch	make_dev(&ppi_cdevsw, device_get_unit(dev),	/* XXX cleanup */
19755939Snsouch		 UID_ROOT, GID_WHEEL,
19855939Snsouch		 0600, "ppi%d", device_get_unit(dev));
19928219Smsmith
20055939Snsouch	return (0);
20128219Smsmith}
20228219Smsmith
20342475Snsouch/*
20442475Snsouch * Cable
20542475Snsouch * -----
20642475Snsouch *
20742475Snsouch * Use an IEEE1284 compliant (DB25/DB25) cable with the following tricks:
20842475Snsouch *
20942475Snsouch * nStrobe   <-> nAck		1  <-> 10
21042475Snsouch * nAutofd   <-> Busy		11 <-> 14
21142475Snsouch * nSelectin <-> Select		17 <-> 13
21242475Snsouch * nInit     <-> nFault		15 <-> 16
21342475Snsouch *
21442475Snsouch */
21528219Smsmithstatic void
21655939Snsouchppiintr(void *arg)
21728219Smsmith{
21842475Snsouch#ifdef PERIPH_1284
21955939Snsouch	device_t ppidev = (device_t)arg;
22055939Snsouch        device_t ppbus = device_get_parent(ppidev);
22155939Snsouch	struct ppi_data *ppi = DEVTOSOFTC(ppidev);
22242475Snsouch
22355939Snsouch	ppi_disable_intr(ppidev);
22442475Snsouch
22555939Snsouch	switch (ppb_1284_get_state(ppbus)) {
22642475Snsouch
22742475Snsouch	/* accept IEEE1284 negociation then wakeup an waiting process to
22842475Snsouch	 * continue negociation at process level */
22942475Snsouch	case PPB_FORWARD_IDLE:
23042475Snsouch		/* Event 1 */
23155939Snsouch		if ((ppb_rstr(ppbus) & (SELECT | nBUSY)) ==
23242475Snsouch							(SELECT | nBUSY)) {
23342475Snsouch			/* IEEE1284 negociation */
23442475Snsouch#ifdef DEBUG_1284
23542475Snsouch			printf("N");
23642475Snsouch#endif
23742475Snsouch
23842475Snsouch			/* Event 2 - prepare for reading the ext. value */
23955939Snsouch			ppb_wctr(ppbus, (PCD | STROBE | nINIT) & ~SELECTIN);
24042475Snsouch
24155939Snsouch			ppb_1284_set_state(ppbus, PPB_NEGOCIATION);
24242475Snsouch
24342475Snsouch		} else {
24442475Snsouch#ifdef DEBUG_1284
24555939Snsouch			printf("0x%x", ppb_rstr(ppbus));
24642475Snsouch#endif
24755939Snsouch			ppb_peripheral_terminate(ppbus, PPB_DONTWAIT);
24842475Snsouch			break;
24942475Snsouch		}
25042475Snsouch
25142475Snsouch		/* wake up any process waiting for negociation from
25242475Snsouch		 * remote master host */
25342475Snsouch
25442475Snsouch		/* XXX should set a variable to warn the process about
25542475Snsouch		 * the interrupt */
25642475Snsouch
25742475Snsouch		wakeup(ppi);
25842475Snsouch		break;
25942475Snsouch	default:
26042475Snsouch#ifdef DEBUG_1284
26155977Speter		printf("?%d", ppb_1284_get_state(ppbus));
26242475Snsouch#endif
26355939Snsouch		ppb_1284_set_state(ppbus, PPB_FORWARD_IDLE);
26455939Snsouch		ppb_set_mode(ppbus, PPB_COMPATIBLE);
26542475Snsouch		break;
26642475Snsouch	}
26742475Snsouch
26855939Snsouch	ppi_enable_intr(ppidev);
26942475Snsouch#endif /* PERIPH_1284 */
27042475Snsouch
27128219Smsmith	return;
27228219Smsmith}
27328219Smsmith
27428219Smsmithstatic int
27528219Smsmithppiopen(dev_t dev, int flags, int fmt, struct proc *p)
27628219Smsmith{
27728257Smsmith	u_int unit = minor(dev);
27855939Snsouch	struct ppi_data *ppi = UNITOSOFTC(unit);
27955939Snsouch	device_t ppidev = UNITODEVICE(unit);
28055939Snsouch        device_t ppbus = device_get_parent(ppidev);
28132178Smsmith	int res;
28228257Smsmith
28355939Snsouch	if (!ppi)
28428257Smsmith		return (ENXIO);
28528257Smsmith
28642475Snsouch	if (!(ppi->ppi_flags & HAVE_PPBUS)) {
28755939Snsouch		if ((res = ppb_request_bus(ppbus, ppidev,
28842475Snsouch			(flags & O_NONBLOCK) ? PPB_DONTWAIT :
28942475Snsouch						(PPB_WAIT | PPB_INTR))))
29032178Smsmith			return (res);
29128257Smsmith
29242475Snsouch		ppi->ppi_flags |= HAVE_PPBUS;
29355939Snsouch
29455939Snsouch		/* register our interrupt handler */
29555939Snsouch		BUS_SETUP_INTR(device_get_parent(ppidev), ppidev, ppi->intr_resource,
29655939Snsouch			       INTR_TYPE_TTY, ppiintr, dev, &ppi->intr_cookie);
29742475Snsouch	}
29842475Snsouch	ppi->ppi_count += 1;
29942475Snsouch
30032178Smsmith	return (0);
30128219Smsmith}
30228219Smsmith
30328219Smsmithstatic int
30428219Smsmithppiclose(dev_t dev, int flags, int fmt, struct proc *p)
30528219Smsmith{
30632178Smsmith	u_int unit = minor(dev);
30755939Snsouch	struct ppi_data *ppi = UNITOSOFTC(unit);
30855939Snsouch	device_t ppidev = UNITODEVICE(unit);
30955939Snsouch        device_t ppbus = device_get_parent(ppidev);
31032178Smsmith
31142475Snsouch	ppi->ppi_count --;
31242475Snsouch	if (!ppi->ppi_count) {
31342475Snsouch
31442475Snsouch#ifdef PERIPH_1284
31555939Snsouch		switch (ppb_1284_get_state(ppbus)) {
31642475Snsouch		case PPB_PERIPHERAL_IDLE:
31755939Snsouch			ppb_peripheral_terminate(ppbus, 0);
31842475Snsouch			break;
31942475Snsouch		case PPB_REVERSE_IDLE:
32042475Snsouch		case PPB_EPP_IDLE:
32142475Snsouch		case PPB_ECP_FORWARD_IDLE:
32242475Snsouch		default:
32355939Snsouch			ppb_1284_terminate(ppbus);
32442475Snsouch			break;
32542475Snsouch		}
32642475Snsouch#endif /* PERIPH_1284 */
32742475Snsouch
32855939Snsouch		/* unregistration of interrupt forced by release */
32955939Snsouch		ppb_release_bus(ppbus, ppidev);
33055939Snsouch
33142475Snsouch		ppi->ppi_flags &= ~HAVE_PPBUS;
33242475Snsouch	}
33342475Snsouch
33432178Smsmith	return (0);
33528219Smsmith}
33628219Smsmith
33742475Snsouch/*
33842475Snsouch * ppiread()
33942475Snsouch *
34042475Snsouch * IEEE1284 compliant read.
34142475Snsouch *
34242475Snsouch * First, try negociation to BYTE then NIBBLE mode
34342475Snsouch * If no data is available, wait for it otherwise transfer as much as possible
34442475Snsouch */
34528219Smsmithstatic int
34642475Snsouchppiread(dev_t dev, struct uio *uio, int ioflag)
34742475Snsouch{
34842475Snsouch#ifdef PERIPH_1284
34942475Snsouch	u_int unit = minor(dev);
35055939Snsouch	struct ppi_data *ppi = UNITOSOFTC(unit);
35155939Snsouch	device_t ppidev = UNITODEVICE(unit);
35255939Snsouch        device_t ppbus = device_get_parent(ppidev);
35342475Snsouch	int len, error = 0;
35442475Snsouch
35555939Snsouch	switch (ppb_1284_get_state(ppbus)) {
35642475Snsouch	case PPB_PERIPHERAL_IDLE:
35755939Snsouch		ppb_peripheral_terminate(ppbus, 0);
35842475Snsouch		/* fall throught */
35942475Snsouch
36042475Snsouch	case PPB_FORWARD_IDLE:
36142475Snsouch		/* if can't negociate NIBBLE mode then try BYTE mode,
36242475Snsouch		 * the peripheral may be a computer
36342475Snsouch		 */
36455939Snsouch		if ((ppb_1284_negociate(ppbus,
36542475Snsouch			ppi->ppi_mode = PPB_NIBBLE, 0))) {
36642475Snsouch
36742475Snsouch			/* XXX Wait 2 seconds to let the remote host some
36842475Snsouch			 * time to terminate its interrupt
36942475Snsouch			 */
37042475Snsouch			tsleep(ppi, PPBPRI, "ppiread", 2*hz);
37142475Snsouch
37255939Snsouch			if ((error = ppb_1284_negociate(ppbus,
37342475Snsouch				ppi->ppi_mode = PPB_BYTE, 0)))
37442475Snsouch				return (error);
37542475Snsouch		}
37642475Snsouch		break;
37742475Snsouch
37842475Snsouch	case PPB_REVERSE_IDLE:
37942475Snsouch	case PPB_EPP_IDLE:
38042475Snsouch	case PPB_ECP_FORWARD_IDLE:
38142475Snsouch	default:
38242475Snsouch		break;
38342475Snsouch	}
38442475Snsouch
38542475Snsouch#ifdef DEBUG_1284
38642475Snsouch	printf("N");
38742475Snsouch#endif
38842475Snsouch	/* read data */
38942475Snsouch	len = 0;
39042475Snsouch	while (uio->uio_resid) {
39155939Snsouch		if ((error = ppb_1284_read(ppbus, ppi->ppi_mode,
39242475Snsouch			ppi->ppi_buffer, min(BUFSIZE, uio->uio_resid),
39342475Snsouch			&len))) {
39442475Snsouch			goto error;
39542475Snsouch		}
39642475Snsouch
39742475Snsouch		if (!len)
39842475Snsouch			goto error;		/* no more data */
39942475Snsouch
40042475Snsouch#ifdef DEBUG_1284
40142475Snsouch		printf("d");
40242475Snsouch#endif
40342475Snsouch		if ((error = uiomove(ppi->ppi_buffer, len, uio)))
40442475Snsouch			goto error;
40542475Snsouch	}
40642475Snsouch
40742475Snsoucherror:
40842475Snsouch
40942475Snsouch#else /* PERIPH_1284 */
41042475Snsouch	int error = ENODEV;
41142475Snsouch#endif
41242475Snsouch
41342475Snsouch	return (error);
41442475Snsouch}
41542475Snsouch
41642475Snsouch/*
41742475Snsouch * ppiwrite()
41842475Snsouch *
41942475Snsouch * IEEE1284 compliant write
42042475Snsouch *
42142475Snsouch * Actually, this is the peripheral side of a remote IEEE1284 read
42242475Snsouch *
42342475Snsouch * The first part of the negociation (IEEE1284 device detection) is
42442475Snsouch * done at interrupt level, then the remaining is done by the writing
42542475Snsouch * process
42642475Snsouch *
42742475Snsouch * Once negociation done, transfer data
42842475Snsouch */
42942475Snsouchstatic int
43042475Snsouchppiwrite(dev_t dev, struct uio *uio, int ioflag)
43142475Snsouch{
43242475Snsouch#ifdef PERIPH_1284
43342475Snsouch	u_int unit = minor(dev);
43455939Snsouch	struct ppi_data *ppi = UNITOSOFTC(unit);
43555939Snsouch	device_t ppidev = UNITODEVICE(unit);
43655939Snsouch        device_t ppbus = device_get_parent(ppidev);
43742475Snsouch	int len, error = 0, sent;
43842475Snsouch
43942475Snsouch#if 0
44042475Snsouch	int ret;
44142475Snsouch
44242475Snsouch	#define ADDRESS		MS_PARAM(0, 0, MS_TYP_PTR)
44342475Snsouch	#define LENGTH		MS_PARAM(0, 1, MS_TYP_INT)
44442475Snsouch
44542475Snsouch	struct ppb_microseq msq[] = {
44642475Snsouch		  { MS_OP_PUT, { MS_UNKNOWN, MS_UNKNOWN, MS_UNKNOWN } },
44742475Snsouch		  MS_RET(0)
44842475Snsouch	};
44942475Snsouch
45042475Snsouch	/* negociate ECP mode */
45155939Snsouch	if (ppb_1284_negociate(ppbus, PPB_ECP, 0)) {
45242475Snsouch		printf("ppiwrite: ECP negociation failed\n");
45342475Snsouch	}
45442475Snsouch
45542475Snsouch	while (!error && (len = min(uio->uio_resid, BUFSIZE))) {
45642475Snsouch		uiomove(ppi->ppi_buffer, len, uio);
45742475Snsouch
45842475Snsouch		ppb_MS_init_msq(msq, 2, ADDRESS, ppi->ppi_buffer, LENGTH, len);
45942475Snsouch
46055939Snsouch		error = ppb_MS_microseq(ppbus, msq, &ret);
46142475Snsouch	}
46242475Snsouch#endif
46342475Snsouch
46442475Snsouch	/* we have to be peripheral to be able to send data, so
46542475Snsouch	 * wait for the appropriate state
46642475Snsouch	 */
46755957Snsouch 	if (ppb_1284_get_state(ppbus) < PPB_PERIPHERAL_NEGOCIATION)
46855939Snsouch		ppb_1284_terminate(ppbus);
46942475Snsouch
47055957Snsouch 	while (ppb_1284_get_state(ppbus) != PPB_PERIPHERAL_IDLE) {
47142475Snsouch		/* XXX should check a variable before sleeping */
47242475Snsouch#ifdef DEBUG_1284
47342475Snsouch		printf("s");
47442475Snsouch#endif
47542475Snsouch
47655939Snsouch		ppi_enable_intr(ppidev);
47742475Snsouch
47842475Snsouch		/* sleep until IEEE1284 negociation starts */
47942475Snsouch		error = tsleep(ppi, PCATCH | PPBPRI, "ppiwrite", 0);
48042475Snsouch
48142475Snsouch		switch (error) {
48242475Snsouch		case 0:
48342475Snsouch			/* negociate peripheral side with BYTE mode */
48455939Snsouch			ppb_peripheral_negociate(ppbus, PPB_BYTE, 0);
48542475Snsouch			break;
48642475Snsouch		case EWOULDBLOCK:
48742475Snsouch			break;
48842475Snsouch		default:
48942475Snsouch			goto error;
49042475Snsouch		}
49142475Snsouch	}
49242475Snsouch#ifdef DEBUG_1284
49342475Snsouch	printf("N");
49442475Snsouch#endif
49542475Snsouch
49642475Snsouch	/* negociation done, write bytes to master host */
49743301Sdillon	while ((len = min(uio->uio_resid, BUFSIZE)) != 0) {
49842475Snsouch		uiomove(ppi->ppi_buffer, len, uio);
49955939Snsouch		if ((error = byte_peripheral_write(ppbus,
50042475Snsouch						ppi->ppi_buffer, len, &sent)))
50142475Snsouch			goto error;
50242475Snsouch#ifdef DEBUG_1284
50342475Snsouch		printf("d");
50442475Snsouch#endif
50542475Snsouch	}
50642475Snsouch
50742475Snsoucherror:
50842475Snsouch
50942475Snsouch#else /* PERIPH_1284 */
51042475Snsouch	int error = ENODEV;
51142475Snsouch#endif
51242475Snsouch
51342475Snsouch	return (error);
51442475Snsouch}
51542475Snsouch
51642475Snsouchstatic int
51736735Sdfrppiioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
51828219Smsmith{
51932178Smsmith	u_int unit = minor(dev);
52055939Snsouch	device_t ppidev = UNITODEVICE(unit);
52155939Snsouch        device_t ppbus = device_get_parent(ppidev);
52232178Smsmith	int error = 0;
52332178Smsmith	u_int8_t *val = (u_int8_t *)data;
52432178Smsmith
52532178Smsmith	switch (cmd) {
52632178Smsmith
52732178Smsmith	case PPIGDATA:			/* get data register */
52855939Snsouch		*val = ppb_rdtr(ppbus);
52932178Smsmith		break;
53032178Smsmith	case PPIGSTATUS:		/* get status bits */
53155939Snsouch		*val = ppb_rstr(ppbus);
53232178Smsmith		break;
53332178Smsmith	case PPIGCTRL:			/* get control bits */
53455939Snsouch		*val = ppb_rctr(ppbus);
53532178Smsmith		break;
53643433Snsouch	case PPIGEPPD:			/* get EPP data bits */
53755939Snsouch		*val = ppb_repp_D(ppbus);
53832178Smsmith		break;
53932178Smsmith	case PPIGECR:			/* get ECP bits */
54055939Snsouch		*val = ppb_recr(ppbus);
54132178Smsmith		break;
54232178Smsmith	case PPIGFIFO:			/* read FIFO */
54355939Snsouch		*val = ppb_rfifo(ppbus);
54432178Smsmith		break;
54532178Smsmith	case PPISDATA:			/* set data register */
54655939Snsouch		ppb_wdtr(ppbus, *val);
54732178Smsmith		break;
54832178Smsmith	case PPISSTATUS:		/* set status bits */
54955939Snsouch		ppb_wstr(ppbus, *val);
55032178Smsmith		break;
55132178Smsmith	case PPISCTRL:			/* set control bits */
55255939Snsouch		ppb_wctr(ppbus, *val);
55332178Smsmith		break;
55443433Snsouch	case PPISEPPD:			/* set EPP data bits */
55555939Snsouch		ppb_wepp_D(ppbus, *val);
55632178Smsmith		break;
55732178Smsmith	case PPISECR:			/* set ECP bits */
55855939Snsouch		ppb_wecr(ppbus, *val);
55932178Smsmith		break;
56032178Smsmith	case PPISFIFO:			/* write FIFO */
56155939Snsouch		ppb_wfifo(ppbus, *val);
56232178Smsmith		break;
56343433Snsouch	case PPIGEPPA:			/* get EPP address bits */
56455939Snsouch		*val = ppb_repp_A(ppbus);
56543433Snsouch		break;
56643433Snsouch	case PPISEPPA:			/* set EPP address bits */
56755939Snsouch		ppb_wepp_A(ppbus, *val);
56843433Snsouch		break;
56932178Smsmith	default:
57032178Smsmith		error = ENOTTY;
57132178Smsmith		break;
57232178Smsmith	}
57332178Smsmith
57432178Smsmith	return (error);
57528219Smsmith}
57628219Smsmith
57755939SnsouchDRIVER_MODULE(ppi, ppbus, ppi_driver, ppi_devclass, 0, 0);
57855939Snsouch
57928257Smsmith#endif /* NPPI */
580