ppi.c revision 43433
128219Smsmith/*-
232178Smsmith * Copyright (c) 1997, 1998 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 *
2643433Snsouch *	$Id: ppi.c,v 1.10 1999/01/27 21:49:53 dillon Exp $
2728219Smsmith *
2828219Smsmith */
2928257Smsmith#include "ppi.h"
3028257Smsmith
3128257Smsmith#if NPPI > 0
3228257Smsmith
3328219Smsmith#include <sys/param.h>
3428219Smsmith#include <sys/systm.h>
3528219Smsmith#include <sys/conf.h>
3628219Smsmith#include <sys/kernel.h>
3742475Snsouch#include <sys/uio.h>
3828219Smsmith#include <sys/malloc.h>
3932178Smsmith#include <sys/fcntl.h>
4028219Smsmith
4142475Snsouch#include <machine/clock.h>
4242475Snsouch
4328219Smsmith#include <dev/ppbus/ppbconf.h>
4442475Snsouch#include <dev/ppbus/ppb_msq.h>
4542475Snsouch
4642475Snsouch#include "opt_ppb_1284.h"
4742475Snsouch
4842475Snsouch#ifdef PERIPH_1284
4942475Snsouch#include <dev/ppbus/ppb_1284.h>
5042475Snsouch#endif
5142475Snsouch
5232178Smsmith#include <dev/ppbus/ppi.h>
5328219Smsmith
5442475Snsouch#define BUFSIZE		512
5532178Smsmith
5628257Smsmithstruct ppi_data {
5728257Smsmith
5832178Smsmith    int		ppi_unit;
5932178Smsmith    int		ppi_flags;
6032178Smsmith#define HAVE_PPBUS	(1<<0)
6142475Snsouch#define HAD_PPBUS	(1<<1)
6228257Smsmith
6342475Snsouch    int		ppi_count;
6442475Snsouch    int		ppi_mode;			/* IEEE1284 mode */
6542475Snsouch    char	ppi_buffer[BUFSIZE];
6642475Snsouch
6732178Smsmith    struct ppb_device ppi_dev;
6828257Smsmith};
6928257Smsmith
7032178Smsmith#define MAXPPI		8			/* XXX not much better! */
7132178Smsmithstatic int 		nppi = 0;
7232178Smsmithstatic struct ppi_data	*ppidata[MAXPPI];
7328219Smsmith
7428219Smsmith/*
7528219Smsmith * Make ourselves visible as a ppbus driver
7628219Smsmith */
7728219Smsmith
7828219Smsmithstatic struct ppb_device	*ppiprobe(struct ppb_data *ppb);
7928219Smsmithstatic int			ppiattach(struct ppb_device *dev);
8028219Smsmithstatic void			ppiintr(int unit);
8128219Smsmith
8228219Smsmithstatic struct ppb_driver ppidriver = {
8328219Smsmith    ppiprobe, ppiattach, "ppi"
8428219Smsmith};
8528219SmsmithDATA_SET(ppbdriver_set, ppidriver);
8628219Smsmith
8728219Smsmithstatic	d_open_t	ppiopen;
8828219Smsmithstatic	d_close_t	ppiclose;
8928219Smsmithstatic	d_ioctl_t	ppiioctl;
9042475Snsouchstatic	d_write_t	ppiwrite;
9142475Snsouchstatic	d_read_t	ppiread;
9228219Smsmith
9328261Smsmith#define CDEV_MAJOR 82
9428219Smsmithstatic struct cdevsw ppi_cdevsw =
9542475Snsouch	{ ppiopen,	ppiclose,	ppiread,	ppiwrite,	/* 82 */
9628219Smsmith	  ppiioctl,	nullstop,	nullreset,	nodevtotty,
9728219Smsmith	  seltrue,	nommap,		nostrat,	"ppi",	NULL,	-1 };
9828219Smsmith
9942475Snsouch#ifdef PERIPH_1284
10042475Snsouch
10142475Snsouchstatic void
10242475Snsouchppi_enable_intr(struct ppi_data *ppi)
10342475Snsouch{
10442475Snsouch	char r;
10542475Snsouch
10642475Snsouch	r = ppb_rctr(&ppi->ppi_dev);
10742475Snsouch	ppb_wctr(&ppi->ppi_dev, r | IRQENABLE);
10842475Snsouch
10942475Snsouch	return;
11042475Snsouch}
11142475Snsouch
11242475Snsouchstatic void
11342475Snsouchppi_disable_intr(struct ppi_data *ppi)
11442475Snsouch{
11542475Snsouch	char r;
11642475Snsouch
11742475Snsouch	r = ppb_rctr(&ppi->ppi_dev);
11842475Snsouch	ppb_wctr(&ppi->ppi_dev, r & ~IRQENABLE);
11942475Snsouch
12042475Snsouch	return;
12142475Snsouch}
12242475Snsouch
12342475Snsouch#endif /* PERIPH_1284 */
12442475Snsouch
12528219Smsmith/*
12628219Smsmith * ppiprobe()
12728219Smsmith */
12828219Smsmithstatic struct ppb_device *
12928219Smsmithppiprobe(struct ppb_data *ppb)
13028219Smsmith{
13128219Smsmith	struct ppi_data *ppi;
13228219Smsmith
13328219Smsmith	ppi = (struct ppi_data *) malloc(sizeof(struct ppi_data),
13428219Smsmith							M_TEMP, M_NOWAIT);
13528219Smsmith	if (!ppi) {
13628219Smsmith		printf("ppi: cannot malloc!\n");
13728219Smsmith		return 0;
13828219Smsmith	}
13928219Smsmith	bzero(ppi, sizeof(struct ppi_data));
14028219Smsmith
14128219Smsmith	ppidata[nppi] = ppi;
14228219Smsmith
14328219Smsmith	/*
14428219Smsmith	 * ppi dependent initialisation.
14528219Smsmith	 */
14628219Smsmith	ppi->ppi_unit = nppi;
14728219Smsmith
14828219Smsmith	/*
14928219Smsmith	 * ppbus dependent initialisation.
15028219Smsmith	 */
15128219Smsmith	ppi->ppi_dev.id_unit = ppi->ppi_unit;
15228219Smsmith	ppi->ppi_dev.ppb = ppb;
15328219Smsmith	ppi->ppi_dev.intr = ppiintr;
15428219Smsmith
15528219Smsmith	/* Ok, go to next device on next probe */
15628219Smsmith	nppi ++;
15728219Smsmith
15828219Smsmith	return &ppi->ppi_dev;
15928219Smsmith}
16028219Smsmith
16128219Smsmithstatic int
16228219Smsmithppiattach(struct ppb_device *dev)
16328219Smsmith{
16428219Smsmith	/*
16528219Smsmith	 * Report ourselves
16628219Smsmith	 */
16728219Smsmith	printf("ppi%d: <generic parallel i/o> on ppbus %d\n",
16828219Smsmith	       dev->id_unit, dev->ppb->ppb_link->adapter_unit);
16928219Smsmith
17028219Smsmith	return (1);
17128219Smsmith}
17228219Smsmith
17342475Snsouch/*
17442475Snsouch * Cable
17542475Snsouch * -----
17642475Snsouch *
17742475Snsouch * Use an IEEE1284 compliant (DB25/DB25) cable with the following tricks:
17842475Snsouch *
17942475Snsouch * nStrobe   <-> nAck		1  <-> 10
18042475Snsouch * nAutofd   <-> Busy		11 <-> 14
18142475Snsouch * nSelectin <-> Select		17 <-> 13
18242475Snsouch * nInit     <-> nFault		15 <-> 16
18342475Snsouch *
18442475Snsouch */
18528219Smsmithstatic void
18628219Smsmithppiintr(int unit)
18728219Smsmith{
18842475Snsouch#ifdef PERIPH_1284
18942475Snsouch	struct ppi_data *ppi = ppidata[unit];
19042475Snsouch
19142475Snsouch	ppi_disable_intr(ppi);
19242475Snsouch
19342475Snsouch	switch (ppi->ppi_dev.ppb->state) {
19442475Snsouch
19542475Snsouch	/* accept IEEE1284 negociation then wakeup an waiting process to
19642475Snsouch	 * continue negociation at process level */
19742475Snsouch	case PPB_FORWARD_IDLE:
19842475Snsouch		/* Event 1 */
19942475Snsouch		if ((ppb_rstr(&ppi->ppi_dev) & (SELECT | nBUSY)) ==
20042475Snsouch							(SELECT | nBUSY)) {
20142475Snsouch			/* IEEE1284 negociation */
20242475Snsouch#ifdef DEBUG_1284
20342475Snsouch			printf("N");
20442475Snsouch#endif
20542475Snsouch
20642475Snsouch			/* Event 2 - prepare for reading the ext. value */
20742475Snsouch			ppb_wctr(&ppi->ppi_dev, (PCD | STROBE | nINIT) & ~SELECTIN);
20842475Snsouch
20942475Snsouch			ppi->ppi_dev.ppb->state = PPB_NEGOCIATION;
21042475Snsouch
21142475Snsouch		} else {
21242475Snsouch#ifdef DEBUG_1284
21342475Snsouch			printf("0x%x", ppb_rstr(&ppi->ppi_dev));
21442475Snsouch#endif
21542475Snsouch			ppb_peripheral_terminate(&ppi->ppi_dev, PPB_DONTWAIT);
21642475Snsouch			break;
21742475Snsouch		}
21842475Snsouch
21942475Snsouch		/* wake up any process waiting for negociation from
22042475Snsouch		 * remote master host */
22142475Snsouch
22242475Snsouch		/* XXX should set a variable to warn the process about
22342475Snsouch		 * the interrupt */
22442475Snsouch
22542475Snsouch		wakeup(ppi);
22642475Snsouch		break;
22742475Snsouch	default:
22842475Snsouch#ifdef DEBUG_1284
22942475Snsouch		printf("?%d", ppi->ppi_dev.ppb->state);
23042475Snsouch#endif
23142475Snsouch		ppi->ppi_dev.ppb->state = PPB_FORWARD_IDLE;
23242475Snsouch		ppb_set_mode(&ppi->ppi_dev, PPB_COMPATIBLE);
23342475Snsouch		break;
23442475Snsouch	}
23542475Snsouch
23642475Snsouch	ppi_enable_intr(ppi);
23742475Snsouch#endif /* PERIPH_1284 */
23842475Snsouch
23928219Smsmith	return;
24028219Smsmith}
24128219Smsmith
24228219Smsmithstatic int
24328219Smsmithppiopen(dev_t dev, int flags, int fmt, struct proc *p)
24428219Smsmith{
24528257Smsmith	u_int unit = minor(dev);
24632178Smsmith	struct ppi_data *ppi = ppidata[unit];
24732178Smsmith	int res;
24828257Smsmith
24928257Smsmith	if (unit >= nppi)
25028257Smsmith		return (ENXIO);
25128257Smsmith
25242475Snsouch	if (!(ppi->ppi_flags & HAVE_PPBUS)) {
25342475Snsouch		if ((res = ppb_request_bus(&ppi->ppi_dev,
25442475Snsouch			(flags & O_NONBLOCK) ? PPB_DONTWAIT :
25542475Snsouch						(PPB_WAIT | PPB_INTR))))
25632178Smsmith			return (res);
25728257Smsmith
25842475Snsouch		ppi->ppi_flags |= HAVE_PPBUS;
25942475Snsouch	}
26042475Snsouch	ppi->ppi_count += 1;
26142475Snsouch
26232178Smsmith	return (0);
26328219Smsmith}
26428219Smsmith
26528219Smsmithstatic int
26628219Smsmithppiclose(dev_t dev, int flags, int fmt, struct proc *p)
26728219Smsmith{
26832178Smsmith	u_int unit = minor(dev);
26932178Smsmith	struct ppi_data *ppi = ppidata[unit];
27032178Smsmith
27142475Snsouch	ppi->ppi_count --;
27242475Snsouch	if (!ppi->ppi_count) {
27342475Snsouch
27442475Snsouch#ifdef PERIPH_1284
27542475Snsouch		switch (ppi->ppi_dev.ppb->state) {
27642475Snsouch		case PPB_PERIPHERAL_IDLE:
27742475Snsouch			ppb_peripheral_terminate(&ppi->ppi_dev, 0);
27842475Snsouch			break;
27942475Snsouch		case PPB_REVERSE_IDLE:
28042475Snsouch		case PPB_EPP_IDLE:
28142475Snsouch		case PPB_ECP_FORWARD_IDLE:
28242475Snsouch		default:
28342475Snsouch			ppb_1284_terminate(&ppi->ppi_dev);
28442475Snsouch			break;
28542475Snsouch		}
28642475Snsouch#endif /* PERIPH_1284 */
28742475Snsouch
28832178Smsmith		ppb_release_bus(&ppi->ppi_dev);
28942475Snsouch		ppi->ppi_flags &= ~HAVE_PPBUS;
29042475Snsouch	}
29142475Snsouch
29232178Smsmith	return (0);
29328219Smsmith}
29428219Smsmith
29542475Snsouch/*
29642475Snsouch * ppiread()
29742475Snsouch *
29842475Snsouch * IEEE1284 compliant read.
29942475Snsouch *
30042475Snsouch * First, try negociation to BYTE then NIBBLE mode
30142475Snsouch * If no data is available, wait for it otherwise transfer as much as possible
30242475Snsouch */
30328219Smsmithstatic int
30442475Snsouchppiread(dev_t dev, struct uio *uio, int ioflag)
30542475Snsouch{
30642475Snsouch#ifdef PERIPH_1284
30742475Snsouch	u_int unit = minor(dev);
30842475Snsouch	struct ppi_data *ppi = ppidata[unit];
30942475Snsouch	int len, error = 0;
31042475Snsouch
31142475Snsouch	switch (ppi->ppi_dev.ppb->state) {
31242475Snsouch	case PPB_PERIPHERAL_IDLE:
31342475Snsouch		ppb_peripheral_terminate(&ppi->ppi_dev, 0);
31442475Snsouch		/* fall throught */
31542475Snsouch
31642475Snsouch	case PPB_FORWARD_IDLE:
31742475Snsouch		/* if can't negociate NIBBLE mode then try BYTE mode,
31842475Snsouch		 * the peripheral may be a computer
31942475Snsouch		 */
32042475Snsouch		if ((ppb_1284_negociate(&ppi->ppi_dev,
32142475Snsouch			ppi->ppi_mode = PPB_NIBBLE, 0))) {
32242475Snsouch
32342475Snsouch			/* XXX Wait 2 seconds to let the remote host some
32442475Snsouch			 * time to terminate its interrupt
32542475Snsouch			 */
32642475Snsouch			tsleep(ppi, PPBPRI, "ppiread", 2*hz);
32742475Snsouch
32842475Snsouch			if ((error = ppb_1284_negociate(&ppi->ppi_dev,
32942475Snsouch				ppi->ppi_mode = PPB_BYTE, 0)))
33042475Snsouch				return (error);
33142475Snsouch		}
33242475Snsouch		break;
33342475Snsouch
33442475Snsouch	case PPB_REVERSE_IDLE:
33542475Snsouch	case PPB_EPP_IDLE:
33642475Snsouch	case PPB_ECP_FORWARD_IDLE:
33742475Snsouch	default:
33842475Snsouch		break;
33942475Snsouch	}
34042475Snsouch
34142475Snsouch#ifdef DEBUG_1284
34242475Snsouch	printf("N");
34342475Snsouch#endif
34442475Snsouch	/* read data */
34542475Snsouch	len = 0;
34642475Snsouch	while (uio->uio_resid) {
34742475Snsouch		if ((error = ppb_1284_read(&ppi->ppi_dev, ppi->ppi_mode,
34842475Snsouch			ppi->ppi_buffer, min(BUFSIZE, uio->uio_resid),
34942475Snsouch			&len))) {
35042475Snsouch			goto error;
35142475Snsouch		}
35242475Snsouch
35342475Snsouch		if (!len)
35442475Snsouch			goto error;		/* no more data */
35542475Snsouch
35642475Snsouch#ifdef DEBUG_1284
35742475Snsouch		printf("d");
35842475Snsouch#endif
35942475Snsouch		if ((error = uiomove(ppi->ppi_buffer, len, uio)))
36042475Snsouch			goto error;
36142475Snsouch	}
36242475Snsouch
36342475Snsoucherror:
36442475Snsouch
36542475Snsouch#else /* PERIPH_1284 */
36642475Snsouch	int error = ENODEV;
36742475Snsouch#endif
36842475Snsouch
36942475Snsouch	return (error);
37042475Snsouch}
37142475Snsouch
37242475Snsouch/*
37342475Snsouch * ppiwrite()
37442475Snsouch *
37542475Snsouch * IEEE1284 compliant write
37642475Snsouch *
37742475Snsouch * Actually, this is the peripheral side of a remote IEEE1284 read
37842475Snsouch *
37942475Snsouch * The first part of the negociation (IEEE1284 device detection) is
38042475Snsouch * done at interrupt level, then the remaining is done by the writing
38142475Snsouch * process
38242475Snsouch *
38342475Snsouch * Once negociation done, transfer data
38442475Snsouch */
38542475Snsouchstatic int
38642475Snsouchppiwrite(dev_t dev, struct uio *uio, int ioflag)
38742475Snsouch{
38842475Snsouch#ifdef PERIPH_1284
38942475Snsouch	u_int unit = minor(dev);
39042475Snsouch	struct ppi_data *ppi = ppidata[unit];
39142475Snsouch	struct ppb_data *ppb = ppi->ppi_dev.ppb;
39242475Snsouch	int len, error = 0, sent;
39342475Snsouch
39442475Snsouch#if 0
39542475Snsouch	int ret;
39642475Snsouch
39742475Snsouch	#define ADDRESS		MS_PARAM(0, 0, MS_TYP_PTR)
39842475Snsouch	#define LENGTH		MS_PARAM(0, 1, MS_TYP_INT)
39942475Snsouch
40042475Snsouch	struct ppb_microseq msq[] = {
40142475Snsouch		  { MS_OP_PUT, { MS_UNKNOWN, MS_UNKNOWN, MS_UNKNOWN } },
40242475Snsouch		  MS_RET(0)
40342475Snsouch	};
40442475Snsouch
40542475Snsouch	/* negociate ECP mode */
40642475Snsouch	if (ppb_1284_negociate(&ppi->ppi_dev, PPB_ECP, 0)) {
40742475Snsouch		printf("ppiwrite: ECP negociation failed\n");
40842475Snsouch	}
40942475Snsouch
41042475Snsouch	while (!error && (len = min(uio->uio_resid, BUFSIZE))) {
41142475Snsouch		uiomove(ppi->ppi_buffer, len, uio);
41242475Snsouch
41342475Snsouch		ppb_MS_init_msq(msq, 2, ADDRESS, ppi->ppi_buffer, LENGTH, len);
41442475Snsouch
41542475Snsouch		error = ppb_MS_microseq(&ppi->ppi_dev, msq, &ret);
41642475Snsouch	}
41742475Snsouch#endif
41842475Snsouch
41942475Snsouch	/* we have to be peripheral to be able to send data, so
42042475Snsouch	 * wait for the appropriate state
42142475Snsouch	 */
42242475Snsouch	if (ppb->state < PPB_PERIPHERAL_NEGOCIATION)
42342475Snsouch		ppb_1284_terminate(&ppi->ppi_dev);
42442475Snsouch
42542475Snsouch	while (ppb->state != PPB_PERIPHERAL_IDLE) {
42642475Snsouch		/* XXX should check a variable before sleeping */
42742475Snsouch#ifdef DEBUG_1284
42842475Snsouch		printf("s");
42942475Snsouch#endif
43042475Snsouch
43142475Snsouch		ppi_enable_intr(ppi);
43242475Snsouch
43342475Snsouch		/* sleep until IEEE1284 negociation starts */
43442475Snsouch		error = tsleep(ppi, PCATCH | PPBPRI, "ppiwrite", 0);
43542475Snsouch
43642475Snsouch		switch (error) {
43742475Snsouch		case 0:
43842475Snsouch			/* negociate peripheral side with BYTE mode */
43942475Snsouch			ppb_peripheral_negociate(&ppi->ppi_dev, PPB_BYTE, 0);
44042475Snsouch			break;
44142475Snsouch		case EWOULDBLOCK:
44242475Snsouch			break;
44342475Snsouch		default:
44442475Snsouch			goto error;
44542475Snsouch		}
44642475Snsouch	}
44742475Snsouch#ifdef DEBUG_1284
44842475Snsouch	printf("N");
44942475Snsouch#endif
45042475Snsouch
45142475Snsouch	/* negociation done, write bytes to master host */
45243301Sdillon	while ((len = min(uio->uio_resid, BUFSIZE)) != 0) {
45342475Snsouch		uiomove(ppi->ppi_buffer, len, uio);
45442475Snsouch		if ((error = byte_peripheral_write(&ppi->ppi_dev,
45542475Snsouch						ppi->ppi_buffer, len, &sent)))
45642475Snsouch			goto error;
45742475Snsouch#ifdef DEBUG_1284
45842475Snsouch		printf("d");
45942475Snsouch#endif
46042475Snsouch	}
46142475Snsouch
46242475Snsoucherror:
46342475Snsouch
46442475Snsouch#else /* PERIPH_1284 */
46542475Snsouch	int error = ENODEV;
46642475Snsouch#endif
46742475Snsouch
46842475Snsouch	return (error);
46942475Snsouch}
47042475Snsouch
47142475Snsouchstatic int
47236735Sdfrppiioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
47328219Smsmith{
47432178Smsmith	u_int unit = minor(dev);
47532178Smsmith	struct ppi_data *ppi = ppidata[unit];
47632178Smsmith	int error = 0;
47732178Smsmith	u_int8_t *val = (u_int8_t *)data;
47832178Smsmith
47932178Smsmith	switch (cmd) {
48032178Smsmith
48132178Smsmith	case PPIGDATA:			/* get data register */
48232178Smsmith		*val = ppb_rdtr(&ppi->ppi_dev);
48332178Smsmith		break;
48432178Smsmith	case PPIGSTATUS:		/* get status bits */
48532178Smsmith		*val = ppb_rstr(&ppi->ppi_dev);
48632178Smsmith		break;
48732178Smsmith	case PPIGCTRL:			/* get control bits */
48832178Smsmith		*val = ppb_rctr(&ppi->ppi_dev);
48932178Smsmith		break;
49043433Snsouch	case PPIGEPPD:			/* get EPP data bits */
49143433Snsouch		*val = ppb_repp_D(&ppi->ppi_dev);
49232178Smsmith		break;
49332178Smsmith	case PPIGECR:			/* get ECP bits */
49432178Smsmith		*val = ppb_recr(&ppi->ppi_dev);
49532178Smsmith		break;
49632178Smsmith	case PPIGFIFO:			/* read FIFO */
49732178Smsmith		*val = ppb_rfifo(&ppi->ppi_dev);
49832178Smsmith		break;
49932178Smsmith
50032178Smsmith	case PPISDATA:			/* set data register */
50132178Smsmith		ppb_wdtr(&ppi->ppi_dev, *val);
50232178Smsmith		break;
50332178Smsmith	case PPISSTATUS:		/* set status bits */
50432178Smsmith		ppb_wstr(&ppi->ppi_dev, *val);
50532178Smsmith		break;
50632178Smsmith	case PPISCTRL:			/* set control bits */
50732178Smsmith		ppb_wctr(&ppi->ppi_dev, *val);
50832178Smsmith		break;
50943433Snsouch	case PPISEPPD:			/* set EPP data bits */
51043433Snsouch		ppb_wepp_D(&ppi->ppi_dev, *val);
51132178Smsmith		break;
51232178Smsmith	case PPISECR:			/* set ECP bits */
51332178Smsmith		ppb_wecr(&ppi->ppi_dev, *val);
51432178Smsmith		break;
51532178Smsmith	case PPISFIFO:			/* write FIFO */
51632178Smsmith		ppb_wfifo(&ppi->ppi_dev, *val);
51732178Smsmith		break;
51843433Snsouch
51943433Snsouch	case PPIGEPPA:			/* get EPP address bits */
52043433Snsouch		*val = ppb_repp_A(&ppi->ppi_dev);
52143433Snsouch		break;
52243433Snsouch	case PPISEPPA:			/* set EPP address bits */
52343433Snsouch		ppb_wepp_A(&ppi->ppi_dev, *val);
52443433Snsouch		break;
52532178Smsmith	default:
52632178Smsmith		error = ENOTTY;
52732178Smsmith		break;
52832178Smsmith	}
52932178Smsmith
53032178Smsmith	return (error);
53128219Smsmith}
53228219Smsmith
53328257Smsmith#ifdef PPI_MODULE
53428257Smsmith
53528257SmsmithMOD_DEV(ppi, LM_DT_CHAR, CDEV_MAJOR, &ppi_cdevsw);
53628257Smsmith
53728257Smsmithstatic int
53828257Smsmithppi_load(struct lkm_table *lkmtp, int cmd)
53928257Smsmith{
54028257Smsmith	struct ppb_data *ppb;
54128257Smsmith	struct ppb_device *dev;
54228257Smsmith	int i;
54328257Smsmith
54428257Smsmith	for (ppb = ppb_next_bus(NULL); ppb; ppb = ppb_next_bus(ppb)) {
54528257Smsmith
54628257Smsmith		dev = ppiprobe(ppb);
54728257Smsmith		ppiattach(dev);
54828257Smsmith
54928257Smsmith		ppb_attach_device(dev);
55028257Smsmith	}
55128257Smsmith
55228257Smsmith	return (0);
55328257Smsmith}
55428257Smsmith
55528257Smsmithstatic int
55628257Smsmithppi_unload(struct lkm_table *lkmtp, int cmd)
55728257Smsmith{
55828257Smsmith	int i;
55928257Smsmith
56028257Smsmith	for (i = nppi-1; i > 0; i--) {
56128257Smsmith		ppb_remove_device(&ppidata[i]->ppi_dev);
56228257Smsmith		free(ppidata[i], M_TEMP);
56328257Smsmith	}
56428257Smsmith
56528257Smsmith	return (0);
56628257Smsmith}
56728257Smsmith
56828257Smsmithint
56928257Smsmithppi_mod(struct lkm_table *lkmtp, int cmd, int ver)
57028257Smsmith{
57128257Smsmith	DISPATCH(lkmtp, cmd, ver, ppi_load, ppi_unload, lkm_nullcmd);
57228257Smsmith}
57328257Smsmith
57428257Smsmith#endif /* PPI_MODULE */
57528257Smsmith
57628219Smsmithstatic ppi_devsw_installed = 0;
57728219Smsmith
57828257Smsmithstatic void ppi_drvinit(void *unused)
57928219Smsmith{
58028219Smsmith	dev_t dev;
58128219Smsmith
58228257Smsmith	if (!ppi_devsw_installed ) {
58328219Smsmith		dev = makedev(CDEV_MAJOR, 0);
58428219Smsmith		cdevsw_add(&dev, &ppi_cdevsw, NULL);
58528219Smsmith		ppi_devsw_installed = 1;
58628219Smsmith    	}
58728219Smsmith}
58828219Smsmith
58928257SmsmithSYSINIT(ppidev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,ppi_drvinit,NULL)
59028257Smsmith
59128257Smsmith#endif /* NPPI */
592