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 *
2628219Smsmith *
2728219Smsmith */
28119418Sobrien
29119418Sobrien#include <sys/cdefs.h>
30119418Sobrien__FBSDID("$FreeBSD$");
3155939Snsouch#include "opt_ppb_1284.h"
3255939Snsouch
3328219Smsmith#include <sys/param.h>
3428219Smsmith#include <sys/systm.h>
3555939Snsouch#include <sys/module.h>
3655939Snsouch#include <sys/bus.h>
3728219Smsmith#include <sys/conf.h>
3828219Smsmith#include <sys/kernel.h>
39187576Sjhb#include <sys/lock.h>
40187576Sjhb#include <sys/sx.h>
4142475Snsouch#include <sys/uio.h>
4232178Smsmith#include <sys/fcntl.h>
4328219Smsmith
4455939Snsouch#include <machine/bus.h>
4555939Snsouch#include <machine/resource.h>
4655939Snsouch#include <sys/rman.h>
4742475Snsouch
4828219Smsmith#include <dev/ppbus/ppbconf.h>
4942475Snsouch#include <dev/ppbus/ppb_msq.h>
5042475Snsouch
5142475Snsouch#ifdef PERIPH_1284
52187576Sjhb#include <sys/malloc.h>
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 {
65184130Sjhb    device_t	ppi_device;
66184130Sjhb    struct cdev *ppi_cdev;
67187576Sjhb    struct sx	ppi_lock;
6832178Smsmith    int		ppi_flags;
6932178Smsmith#define HAVE_PPBUS	(1<<0)
7028257Smsmith
7142475Snsouch    int		ppi_mode;			/* IEEE1284 mode */
7242475Snsouch    char	ppi_buffer[BUFSIZE];
7342475Snsouch
7460194Sn_hibma#ifdef PERIPH_1284
7555939Snsouch    struct resource *intr_resource;	/* interrupt resource */
7655939Snsouch    void *intr_cookie;			/* interrupt registration cookie */
7760194Sn_hibma#endif /* PERIPH_1284 */
7828257Smsmith};
7928257Smsmith
8055939Snsouch#define DEVTOSOFTC(dev) \
8155939Snsouch	((struct ppi_data *)device_get_softc(dev))
8228219Smsmith
8355939Snsouchstatic devclass_t ppi_devclass;
8428219Smsmith
85187576Sjhb#ifdef PERIPH_1284
86187576Sjhbstatic void	ppiintr(void *arg);
87187576Sjhb#endif
88187576Sjhb
8928219Smsmithstatic	d_open_t	ppiopen;
9028219Smsmithstatic	d_close_t	ppiclose;
9128219Smsmithstatic	d_ioctl_t	ppiioctl;
9242475Snsouchstatic	d_write_t	ppiwrite;
9342475Snsouchstatic	d_read_t	ppiread;
9428219Smsmith
9547625Sphkstatic struct cdevsw ppi_cdevsw = {
96126080Sphk	.d_version =	D_VERSION,
97111815Sphk	.d_open =	ppiopen,
98111815Sphk	.d_close =	ppiclose,
99111815Sphk	.d_read =	ppiread,
100111815Sphk	.d_write =	ppiwrite,
101111815Sphk	.d_ioctl =	ppiioctl,
102111815Sphk	.d_name =	"ppi",
10347625Sphk};
10428219Smsmith
10542475Snsouch#ifdef PERIPH_1284
10642475Snsouch
10742475Snsouchstatic void
10855939Snsouchppi_enable_intr(device_t ppidev)
10942475Snsouch{
11042475Snsouch	char r;
11155939Snsouch	device_t ppbus = device_get_parent(ppidev);
11242475Snsouch
11355939Snsouch	r = ppb_rctr(ppbus);
11455939Snsouch	ppb_wctr(ppbus, r | IRQENABLE);
11542475Snsouch
11642475Snsouch	return;
11742475Snsouch}
11842475Snsouch
11942475Snsouchstatic void
12055939Snsouchppi_disable_intr(device_t ppidev)
12142475Snsouch{
12242475Snsouch	char r;
123185003Sjhb	device_t ppbus = device_get_parent(ppidev);
12442475Snsouch
12555939Snsouch	r = ppb_rctr(ppbus);
12655939Snsouch	ppb_wctr(ppbus, r & ~IRQENABLE);
12742475Snsouch
12842475Snsouch	return;
12942475Snsouch}
13042475Snsouch
13142475Snsouch#endif /* PERIPH_1284 */
13242475Snsouch
13356455Speterstatic void
13456455Speterppi_identify(driver_t *driver, device_t parent)
13556455Speter{
13656455Speter
137127189Sguido	device_t dev;
138127189Sguido
139155921Sjhb	dev = device_find_child(parent, "ppi", -1);
140127189Sguido	if (!dev)
141127189Sguido		BUS_ADD_CHILD(parent, 0, "ppi", -1);
14256455Speter}
14356455Speter
14428219Smsmith/*
14555939Snsouch * ppi_probe()
14628219Smsmith */
14755939Snsouchstatic int
14855939Snsouchppi_probe(device_t dev)
14928219Smsmith{
15028219Smsmith	struct ppi_data *ppi;
15128219Smsmith
15255939Snsouch	/* probe is always ok */
15355939Snsouch	device_set_desc(dev, "Parallel I/O");
15455939Snsouch
15555939Snsouch	ppi = DEVTOSOFTC(dev);
15628219Smsmith
15755939Snsouch	return (0);
15855939Snsouch}
15928219Smsmith
16055939Snsouch/*
16155939Snsouch * ppi_attach()
16255939Snsouch */
16355939Snsouchstatic int
16455939Snsouchppi_attach(device_t dev)
16555939Snsouch{
166184130Sjhb	struct ppi_data *ppi = DEVTOSOFTC(dev);
16760194Sn_hibma#ifdef PERIPH_1284
168187576Sjhb	int error, rid = 0;
16928219Smsmith
17055939Snsouch	/* declare our interrupt handler */
171183053Sjhb	ppi->intr_resource = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
172183053Sjhb	    RF_ACTIVE);
173187576Sjhb	if (ppi->intr_resource) {
174187576Sjhb		/* register our interrupt handler */
175187576Sjhb		error = bus_setup_intr(dev, ppi->intr_resource,
176187576Sjhb		    INTR_TYPE_TTY | INTR_MPSAFE, NULL, ppiintr, dev,
177187576Sjhb		    &ppi->intr_cookie);
178187576Sjhb		if (error) {
179187576Sjhb			bus_release_resource(dev, SYS_RES_IRQ, rid,
180187576Sjhb			    ppi->intr_resource);
181187576Sjhb			device_printf(dev,
182187576Sjhb			    "Unable to register interrupt handler\n");
183187576Sjhb			return (error);
184187576Sjhb		}
185187576Sjhb	}
18660194Sn_hibma#endif /* PERIPH_1284 */
18728219Smsmith
188187576Sjhb	sx_init(&ppi->ppi_lock, "ppi");
189184130Sjhb	ppi->ppi_cdev = make_dev(&ppi_cdevsw, device_get_unit(dev),
19055939Snsouch		 UID_ROOT, GID_WHEEL,
19155939Snsouch		 0600, "ppi%d", device_get_unit(dev));
192184130Sjhb	if (ppi->ppi_cdev == NULL) {
193184164Sjhb		device_printf(dev, "Failed to create character device\n");
194184130Sjhb		return (ENXIO);
195184130Sjhb	}
196184130Sjhb	ppi->ppi_cdev->si_drv1 = ppi;
197184130Sjhb	ppi->ppi_device = dev;
19828219Smsmith
19955939Snsouch	return (0);
20028219Smsmith}
20128219Smsmith
202187576Sjhbstatic int
203187576Sjhbppi_detach(device_t dev)
204187576Sjhb{
205187576Sjhb	struct ppi_data *ppi = DEVTOSOFTC(dev);
206187576Sjhb
207187576Sjhb	destroy_dev(ppi->ppi_cdev);
20860194Sn_hibma#ifdef PERIPH_1284
209187576Sjhb	if (ppi->intr_resource != NULL) {
210187576Sjhb		bus_teardown_intr(dev, ppi->intr_resource, ppi->intr_cookie);
211187576Sjhb		bus_release_resource(dev, SYS_RES_IRQ, 0, ppi->intr_resource);
212187576Sjhb	}
213187576Sjhb#endif
214187576Sjhb	sx_destroy(&ppi->ppi_lock);
215187576Sjhb	return (0);
216187576Sjhb}
217187576Sjhb
218187576Sjhb#ifdef PERIPH_1284
21942475Snsouch/*
22042475Snsouch * Cable
22142475Snsouch * -----
22242475Snsouch *
22342475Snsouch * Use an IEEE1284 compliant (DB25/DB25) cable with the following tricks:
22442475Snsouch *
22542475Snsouch * nStrobe   <-> nAck		1  <-> 10
22642475Snsouch * nAutofd   <-> Busy		11 <-> 14
22742475Snsouch * nSelectin <-> Select		17 <-> 13
22842475Snsouch * nInit     <-> nFault		15 <-> 16
22942475Snsouch *
23042475Snsouch */
23128219Smsmithstatic void
23255939Snsouchppiintr(void *arg)
23328219Smsmith{
23455939Snsouch	device_t ppidev = (device_t)arg;
235185003Sjhb	device_t ppbus = device_get_parent(ppidev);
23655939Snsouch	struct ppi_data *ppi = DEVTOSOFTC(ppidev);
23742475Snsouch
238187576Sjhb	ppb_assert_locked(ppbus);
23955939Snsouch	ppi_disable_intr(ppidev);
24042475Snsouch
24155939Snsouch	switch (ppb_1284_get_state(ppbus)) {
24242475Snsouch
243108470Sschweikh	/* accept IEEE1284 negotiation then wakeup a waiting process to
244108470Sschweikh	 * continue negotiation at process level */
24542475Snsouch	case PPB_FORWARD_IDLE:
24642475Snsouch		/* Event 1 */
24755939Snsouch		if ((ppb_rstr(ppbus) & (SELECT | nBUSY)) ==
24842475Snsouch							(SELECT | nBUSY)) {
249108470Sschweikh			/* IEEE1284 negotiation */
25042475Snsouch#ifdef DEBUG_1284
25142475Snsouch			printf("N");
25242475Snsouch#endif
25342475Snsouch
25442475Snsouch			/* Event 2 - prepare for reading the ext. value */
25555939Snsouch			ppb_wctr(ppbus, (PCD | STROBE | nINIT) & ~SELECTIN);
25642475Snsouch
25755939Snsouch			ppb_1284_set_state(ppbus, PPB_NEGOCIATION);
25842475Snsouch
25942475Snsouch		} else {
26042475Snsouch#ifdef DEBUG_1284
26155939Snsouch			printf("0x%x", ppb_rstr(ppbus));
26242475Snsouch#endif
26355939Snsouch			ppb_peripheral_terminate(ppbus, PPB_DONTWAIT);
26442475Snsouch			break;
26542475Snsouch		}
26642475Snsouch
267108470Sschweikh		/* wake up any process waiting for negotiation from
26842475Snsouch		 * remote master host */
26942475Snsouch
27042475Snsouch		/* XXX should set a variable to warn the process about
27142475Snsouch		 * the interrupt */
27242475Snsouch
27342475Snsouch		wakeup(ppi);
27442475Snsouch		break;
27542475Snsouch	default:
27642475Snsouch#ifdef DEBUG_1284
27755977Speter		printf("?%d", ppb_1284_get_state(ppbus));
27842475Snsouch#endif
27955939Snsouch		ppb_1284_set_state(ppbus, PPB_FORWARD_IDLE);
28055939Snsouch		ppb_set_mode(ppbus, PPB_COMPATIBLE);
28142475Snsouch		break;
28242475Snsouch	}
28342475Snsouch
28455939Snsouch	ppi_enable_intr(ppidev);
28542475Snsouch
28628219Smsmith	return;
28728219Smsmith}
28860194Sn_hibma#endif /* PERIPH_1284 */
28928219Smsmith
29028219Smsmithstatic int
291130585Sphkppiopen(struct cdev *dev, int flags, int fmt, struct thread *td)
29228219Smsmith{
293184130Sjhb	struct ppi_data *ppi = dev->si_drv1;
294184130Sjhb	device_t ppidev = ppi->ppi_device;
295185003Sjhb	device_t ppbus = device_get_parent(ppidev);
29632178Smsmith	int res;
29728257Smsmith
298187576Sjhb	sx_xlock(&ppi->ppi_lock);
29942475Snsouch	if (!(ppi->ppi_flags & HAVE_PPBUS)) {
300187576Sjhb		ppb_lock(ppbus);
301187576Sjhb		res = ppb_request_bus(ppbus, ppidev,
302187576Sjhb		    (flags & O_NONBLOCK) ? PPB_DONTWAIT : PPB_WAIT | PPB_INTR);
303187576Sjhb		ppb_unlock(ppbus);
304187576Sjhb		if (res) {
305187576Sjhb			sx_xunlock(&ppi->ppi_lock);
30632178Smsmith			return (res);
307187576Sjhb		}
30828257Smsmith
30942475Snsouch		ppi->ppi_flags |= HAVE_PPBUS;
31042475Snsouch	}
311187576Sjhb	sx_xunlock(&ppi->ppi_lock);
31242475Snsouch
31332178Smsmith	return (0);
31428219Smsmith}
31528219Smsmith
31628219Smsmithstatic int
317130585Sphkppiclose(struct cdev *dev, int flags, int fmt, struct thread *td)
31828219Smsmith{
319184130Sjhb	struct ppi_data *ppi = dev->si_drv1;
320184130Sjhb	device_t ppidev = ppi->ppi_device;
321185003Sjhb	device_t ppbus = device_get_parent(ppidev);
32232178Smsmith
323187576Sjhb	sx_xlock(&ppi->ppi_lock);
324187576Sjhb	ppb_lock(ppbus);
32542475Snsouch#ifdef PERIPH_1284
326187576Sjhb	switch (ppb_1284_get_state(ppbus)) {
327187576Sjhb	case PPB_PERIPHERAL_IDLE:
328187576Sjhb		ppb_peripheral_terminate(ppbus, 0);
329187576Sjhb		break;
330187576Sjhb	case PPB_REVERSE_IDLE:
331187576Sjhb	case PPB_EPP_IDLE:
332187576Sjhb	case PPB_ECP_FORWARD_IDLE:
333187576Sjhb	default:
334187576Sjhb		ppb_1284_terminate(ppbus);
335187576Sjhb		break;
336187576Sjhb	}
33742475Snsouch#endif /* PERIPH_1284 */
33842475Snsouch
339187576Sjhb	/* unregistration of interrupt forced by release */
340187576Sjhb	ppb_release_bus(ppbus, ppidev);
341187576Sjhb	ppb_unlock(ppbus);
34255939Snsouch
343187576Sjhb	ppi->ppi_flags &= ~HAVE_PPBUS;
344187576Sjhb	sx_xunlock(&ppi->ppi_lock);
34542475Snsouch
34632178Smsmith	return (0);
34728219Smsmith}
34828219Smsmith
34942475Snsouch/*
35042475Snsouch * ppiread()
35142475Snsouch *
35242475Snsouch * IEEE1284 compliant read.
35342475Snsouch *
354108470Sschweikh * First, try negotiation to BYTE then NIBBLE mode
35542475Snsouch * If no data is available, wait for it otherwise transfer as much as possible
35642475Snsouch */
35728219Smsmithstatic int
358130585Sphkppiread(struct cdev *dev, struct uio *uio, int ioflag)
35942475Snsouch{
36042475Snsouch#ifdef PERIPH_1284
361184130Sjhb	struct ppi_data *ppi = dev->si_drv1;
362184130Sjhb	device_t ppidev = ppi->ppi_device;
363185003Sjhb	device_t ppbus = device_get_parent(ppidev);
36442475Snsouch	int len, error = 0;
365187576Sjhb	char *buffer;
36642475Snsouch
367187576Sjhb	buffer = malloc(BUFSIZE, M_DEVBUF, M_WAITOK);
368187576Sjhb
369187576Sjhb	ppb_lock(ppbus);
37055939Snsouch	switch (ppb_1284_get_state(ppbus)) {
37142475Snsouch	case PPB_PERIPHERAL_IDLE:
37255939Snsouch		ppb_peripheral_terminate(ppbus, 0);
373102412Scharnier		/* FALLTHROUGH */
37442475Snsouch
37542475Snsouch	case PPB_FORWARD_IDLE:
376108470Sschweikh		/* if can't negotiate NIBBLE mode then try BYTE mode,
37742475Snsouch		 * the peripheral may be a computer
37842475Snsouch		 */
37955939Snsouch		if ((ppb_1284_negociate(ppbus,
38042475Snsouch			ppi->ppi_mode = PPB_NIBBLE, 0))) {
38142475Snsouch
38242475Snsouch			/* XXX Wait 2 seconds to let the remote host some
38342475Snsouch			 * time to terminate its interrupt
38442475Snsouch			 */
385187576Sjhb			ppb_sleep(ppbus, ppi, PPBPRI, "ppiread", 2 * hz);
386185003Sjhb
38755939Snsouch			if ((error = ppb_1284_negociate(ppbus,
388187576Sjhb			    ppi->ppi_mode = PPB_BYTE, 0))) {
389187576Sjhb				ppb_unlock(ppbus);
390187576Sjhb				free(buffer, M_DEVBUF);
39142475Snsouch				return (error);
392187576Sjhb			}
39342475Snsouch		}
39442475Snsouch		break;
39542475Snsouch
39642475Snsouch	case PPB_REVERSE_IDLE:
39742475Snsouch	case PPB_EPP_IDLE:
39842475Snsouch	case PPB_ECP_FORWARD_IDLE:
39942475Snsouch	default:
40042475Snsouch		break;
40142475Snsouch	}
40242475Snsouch
40342475Snsouch#ifdef DEBUG_1284
40442475Snsouch	printf("N");
40542475Snsouch#endif
40642475Snsouch	/* read data */
40742475Snsouch	len = 0;
40842475Snsouch	while (uio->uio_resid) {
409187576Sjhb		error = ppb_1284_read(ppbus, ppi->ppi_mode,
410187576Sjhb		    buffer, min(BUFSIZE, uio->uio_resid), &len);
411187576Sjhb		ppb_unlock(ppbus);
412187576Sjhb		if (error)
41342475Snsouch			goto error;
41442475Snsouch
41542475Snsouch		if (!len)
41642475Snsouch			goto error;		/* no more data */
41742475Snsouch
41842475Snsouch#ifdef DEBUG_1284
41942475Snsouch		printf("d");
42042475Snsouch#endif
421187576Sjhb		if ((error = uiomove(buffer, len, uio)))
42242475Snsouch			goto error;
423187576Sjhb		ppb_lock(ppbus);
42442475Snsouch	}
425187576Sjhb	ppb_unlock(ppbus);
42642475Snsouch
42742475Snsoucherror:
428187576Sjhb	free(buffer, M_DEVBUF);
42942475Snsouch#else /* PERIPH_1284 */
43042475Snsouch	int error = ENODEV;
43142475Snsouch#endif
43242475Snsouch
43342475Snsouch	return (error);
43442475Snsouch}
43542475Snsouch
43642475Snsouch/*
43742475Snsouch * ppiwrite()
43842475Snsouch *
43942475Snsouch * IEEE1284 compliant write
44042475Snsouch *
44142475Snsouch * Actually, this is the peripheral side of a remote IEEE1284 read
44242475Snsouch *
443108470Sschweikh * The first part of the negotiation (IEEE1284 device detection) is
44442475Snsouch * done at interrupt level, then the remaining is done by the writing
44542475Snsouch * process
44642475Snsouch *
447108470Sschweikh * Once negotiation done, transfer data
44842475Snsouch */
44942475Snsouchstatic int
450130585Sphkppiwrite(struct cdev *dev, struct uio *uio, int ioflag)
45142475Snsouch{
45242475Snsouch#ifdef PERIPH_1284
453184130Sjhb	struct ppi_data *ppi = dev->si_drv1;
454184130Sjhb	device_t ppidev = ppi->ppi_device;
455185003Sjhb	device_t ppbus = device_get_parent(ppidev);
45642475Snsouch	int len, error = 0, sent;
457187576Sjhb	char *buffer;
45842475Snsouch
45942475Snsouch#if 0
46042475Snsouch	int ret;
46142475Snsouch
46242475Snsouch	#define ADDRESS		MS_PARAM(0, 0, MS_TYP_PTR)
46342475Snsouch	#define LENGTH		MS_PARAM(0, 1, MS_TYP_INT)
46442475Snsouch
46542475Snsouch	struct ppb_microseq msq[] = {
46642475Snsouch		  { MS_OP_PUT, { MS_UNKNOWN, MS_UNKNOWN, MS_UNKNOWN } },
46742475Snsouch		  MS_RET(0)
46842475Snsouch	};
46942475Snsouch
470187576Sjhb	buffer = malloc(BUFSIZE, M_DEVBUF, M_WAITOK);
471187576Sjhb	ppb_lock(ppbus);
472187576Sjhb
473108470Sschweikh	/* negotiate ECP mode */
47455939Snsouch	if (ppb_1284_negociate(ppbus, PPB_ECP, 0)) {
475108470Sschweikh		printf("ppiwrite: ECP negotiation failed\n");
47642475Snsouch	}
47742475Snsouch
47842475Snsouch	while (!error && (len = min(uio->uio_resid, BUFSIZE))) {
479187576Sjhb		ppb_unlock(ppbus);
480187576Sjhb		uiomove(buffer, len, uio);
48142475Snsouch
482187576Sjhb		ppb_MS_init_msq(msq, 2, ADDRESS, buffer, LENGTH, len);
48342475Snsouch
484187576Sjhb		ppb_lock(ppbus);
48555939Snsouch		error = ppb_MS_microseq(ppbus, msq, &ret);
48642475Snsouch	}
487187576Sjhb#else
488187576Sjhb	buffer = malloc(BUFSIZE, M_DEVBUF, M_WAITOK);
489187576Sjhb	ppb_lock(ppbus);
49042475Snsouch#endif
49142475Snsouch
49242475Snsouch	/* we have to be peripheral to be able to send data, so
49342475Snsouch	 * wait for the appropriate state
49442475Snsouch	 */
49555957Snsouch 	if (ppb_1284_get_state(ppbus) < PPB_PERIPHERAL_NEGOCIATION)
49655939Snsouch		ppb_1284_terminate(ppbus);
49742475Snsouch
49855957Snsouch 	while (ppb_1284_get_state(ppbus) != PPB_PERIPHERAL_IDLE) {
49942475Snsouch		/* XXX should check a variable before sleeping */
50042475Snsouch#ifdef DEBUG_1284
50142475Snsouch		printf("s");
50242475Snsouch#endif
50342475Snsouch
50455939Snsouch		ppi_enable_intr(ppidev);
50542475Snsouch
506108470Sschweikh		/* sleep until IEEE1284 negotiation starts */
507187576Sjhb		error = ppb_sleep(ppbus, ppi, PCATCH | PPBPRI, "ppiwrite", 0);
50842475Snsouch
50942475Snsouch		switch (error) {
51042475Snsouch		case 0:
511108470Sschweikh			/* negotiate peripheral side with BYTE mode */
51255939Snsouch			ppb_peripheral_negociate(ppbus, PPB_BYTE, 0);
51342475Snsouch			break;
51442475Snsouch		case EWOULDBLOCK:
51542475Snsouch			break;
51642475Snsouch		default:
51742475Snsouch			goto error;
51842475Snsouch		}
51942475Snsouch	}
52042475Snsouch#ifdef DEBUG_1284
52142475Snsouch	printf("N");
52242475Snsouch#endif
52342475Snsouch
524108470Sschweikh	/* negotiation done, write bytes to master host */
52543301Sdillon	while ((len = min(uio->uio_resid, BUFSIZE)) != 0) {
526187576Sjhb		ppb_unlock(ppbus);
527187576Sjhb		uiomove(buffer, len, uio);
528187576Sjhb		ppb_lock(ppbus);
52955939Snsouch		if ((error = byte_peripheral_write(ppbus,
530187576Sjhb						buffer, len, &sent)))
53142475Snsouch			goto error;
53242475Snsouch#ifdef DEBUG_1284
53342475Snsouch		printf("d");
53442475Snsouch#endif
53542475Snsouch	}
53642475Snsouch
53742475Snsoucherror:
538187576Sjhb	ppb_unlock(ppbus);
539187576Sjhb	free(buffer, M_DEVBUF);
54042475Snsouch#else /* PERIPH_1284 */
54142475Snsouch	int error = ENODEV;
54242475Snsouch#endif
54342475Snsouch
54442475Snsouch	return (error);
54542475Snsouch}
54642475Snsouch
54742475Snsouchstatic int
548130585Sphkppiioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, struct thread *td)
54928219Smsmith{
550184130Sjhb	struct ppi_data *ppi = dev->si_drv1;
551184130Sjhb	device_t ppidev = ppi->ppi_device;
552184164Sjhb	device_t ppbus = device_get_parent(ppidev);
55332178Smsmith	int error = 0;
55432178Smsmith	u_int8_t *val = (u_int8_t *)data;
55532178Smsmith
556187576Sjhb	ppb_lock(ppbus);
55732178Smsmith	switch (cmd) {
55832178Smsmith
55932178Smsmith	case PPIGDATA:			/* get data register */
56055939Snsouch		*val = ppb_rdtr(ppbus);
56132178Smsmith		break;
56232178Smsmith	case PPIGSTATUS:		/* get status bits */
56355939Snsouch		*val = ppb_rstr(ppbus);
56432178Smsmith		break;
56532178Smsmith	case PPIGCTRL:			/* get control bits */
56655939Snsouch		*val = ppb_rctr(ppbus);
56732178Smsmith		break;
56843433Snsouch	case PPIGEPPD:			/* get EPP data bits */
56955939Snsouch		*val = ppb_repp_D(ppbus);
57032178Smsmith		break;
57132178Smsmith	case PPIGECR:			/* get ECP bits */
57255939Snsouch		*val = ppb_recr(ppbus);
57332178Smsmith		break;
57432178Smsmith	case PPIGFIFO:			/* read FIFO */
57555939Snsouch		*val = ppb_rfifo(ppbus);
57632178Smsmith		break;
57732178Smsmith	case PPISDATA:			/* set data register */
57855939Snsouch		ppb_wdtr(ppbus, *val);
57932178Smsmith		break;
58032178Smsmith	case PPISSTATUS:		/* set status bits */
58155939Snsouch		ppb_wstr(ppbus, *val);
58232178Smsmith		break;
58332178Smsmith	case PPISCTRL:			/* set control bits */
58455939Snsouch		ppb_wctr(ppbus, *val);
58532178Smsmith		break;
58643433Snsouch	case PPISEPPD:			/* set EPP data bits */
58755939Snsouch		ppb_wepp_D(ppbus, *val);
58832178Smsmith		break;
58932178Smsmith	case PPISECR:			/* set ECP bits */
59055939Snsouch		ppb_wecr(ppbus, *val);
59132178Smsmith		break;
59232178Smsmith	case PPISFIFO:			/* write FIFO */
59355939Snsouch		ppb_wfifo(ppbus, *val);
59432178Smsmith		break;
59543433Snsouch	case PPIGEPPA:			/* get EPP address bits */
59655939Snsouch		*val = ppb_repp_A(ppbus);
59743433Snsouch		break;
59843433Snsouch	case PPISEPPA:			/* set EPP address bits */
59955939Snsouch		ppb_wepp_A(ppbus, *val);
60043433Snsouch		break;
60132178Smsmith	default:
60232178Smsmith		error = ENOTTY;
60332178Smsmith		break;
60432178Smsmith	}
605187576Sjhb	ppb_unlock(ppbus);
606185003Sjhb
60732178Smsmith	return (error);
60828219Smsmith}
60928219Smsmith
61056455Speterstatic device_method_t ppi_methods[] = {
61156455Speter	/* device interface */
61256455Speter	DEVMETHOD(device_identify,	ppi_identify),
61356455Speter	DEVMETHOD(device_probe,		ppi_probe),
61456455Speter	DEVMETHOD(device_attach,	ppi_attach),
615187576Sjhb	DEVMETHOD(device_detach,	ppi_detach),
61656455Speter
61756455Speter	{ 0, 0 }
61856455Speter};
61956455Speter
62056455Speterstatic driver_t ppi_driver = {
62156455Speter	"ppi",
62256455Speter	ppi_methods,
62356455Speter	sizeof(struct ppi_data),
62456455Speter};
62555939SnsouchDRIVER_MODULE(ppi, ppbus, ppi_driver, ppi_devclass, 0, 0);
626153610SruMODULE_DEPEND(ppi, ppbus, 1, 1, 1);
627