ppi.c revision 47625
1178825Sdfr/*-
2178825Sdfr * Copyright (c) 1997, 1998 Nicolas Souchu, Michael Smith
3178825Sdfr * All rights reserved.
4178825Sdfr *
5178825Sdfr * Redistribution and use in source and binary forms, with or without
6178825Sdfr * modification, are permitted provided that the following conditions
7178825Sdfr * are met:
8178825Sdfr * 1. Redistributions of source code must retain the above copyright
9178825Sdfr *    notice, this list of conditions and the following disclaimer.
10178825Sdfr * 2. Redistributions in binary form must reproduce the above copyright
11178825Sdfr *    notice, this list of conditions and the following disclaimer in the
12178825Sdfr *    documentation and/or other materials provided with the distribution.
13178825Sdfr *
14178825Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15178825Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16178825Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17178825Sdfr * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18178825Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19178825Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20178825Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21178825Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22178825Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23178825Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24178825Sdfr * SUCH DAMAGE.
25178825Sdfr *
26178825Sdfr *	$Id: ppi.c,v 1.13 1999/04/28 10:51:39 dt Exp $
27178825Sdfr *
28178825Sdfr */
29178825Sdfr#include "ppi.h"
30178825Sdfr
31178825Sdfr#if NPPI > 0
32178825Sdfr
33178825Sdfr#include <sys/param.h>
34178825Sdfr#include <sys/systm.h>
35178825Sdfr#include <sys/conf.h>
36178825Sdfr#include <sys/kernel.h>
37178825Sdfr#include <sys/uio.h>
38178825Sdfr#include <sys/malloc.h>
39178825Sdfr#include <sys/fcntl.h>
40178825Sdfr
41178825Sdfr#include <machine/clock.h>
42178825Sdfr
43178825Sdfr#include <dev/ppbus/ppbconf.h>
44178825Sdfr#include <dev/ppbus/ppb_msq.h>
45178825Sdfr
46178825Sdfr#include "opt_ppb_1284.h"
47178825Sdfr
48178825Sdfr#ifdef PERIPH_1284
49178825Sdfr#include <dev/ppbus/ppb_1284.h>
50178825Sdfr#endif
51178825Sdfr
52178825Sdfr#include <dev/ppbus/ppi.h>
53178825Sdfr
54178825Sdfr#define BUFSIZE		512
55178825Sdfr
56178825Sdfrstruct ppi_data {
57178825Sdfr
58178825Sdfr    int		ppi_unit;
59178825Sdfr    int		ppi_flags;
60178825Sdfr#define HAVE_PPBUS	(1<<0)
61178825Sdfr#define HAD_PPBUS	(1<<1)
62178825Sdfr
63178825Sdfr    int		ppi_count;
64178825Sdfr    int		ppi_mode;			/* IEEE1284 mode */
65178825Sdfr    char	ppi_buffer[BUFSIZE];
66178825Sdfr
67178825Sdfr    struct ppb_device ppi_dev;
68178825Sdfr};
69178825Sdfr
70178825Sdfr#define MAXPPI		8			/* XXX not much better! */
71178825Sdfrstatic int 		nppi = 0;
72178825Sdfrstatic struct ppi_data	*ppidata[MAXPPI];
73178825Sdfr
74178825Sdfr/*
75178825Sdfr * Make ourselves visible as a ppbus driver
76178825Sdfr */
77178825Sdfr
78178825Sdfrstatic struct ppb_device	*ppiprobe(struct ppb_data *ppb);
79178825Sdfrstatic int			ppiattach(struct ppb_device *dev);
80178825Sdfrstatic void			ppiintr(int unit);
81178825Sdfr
82178825Sdfrstatic struct ppb_driver ppidriver = {
83178825Sdfr    ppiprobe, ppiattach, "ppi"
84178825Sdfr};
85178825SdfrDATA_SET(ppbdriver_set, ppidriver);
86178825Sdfr
87178825Sdfrstatic	d_open_t	ppiopen;
88178825Sdfrstatic	d_close_t	ppiclose;
89178825Sdfrstatic	d_ioctl_t	ppiioctl;
90178825Sdfrstatic	d_write_t	ppiwrite;
91178825Sdfrstatic	d_read_t	ppiread;
92178825Sdfr
93178825Sdfr#define CDEV_MAJOR 82
94178825Sdfrstatic struct cdevsw ppi_cdevsw = {
95178825Sdfr	/* open */	ppiopen,
96178825Sdfr	/* close */	ppiclose,
97178825Sdfr	/* read */	ppiread,
98178825Sdfr	/* write */	ppiwrite,
99178825Sdfr	/* ioctl */	ppiioctl,
100178825Sdfr	/* stop */	nostop,
101178825Sdfr	/* reset */	noreset,
102178825Sdfr	/* devtotty */	nodevtotty,
103178825Sdfr	/* poll */	nopoll,
104178825Sdfr	/* mmap */	nommap,
105178825Sdfr	/* strategy */	nostrategy,
106178825Sdfr	/* name */	"ppi",
107178825Sdfr	/* parms */	noparms,
108178825Sdfr	/* maj */	CDEV_MAJOR,
109178825Sdfr	/* dump */	nodump,
110178825Sdfr	/* psize */	nopsize,
111178825Sdfr	/* flags */	0,
112178825Sdfr	/* maxio */	0,
113178825Sdfr	/* bmaj */	-1
114178825Sdfr};
115178825Sdfr
116178825Sdfr#ifdef PERIPH_1284
117178825Sdfr
118178825Sdfrstatic void
119178825Sdfrppi_enable_intr(struct ppi_data *ppi)
120178825Sdfr{
121178825Sdfr	char r;
122178825Sdfr
123178825Sdfr	r = ppb_rctr(&ppi->ppi_dev);
124178825Sdfr	ppb_wctr(&ppi->ppi_dev, r | IRQENABLE);
125178825Sdfr
126178825Sdfr	return;
127178825Sdfr}
128178825Sdfr
129178825Sdfrstatic void
130178825Sdfrppi_disable_intr(struct ppi_data *ppi)
131178825Sdfr{
132178825Sdfr	char r;
133178825Sdfr
134178825Sdfr	r = ppb_rctr(&ppi->ppi_dev);
135178825Sdfr	ppb_wctr(&ppi->ppi_dev, r & ~IRQENABLE);
136178825Sdfr
137178825Sdfr	return;
138178825Sdfr}
139178825Sdfr
140178825Sdfr#endif /* PERIPH_1284 */
141178825Sdfr
142178825Sdfr/*
143178825Sdfr * ppiprobe()
144178825Sdfr */
145178825Sdfrstatic struct ppb_device *
146178825Sdfrppiprobe(struct ppb_data *ppb)
147178825Sdfr{
148178825Sdfr	struct ppi_data *ppi;
149178825Sdfr
150178825Sdfr	ppi = (struct ppi_data *) malloc(sizeof(struct ppi_data),
151178825Sdfr							M_TEMP, M_NOWAIT);
152201444Sbrooks	if (!ppi) {
153178825Sdfr		printf("ppi: cannot malloc!\n");
154178825Sdfr		return 0;
155178825Sdfr	}
156178825Sdfr	bzero(ppi, sizeof(struct ppi_data));
157178825Sdfr
158178825Sdfr	ppidata[nppi] = ppi;
159178825Sdfr
160178825Sdfr	/*
161178825Sdfr	 * ppi dependent initialisation.
162178825Sdfr	 */
163178825Sdfr	ppi->ppi_unit = nppi;
164178825Sdfr
165178825Sdfr	/*
166178825Sdfr	 * ppbus dependent initialisation.
167178825Sdfr	 */
168178825Sdfr	ppi->ppi_dev.id_unit = ppi->ppi_unit;
169178825Sdfr	ppi->ppi_dev.ppb = ppb;
170178825Sdfr	ppi->ppi_dev.intr = ppiintr;
171178825Sdfr
172178825Sdfr	/* Ok, go to next device on next probe */
173178825Sdfr	nppi ++;
174178825Sdfr
175178825Sdfr	return &ppi->ppi_dev;
176178825Sdfr}
177178825Sdfr
178178825Sdfrstatic int
179178825Sdfrppiattach(struct ppb_device *dev)
180178825Sdfr{
181178825Sdfr	/*
182178825Sdfr	 * Report ourselves
183178825Sdfr	 */
184178825Sdfr	printf("ppi%d: <generic parallel i/o> on ppbus %d\n",
185178825Sdfr	       dev->id_unit, dev->ppb->ppb_link->adapter_unit);
186178825Sdfr
187178825Sdfr	return (1);
188178825Sdfr}
189178825Sdfr
190178825Sdfr/*
191178825Sdfr * Cable
192178825Sdfr * -----
193178825Sdfr *
194178825Sdfr * Use an IEEE1284 compliant (DB25/DB25) cable with the following tricks:
195178825Sdfr *
196178825Sdfr * nStrobe   <-> nAck		1  <-> 10
197178825Sdfr * nAutofd   <-> Busy		11 <-> 14
198178825Sdfr * nSelectin <-> Select		17 <-> 13
199178825Sdfr * nInit     <-> nFault		15 <-> 16
200178825Sdfr *
201178825Sdfr */
202178825Sdfrstatic void
203178825Sdfrppiintr(int unit)
204178825Sdfr{
205178825Sdfr#ifdef PERIPH_1284
206178825Sdfr	struct ppi_data *ppi = ppidata[unit];
207178825Sdfr
208178825Sdfr	ppi_disable_intr(ppi);
209178825Sdfr
210178825Sdfr	switch (ppi->ppi_dev.ppb->state) {
211178825Sdfr
212178825Sdfr	/* accept IEEE1284 negociation then wakeup an waiting process to
213178825Sdfr	 * continue negociation at process level */
214178825Sdfr	case PPB_FORWARD_IDLE:
215178825Sdfr		/* Event 1 */
216178825Sdfr		if ((ppb_rstr(&ppi->ppi_dev) & (SELECT | nBUSY)) ==
217178825Sdfr							(SELECT | nBUSY)) {
218178825Sdfr			/* IEEE1284 negociation */
219178825Sdfr#ifdef DEBUG_1284
220178825Sdfr			printf("N");
221178825Sdfr#endif
222178825Sdfr
223178825Sdfr			/* Event 2 - prepare for reading the ext. value */
224178825Sdfr			ppb_wctr(&ppi->ppi_dev, (PCD | STROBE | nINIT) & ~SELECTIN);
225178825Sdfr
226178825Sdfr			ppi->ppi_dev.ppb->state = PPB_NEGOCIATION;
227178825Sdfr
228178825Sdfr		} else {
229178825Sdfr#ifdef DEBUG_1284
230178825Sdfr			printf("0x%x", ppb_rstr(&ppi->ppi_dev));
231178825Sdfr#endif
232178825Sdfr			ppb_peripheral_terminate(&ppi->ppi_dev, PPB_DONTWAIT);
233178825Sdfr			break;
234178825Sdfr		}
235178825Sdfr
236178825Sdfr		/* wake up any process waiting for negociation from
237178825Sdfr		 * remote master host */
238178825Sdfr
239178825Sdfr		/* XXX should set a variable to warn the process about
240178825Sdfr		 * the interrupt */
241178825Sdfr
242178825Sdfr		wakeup(ppi);
243178825Sdfr		break;
244178825Sdfr	default:
245178825Sdfr#ifdef DEBUG_1284
246178825Sdfr		printf("?%d", ppi->ppi_dev.ppb->state);
247178825Sdfr#endif
248178825Sdfr		ppi->ppi_dev.ppb->state = PPB_FORWARD_IDLE;
249178825Sdfr		ppb_set_mode(&ppi->ppi_dev, PPB_COMPATIBLE);
250178825Sdfr		break;
251178825Sdfr	}
252178825Sdfr
253178825Sdfr	ppi_enable_intr(ppi);
254178825Sdfr#endif /* PERIPH_1284 */
255178825Sdfr
256178825Sdfr	return;
257178825Sdfr}
258178825Sdfr
259178825Sdfrstatic int
260178825Sdfrppiopen(dev_t dev, int flags, int fmt, struct proc *p)
261178825Sdfr{
262178825Sdfr	u_int unit = minor(dev);
263178825Sdfr	struct ppi_data *ppi = ppidata[unit];
264178825Sdfr	int res;
265178825Sdfr
266178825Sdfr	if (unit >= nppi)
267178825Sdfr		return (ENXIO);
268178825Sdfr
269178825Sdfr	if (!(ppi->ppi_flags & HAVE_PPBUS)) {
270178825Sdfr		if ((res = ppb_request_bus(&ppi->ppi_dev,
271178825Sdfr			(flags & O_NONBLOCK) ? PPB_DONTWAIT :
272178825Sdfr						(PPB_WAIT | PPB_INTR))))
273178825Sdfr			return (res);
274178825Sdfr
275178825Sdfr		ppi->ppi_flags |= HAVE_PPBUS;
276178825Sdfr	}
277178825Sdfr	ppi->ppi_count += 1;
278178825Sdfr
279178825Sdfr	return (0);
280178825Sdfr}
281178825Sdfr
282178825Sdfrstatic int
283178825Sdfrppiclose(dev_t dev, int flags, int fmt, struct proc *p)
284178825Sdfr{
285178825Sdfr	u_int unit = minor(dev);
286178825Sdfr	struct ppi_data *ppi = ppidata[unit];
287178825Sdfr
288178825Sdfr	ppi->ppi_count --;
289178825Sdfr	if (!ppi->ppi_count) {
290178825Sdfr
291178825Sdfr#ifdef PERIPH_1284
292178825Sdfr		switch (ppi->ppi_dev.ppb->state) {
293178825Sdfr		case PPB_PERIPHERAL_IDLE:
294178825Sdfr			ppb_peripheral_terminate(&ppi->ppi_dev, 0);
295178825Sdfr			break;
296178825Sdfr		case PPB_REVERSE_IDLE:
297178825Sdfr		case PPB_EPP_IDLE:
298178825Sdfr		case PPB_ECP_FORWARD_IDLE:
299178825Sdfr		default:
300178825Sdfr			ppb_1284_terminate(&ppi->ppi_dev);
301178825Sdfr			break;
302178825Sdfr		}
303178825Sdfr#endif /* PERIPH_1284 */
304178825Sdfr
305178825Sdfr		ppb_release_bus(&ppi->ppi_dev);
306178825Sdfr		ppi->ppi_flags &= ~HAVE_PPBUS;
307178825Sdfr	}
308178825Sdfr
309178825Sdfr	return (0);
310178825Sdfr}
311178825Sdfr
312178825Sdfr/*
313178825Sdfr * ppiread()
314178825Sdfr *
315178825Sdfr * IEEE1284 compliant read.
316178825Sdfr *
317178825Sdfr * First, try negociation to BYTE then NIBBLE mode
318178825Sdfr * If no data is available, wait for it otherwise transfer as much as possible
319178825Sdfr */
320178825Sdfrstatic int
321178825Sdfrppiread(dev_t dev, struct uio *uio, int ioflag)
322178825Sdfr{
323178825Sdfr#ifdef PERIPH_1284
324178825Sdfr	u_int unit = minor(dev);
325178825Sdfr	struct ppi_data *ppi = ppidata[unit];
326178825Sdfr	int len, error = 0;
327178825Sdfr
328178825Sdfr	switch (ppi->ppi_dev.ppb->state) {
329178825Sdfr	case PPB_PERIPHERAL_IDLE:
330178825Sdfr		ppb_peripheral_terminate(&ppi->ppi_dev, 0);
331178825Sdfr		/* fall throught */
332178825Sdfr
333178825Sdfr	case PPB_FORWARD_IDLE:
334178825Sdfr		/* if can't negociate NIBBLE mode then try BYTE mode,
335178825Sdfr		 * the peripheral may be a computer
336178825Sdfr		 */
337178825Sdfr		if ((ppb_1284_negociate(&ppi->ppi_dev,
338178825Sdfr			ppi->ppi_mode = PPB_NIBBLE, 0))) {
339178825Sdfr
340178825Sdfr			/* XXX Wait 2 seconds to let the remote host some
341178825Sdfr			 * time to terminate its interrupt
342178825Sdfr			 */
343178825Sdfr			tsleep(ppi, PPBPRI, "ppiread", 2*hz);
344178825Sdfr
345178825Sdfr			if ((error = ppb_1284_negociate(&ppi->ppi_dev,
346178825Sdfr				ppi->ppi_mode = PPB_BYTE, 0)))
347178825Sdfr				return (error);
348178825Sdfr		}
349178825Sdfr		break;
350178825Sdfr
351178825Sdfr	case PPB_REVERSE_IDLE:
352178825Sdfr	case PPB_EPP_IDLE:
353178825Sdfr	case PPB_ECP_FORWARD_IDLE:
354178825Sdfr	default:
355178825Sdfr		break;
356178825Sdfr	}
357178825Sdfr
358178825Sdfr#ifdef DEBUG_1284
359178825Sdfr	printf("N");
360178825Sdfr#endif
361178825Sdfr	/* read data */
362178825Sdfr	len = 0;
363178825Sdfr	while (uio->uio_resid) {
364178825Sdfr		if ((error = ppb_1284_read(&ppi->ppi_dev, ppi->ppi_mode,
365178825Sdfr			ppi->ppi_buffer, min(BUFSIZE, uio->uio_resid),
366178825Sdfr			&len))) {
367178825Sdfr			goto error;
368178825Sdfr		}
369178825Sdfr
370178825Sdfr		if (!len)
371178825Sdfr			goto error;		/* no more data */
372178825Sdfr
373178825Sdfr#ifdef DEBUG_1284
374178825Sdfr		printf("d");
375178825Sdfr#endif
376178825Sdfr		if ((error = uiomove(ppi->ppi_buffer, len, uio)))
377178825Sdfr			goto error;
378178825Sdfr	}
379178825Sdfr
380178825Sdfrerror:
381178825Sdfr
382178825Sdfr#else /* PERIPH_1284 */
383178825Sdfr	int error = ENODEV;
384178825Sdfr#endif
385178825Sdfr
386178825Sdfr	return (error);
387178825Sdfr}
388178825Sdfr
389178825Sdfr/*
390178825Sdfr * ppiwrite()
391178825Sdfr *
392178825Sdfr * IEEE1284 compliant write
393178825Sdfr *
394178825Sdfr * Actually, this is the peripheral side of a remote IEEE1284 read
395178825Sdfr *
396178825Sdfr * The first part of the negociation (IEEE1284 device detection) is
397178825Sdfr * done at interrupt level, then the remaining is done by the writing
398178825Sdfr * process
399178825Sdfr *
400178825Sdfr * Once negociation done, transfer data
401178825Sdfr */
402178825Sdfrstatic int
403178825Sdfrppiwrite(dev_t dev, struct uio *uio, int ioflag)
404178825Sdfr{
405178825Sdfr#ifdef PERIPH_1284
406178825Sdfr	u_int unit = minor(dev);
407178825Sdfr	struct ppi_data *ppi = ppidata[unit];
408178825Sdfr	struct ppb_data *ppb = ppi->ppi_dev.ppb;
409178825Sdfr	int len, error = 0, sent;
410178825Sdfr
411178825Sdfr#if 0
412178825Sdfr	int ret;
413178825Sdfr
414178825Sdfr	#define ADDRESS		MS_PARAM(0, 0, MS_TYP_PTR)
415178825Sdfr	#define LENGTH		MS_PARAM(0, 1, MS_TYP_INT)
416178825Sdfr
417178825Sdfr	struct ppb_microseq msq[] = {
418178825Sdfr		  { MS_OP_PUT, { MS_UNKNOWN, MS_UNKNOWN, MS_UNKNOWN } },
419178825Sdfr		  MS_RET(0)
420178825Sdfr	};
421178825Sdfr
422178825Sdfr	/* negociate ECP mode */
423178825Sdfr	if (ppb_1284_negociate(&ppi->ppi_dev, PPB_ECP, 0)) {
424178825Sdfr		printf("ppiwrite: ECP negociation failed\n");
425178825Sdfr	}
426178825Sdfr
427178825Sdfr	while (!error && (len = min(uio->uio_resid, BUFSIZE))) {
428178825Sdfr		uiomove(ppi->ppi_buffer, len, uio);
429178825Sdfr
430178825Sdfr		ppb_MS_init_msq(msq, 2, ADDRESS, ppi->ppi_buffer, LENGTH, len);
431178825Sdfr
432178825Sdfr		error = ppb_MS_microseq(&ppi->ppi_dev, msq, &ret);
433178825Sdfr	}
434178825Sdfr#endif
435178825Sdfr
436178825Sdfr	/* we have to be peripheral to be able to send data, so
437178825Sdfr	 * wait for the appropriate state
438178825Sdfr	 */
439178825Sdfr	if (ppb->state < PPB_PERIPHERAL_NEGOCIATION)
440178825Sdfr		ppb_1284_terminate(&ppi->ppi_dev);
441178825Sdfr
442178825Sdfr	while (ppb->state != PPB_PERIPHERAL_IDLE) {
443178825Sdfr		/* XXX should check a variable before sleeping */
444178825Sdfr#ifdef DEBUG_1284
445178825Sdfr		printf("s");
446178825Sdfr#endif
447178825Sdfr
448178825Sdfr		ppi_enable_intr(ppi);
449178825Sdfr
450178825Sdfr		/* sleep until IEEE1284 negociation starts */
451178825Sdfr		error = tsleep(ppi, PCATCH | PPBPRI, "ppiwrite", 0);
452178825Sdfr
453178825Sdfr		switch (error) {
454178825Sdfr		case 0:
455178825Sdfr			/* negociate peripheral side with BYTE mode */
456178825Sdfr			ppb_peripheral_negociate(&ppi->ppi_dev, PPB_BYTE, 0);
457178825Sdfr			break;
458178825Sdfr		case EWOULDBLOCK:
459178825Sdfr			break;
460178825Sdfr		default:
461178825Sdfr			goto error;
462178825Sdfr		}
463178825Sdfr	}
464178825Sdfr#ifdef DEBUG_1284
465178825Sdfr	printf("N");
466178825Sdfr#endif
467178825Sdfr
468178825Sdfr	/* negociation done, write bytes to master host */
469178825Sdfr	while ((len = min(uio->uio_resid, BUFSIZE)) != 0) {
470178825Sdfr		uiomove(ppi->ppi_buffer, len, uio);
471178825Sdfr		if ((error = byte_peripheral_write(&ppi->ppi_dev,
472178825Sdfr						ppi->ppi_buffer, len, &sent)))
473178825Sdfr			goto error;
474178825Sdfr#ifdef DEBUG_1284
475178825Sdfr		printf("d");
476178825Sdfr#endif
477178825Sdfr	}
478178825Sdfr
479178825Sdfrerror:
480178825Sdfr
481178825Sdfr#else /* PERIPH_1284 */
482178825Sdfr	int error = ENODEV;
483178825Sdfr#endif
484178825Sdfr
485178825Sdfr	return (error);
486178825Sdfr}
487178825Sdfr
488178825Sdfrstatic int
489178825Sdfrppiioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
490178825Sdfr{
491178825Sdfr	u_int unit = minor(dev);
492178825Sdfr	struct ppi_data *ppi = ppidata[unit];
493178825Sdfr	int error = 0;
494178825Sdfr	u_int8_t *val = (u_int8_t *)data;
495178825Sdfr
496178825Sdfr	switch (cmd) {
497178825Sdfr
498178825Sdfr	case PPIGDATA:			/* get data register */
499178825Sdfr		*val = ppb_rdtr(&ppi->ppi_dev);
500178825Sdfr		break;
501178825Sdfr	case PPIGSTATUS:		/* get status bits */
502178825Sdfr		*val = ppb_rstr(&ppi->ppi_dev);
503178825Sdfr		break;
504178825Sdfr	case PPIGCTRL:			/* get control bits */
505178825Sdfr		*val = ppb_rctr(&ppi->ppi_dev);
506178825Sdfr		break;
507178825Sdfr	case PPIGEPPD:			/* get EPP data bits */
508178825Sdfr		*val = ppb_repp_D(&ppi->ppi_dev);
509178825Sdfr		break;
510178825Sdfr	case PPIGECR:			/* get ECP bits */
511178825Sdfr		*val = ppb_recr(&ppi->ppi_dev);
512178825Sdfr		break;
513178825Sdfr	case PPIGFIFO:			/* read FIFO */
514178825Sdfr		*val = ppb_rfifo(&ppi->ppi_dev);
515178825Sdfr		break;
516178825Sdfr
517178825Sdfr	case PPISDATA:			/* set data register */
518178825Sdfr		ppb_wdtr(&ppi->ppi_dev, *val);
519178825Sdfr		break;
520178825Sdfr	case PPISSTATUS:		/* set status bits */
521178825Sdfr		ppb_wstr(&ppi->ppi_dev, *val);
522178825Sdfr		break;
523178825Sdfr	case PPISCTRL:			/* set control bits */
524178825Sdfr		ppb_wctr(&ppi->ppi_dev, *val);
525178825Sdfr		break;
526178825Sdfr	case PPISEPPD:			/* set EPP data bits */
527178825Sdfr		ppb_wepp_D(&ppi->ppi_dev, *val);
528178825Sdfr		break;
529178825Sdfr	case PPISECR:			/* set ECP bits */
530178825Sdfr		ppb_wecr(&ppi->ppi_dev, *val);
531178825Sdfr		break;
532178825Sdfr	case PPISFIFO:			/* write FIFO */
533178825Sdfr		ppb_wfifo(&ppi->ppi_dev, *val);
534178825Sdfr		break;
535178825Sdfr
536178825Sdfr	case PPIGEPPA:			/* get EPP address bits */
537178825Sdfr		*val = ppb_repp_A(&ppi->ppi_dev);
538178825Sdfr		break;
539178825Sdfr	case PPISEPPA:			/* set EPP address bits */
540178825Sdfr		ppb_wepp_A(&ppi->ppi_dev, *val);
541178825Sdfr		break;
542178825Sdfr	default:
543178825Sdfr		error = ENOTTY;
544178825Sdfr		break;
545178825Sdfr	}
546178825Sdfr
547178825Sdfr	return (error);
548178825Sdfr}
549178825Sdfr
550178825Sdfrstatic int ppi_devsw_installed;
551178825Sdfr
552178825Sdfrstatic void ppi_drvinit(void *unused)
553178825Sdfr{
554178825Sdfr	dev_t dev;
555178825Sdfr
556178825Sdfr	if (!ppi_devsw_installed ) {
557178825Sdfr		dev = makedev(CDEV_MAJOR, 0);
558178825Sdfr		cdevsw_add(&dev, &ppi_cdevsw, NULL);
559178825Sdfr		ppi_devsw_installed = 1;
560178825Sdfr    	}
561178825Sdfr}
562178825Sdfr
563178825SdfrSYSINIT(ppidev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,ppi_drvinit,NULL)
564178825Sdfr
565178825Sdfr#endif /* NPPI */
566178825Sdfr