xref: /freebsd-src/sys/dev/pbio/pbio.c (revision fdafd315ad0d0f28a11b9fb4476a9ab059c62b92)
1098ca2bdSWarner Losh /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni  *
4bacb482dSWarner Losh  *  Copyright (c) 2000-2004
5bacb482dSWarner Losh  *          Diomidis D. Spinellis, Athens, Greece
6bacb482dSWarner Losh  *      All rights reserved.
7bacb482dSWarner Losh  *
8bacb482dSWarner Losh  *  Redistribution and use in source and binary forms, with or without
9bacb482dSWarner Losh  *  modification, are permitted provided that the following conditions
10bacb482dSWarner Losh  *  are met:
11bacb482dSWarner Losh  *  1. Redistributions of source code must retain the above copyright
12bacb482dSWarner Losh  *     notice, this list of conditions and the following disclaimer as
13bacb482dSWarner Losh  *     the first lines of this file unmodified.
14bacb482dSWarner Losh  *  2. Redistributions in binary form must reproduce the above copyright
15bacb482dSWarner Losh  *     notice, this list of conditions and the following disclaimer in the
16bacb482dSWarner Losh  *     documentation and/or other materials provided with the distribution.
17bacb482dSWarner Losh  *
18bacb482dSWarner Losh  *  THIS SOFTWARE IS PROVIDED BY Diomidis D. Spinellis ``AS IS'' AND ANY
19bacb482dSWarner Losh  *  EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20bacb482dSWarner Losh  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21bacb482dSWarner Losh  *  PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL Diomidis D. Spinellis BE
22bacb482dSWarner Losh  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23bacb482dSWarner Losh  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24bacb482dSWarner Losh  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
25bacb482dSWarner Losh  *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26bacb482dSWarner Losh  *  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
27bacb482dSWarner Losh  *  OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
28bacb482dSWarner Losh  *  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29bacb482dSWarner Losh  *
30bacb482dSWarner Losh  * $Id: pbio.c,v 1.12 2003/10/11 13:05:08 dds Exp dds $
31bacb482dSWarner Losh  */
32bacb482dSWarner Losh 
33bacb482dSWarner Losh #include <sys/param.h>
34bacb482dSWarner Losh #include <sys/systm.h>
35bacb482dSWarner Losh #include <sys/kernel.h>		/* SYSINIT stuff */
36bacb482dSWarner Losh #include <sys/bus.h>
37bacb482dSWarner Losh #include <sys/resource.h>
38bacb482dSWarner Losh #include <sys/syslog.h>
39bacb482dSWarner Losh #include <sys/sysctl.h>
40bacb482dSWarner Losh #include <sys/conf.h>		/* cdevsw stuff */
41bacb482dSWarner Losh #include <sys/malloc.h>		/* malloc region definitions */
42bacb482dSWarner Losh #include <sys/module.h>
43bacb482dSWarner Losh #include <machine/bus.h>
44bacb482dSWarner Losh #include <machine/resource.h>
45bacb482dSWarner Losh #include <sys/rman.h>
46154eb445SDavid E. O'Brien #include <dev/pbio/pbioio.h>		/* pbio IOCTL definitions */
47bacb482dSWarner Losh #include <sys/uio.h>
48bacb482dSWarner Losh #include <sys/fcntl.h>
4951f48123SJohn Baldwin #include <sys/sx.h>
508d50b6afSWarner Losh #include <isa/isavar.h>
51bacb482dSWarner Losh 
52bacb482dSWarner Losh /* Function prototypes (these should all be static) */
53bacb482dSWarner Losh static	d_open_t	pbioopen;
54bacb482dSWarner Losh static	d_read_t	pbioread;
55bacb482dSWarner Losh static	d_write_t	pbiowrite;
56bacb482dSWarner Losh static	d_ioctl_t	pbioioctl;
57bacb482dSWarner Losh static	d_poll_t	pbiopoll;
58bacb482dSWarner Losh static	int		pbioprobe(device_t);
59bacb482dSWarner Losh static	int		pbioattach(device_t);
60bacb482dSWarner Losh 
61bacb482dSWarner Losh /* Device registers */
62bacb482dSWarner Losh #define	PBIO_PORTA	0
63bacb482dSWarner Losh #define	PBIO_PORTB	1
64bacb482dSWarner Losh #define	PBIO_PORTC	2
65bacb482dSWarner Losh #define	PBIO_CFG	3
66bacb482dSWarner Losh #define	PBIO_IOSIZE	4
67bacb482dSWarner Losh 
68bacb482dSWarner Losh /* Per-port buffer size */
69bacb482dSWarner Losh #define	PBIO_BUFSIZ 64
70bacb482dSWarner Losh 
71bacb482dSWarner Losh /* Number of /dev entries */
72bacb482dSWarner Losh #define	PBIO_NPORTS 4
73bacb482dSWarner Losh 
74bacb482dSWarner Losh /* I/O port range */
75bacb482dSWarner Losh #define	IO_PBIOSIZE 4
76bacb482dSWarner Losh 
77bacb482dSWarner Losh static char *port_names[] = {"a", "b", "ch", "cl"};
78bacb482dSWarner Losh 
79bacb482dSWarner Losh #define	PBIO_PNAME(n)		(port_names[(n)])
80bacb482dSWarner Losh 
810db65574SJohn Baldwin #define	PORT(dev)		(dev2unit(dev))
820db65574SJohn Baldwin 
830db65574SJohn Baldwin #define	pbio_addr(dev)		((dev)->si_drv1)
84bacb482dSWarner Losh 
85bacb482dSWarner Losh static struct cdevsw pbio_cdevsw = {
86bacb482dSWarner Losh 	.d_version = D_VERSION,
87bacb482dSWarner Losh 	.d_open = pbioopen,
88bacb482dSWarner Losh 	.d_read = pbioread,
89bacb482dSWarner Losh 	.d_write = pbiowrite,
90bacb482dSWarner Losh 	.d_ioctl = pbioioctl,
91bacb482dSWarner Losh 	.d_poll = pbiopoll,
92bacb482dSWarner Losh 	.d_name = "pbio"
93bacb482dSWarner Losh };
94bacb482dSWarner Losh 
95bacb482dSWarner Losh /*
96bacb482dSWarner Losh  * Data specific to each I/O port
97bacb482dSWarner Losh  */
98bacb482dSWarner Losh struct portdata {
99bacb482dSWarner Losh 	struct cdev *port;
100bacb482dSWarner Losh 	int	diff;			/* When true read only differences */
101bacb482dSWarner Losh 	int	ipace;			/* Input pace */
102bacb482dSWarner Losh 	int	opace;			/* Output pace */
103bacb482dSWarner Losh 	char	oldval;			/* Last value read */
104bacb482dSWarner Losh 	char	buff[PBIO_BUFSIZ];	/* Per-port data buffer */
105bacb482dSWarner Losh };
106bacb482dSWarner Losh 
107bacb482dSWarner Losh /*
108bacb482dSWarner Losh  * One of these per allocated device
109bacb482dSWarner Losh  */
110bacb482dSWarner Losh struct pbio_softc {
111bacb482dSWarner Losh 	struct portdata pd[PBIO_NPORTS];/* Per port data */
112bacb482dSWarner Losh 	int	iomode;			/* Virtualized I/O mode port value */
113bacb482dSWarner Losh 					/* The real port is write-only */
114ac00fac2SWarner Losh 	struct resource *res;
11551f48123SJohn Baldwin 	struct sx lock;
116bacb482dSWarner Losh };
117bacb482dSWarner Losh 
118bacb482dSWarner Losh typedef	struct pbio_softc *sc_p;
119bacb482dSWarner Losh 
120bacb482dSWarner Losh static device_method_t pbio_methods[] = {
121bacb482dSWarner Losh 	/* Device interface */
122bacb482dSWarner Losh 	DEVMETHOD(device_probe,		pbioprobe),
123bacb482dSWarner Losh 	DEVMETHOD(device_attach,	pbioattach),
124bacb482dSWarner Losh 	{ 0, 0 }
125bacb482dSWarner Losh };
126bacb482dSWarner Losh 
127bacb482dSWarner Losh static char driver_name[] = "pbio";
128bacb482dSWarner Losh 
129bacb482dSWarner Losh static driver_t pbio_driver = {
130bacb482dSWarner Losh 	driver_name,
131bacb482dSWarner Losh 	pbio_methods,
132bacb482dSWarner Losh 	sizeof(struct pbio_softc),
133bacb482dSWarner Losh };
134bacb482dSWarner Losh 
135ce4ca2edSJohn Baldwin DRIVER_MODULE(pbio, isa, pbio_driver, 0, 0);
136bacb482dSWarner Losh 
137ac00fac2SWarner Losh static __inline uint8_t
pbinb(struct pbio_softc * scp,int off)138ac00fac2SWarner Losh pbinb(struct pbio_softc *scp, int off)
139ac00fac2SWarner Losh {
140ac00fac2SWarner Losh 
141bb81a138SJohn Baldwin 	return (bus_read_1(scp->res, off));
142ac00fac2SWarner Losh }
143ac00fac2SWarner Losh 
144ac00fac2SWarner Losh static __inline void
pboutb(struct pbio_softc * scp,int off,uint8_t val)145ac00fac2SWarner Losh pboutb(struct pbio_softc *scp, int off, uint8_t val)
146ac00fac2SWarner Losh {
147ac00fac2SWarner Losh 
148bb81a138SJohn Baldwin 	bus_write_1(scp->res, off, val);
149ac00fac2SWarner Losh }
150ac00fac2SWarner Losh 
151bacb482dSWarner Losh static int
pbioprobe(device_t dev)152bacb482dSWarner Losh pbioprobe(device_t dev)
153bacb482dSWarner Losh {
154bacb482dSWarner Losh 	int		rid;
155ac00fac2SWarner Losh 	struct pbio_softc *scp = device_get_softc(dev);
156bacb482dSWarner Losh #ifdef GENERIC_PBIO_PROBE
157bacb482dSWarner Losh 	unsigned char val;
158bacb482dSWarner Losh #endif
159bacb482dSWarner Losh 
1608d50b6afSWarner Losh 	if (isa_get_logicalid(dev))		/* skip PnP probes */
1618d50b6afSWarner Losh 		return (ENXIO);
162bacb482dSWarner Losh 	rid = 0;
163c47476d7SJustin Hibbits 	scp->res = bus_alloc_resource_anywhere(dev, SYS_RES_IOPORT, &rid,
164c47476d7SJustin Hibbits 	    IO_PBIOSIZE, RF_ACTIVE);
165ac00fac2SWarner Losh 	if (scp->res == NULL)
166bacb482dSWarner Losh 		return (ENXIO);
167bacb482dSWarner Losh 
168bacb482dSWarner Losh #ifdef GENERIC_PBIO_PROBE
169bacb482dSWarner Losh 	/*
170bacb482dSWarner Losh 	 * try see if the device is there.
171bacb482dSWarner Losh 	 * This probe works only if the device has no I/O attached to it
172bacb482dSWarner Losh 	 * XXX Better allow flags to abort testing
173bacb482dSWarner Losh 	 */
174bacb482dSWarner Losh 	/* Set all ports to output */
175ac00fac2SWarner Losh 	pboutb(scp, PBIO_CFG, 0x80);
176bacb482dSWarner Losh 	printf("pbio val(CFG: 0x%03x)=0x%02x (should be 0x80)\n",
177905454c8SWarner Losh 		rman_get_start(scp->res), pbinb(scp, PBIO_CFG));
178ac00fac2SWarner Losh 	pboutb(scp, PBIO_PORTA, 0xa5);
179ac00fac2SWarner Losh 	val = pbinb(scp, PBIO_PORTA);
180bacb482dSWarner Losh 	printf("pbio val=0x%02x (should be 0xa5)\n", val);
181ac00fac2SWarner Losh 	if (val != 0xa5) {
182ac00fac2SWarner Losh 		bus_release_resource(dev, SYS_RES_IOPORT, rid, sc->res);
183bacb482dSWarner Losh 		return (ENXIO);
184ac00fac2SWarner Losh 	}
185ac00fac2SWarner Losh 	pboutb(scp, PBIO_PORTA, 0x5a);
186ac00fac2SWarner Losh 	val = pbinb(scp, PBIO_PORTA);
187bacb482dSWarner Losh 	printf("pbio val=0x%02x (should be 0x5a)\n", val);
188ac00fac2SWarner Losh 	if (val != 0x5a) {
189ac00fac2SWarner Losh 		bus_release_resource(dev, SYS_RES_IOPORT, rid, sc->res);
190bacb482dSWarner Losh 		return (ENXIO);
191ac00fac2SWarner Losh 	}
192bacb482dSWarner Losh #endif
193bacb482dSWarner Losh 	device_set_desc(dev, "Intel 8255 PPI (basic mode)");
194bacb482dSWarner Losh 	/* Set all ports to input */
195ac00fac2SWarner Losh 	/* pboutb(scp, PBIO_CFG, 0x9b); */
196ac00fac2SWarner Losh 	bus_release_resource(dev, SYS_RES_IOPORT, rid, scp->res);
1974942e8dfSJohn Baldwin 	return (BUS_PROBE_DEFAULT);
198bacb482dSWarner Losh }
199bacb482dSWarner Losh 
200bacb482dSWarner Losh /*
201bacb482dSWarner Losh  * Called if the probe succeeded.
202bacb482dSWarner Losh  * We can be destructive here as we know we have the device.
203bacb482dSWarner Losh  * we can also trust the unit number.
204bacb482dSWarner Losh  */
205bacb482dSWarner Losh static int
pbioattach(device_t dev)206bacb482dSWarner Losh pbioattach (device_t dev)
207bacb482dSWarner Losh {
2080db65574SJohn Baldwin 	struct make_dev_args args;
209ac00fac2SWarner Losh 	int unit;
210ac00fac2SWarner Losh 	int i;
211ac00fac2SWarner Losh 	int		rid;
212bacb482dSWarner Losh 	struct pbio_softc *sc;
213bacb482dSWarner Losh 
214ac00fac2SWarner Losh 	sc = device_get_softc(dev);
2153b33d41dSDavid E. O'Brien 	unit = device_get_unit(dev);
216bacb482dSWarner Losh 	rid = 0;
217c47476d7SJustin Hibbits 	sc->res = bus_alloc_resource_anywhere(dev, SYS_RES_IOPORT, &rid,
218c47476d7SJustin Hibbits 	    IO_PBIOSIZE, RF_ACTIVE);
219ac00fac2SWarner Losh 	if (sc->res == NULL)
220bacb482dSWarner Losh 		return (ENXIO);
221bacb482dSWarner Losh 
222bacb482dSWarner Losh 	/*
223bacb482dSWarner Losh 	 * Store whatever seems wise.
224bacb482dSWarner Losh 	 */
225bacb482dSWarner Losh 	sc->iomode = 0x9b;		/* All ports to input */
226bacb482dSWarner Losh 
22751f48123SJohn Baldwin 	sx_init(&sc->lock, "pbio");
2280db65574SJohn Baldwin 	for (i = 0; i < PBIO_NPORTS; i++) {
2290db65574SJohn Baldwin 		make_dev_args_init(&args);
2300db65574SJohn Baldwin 		args.mda_devsw = &pbio_cdevsw;
2310db65574SJohn Baldwin 		args.mda_uid = 0;
2320db65574SJohn Baldwin 		args.mda_gid = 0;
2330db65574SJohn Baldwin 		args.mda_mode = 0600;
2340db65574SJohn Baldwin 		args.mda_unit = i;
2350db65574SJohn Baldwin 		args.mda_si_drv1 = sc;
2360db65574SJohn Baldwin 		(void)make_dev_s(&args, &sc->pd[i].port, "pbio%d%s", unit,
2370db65574SJohn Baldwin 		    PBIO_PNAME(i));
2380db65574SJohn Baldwin 	}
2393b33d41dSDavid E. O'Brien 	return (0);
240bacb482dSWarner Losh }
241bacb482dSWarner Losh 
242bacb482dSWarner Losh static int
pbioioctl(struct cdev * dev,u_long cmd,caddr_t data,int flag,struct thread * td)243bacb482dSWarner Losh pbioioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag,
244bacb482dSWarner Losh     struct thread *td)
245bacb482dSWarner Losh {
246bacb482dSWarner Losh 	struct pbio_softc *scp;
24751f48123SJohn Baldwin 	int error, port;
248bacb482dSWarner Losh 
24951f48123SJohn Baldwin 	error = 0;
2503b33d41dSDavid E. O'Brien 	port = PORT(dev);
2510db65574SJohn Baldwin 	scp = pbio_addr(dev);
25251f48123SJohn Baldwin 	sx_xlock(&scp->lock);
253bacb482dSWarner Losh 	switch (cmd) {
254bacb482dSWarner Losh 	case PBIO_SETDIFF:
255bacb482dSWarner Losh 		scp->pd[port].diff = *(int *)data;
256bacb482dSWarner Losh 		break;
257bacb482dSWarner Losh 	case PBIO_SETIPACE:
258bacb482dSWarner Losh 		scp->pd[port].ipace = *(int *)data;
259bacb482dSWarner Losh 		break;
260bacb482dSWarner Losh 	case PBIO_SETOPACE:
261bacb482dSWarner Losh 		scp->pd[port].opace = *(int *)data;
262bacb482dSWarner Losh 		break;
263bacb482dSWarner Losh 	case PBIO_GETDIFF:
264bacb482dSWarner Losh 		*(int *)data = scp->pd[port].diff;
265bacb482dSWarner Losh 		break;
266bacb482dSWarner Losh 	case PBIO_GETIPACE:
267bacb482dSWarner Losh 		*(int *)data = scp->pd[port].ipace;
268bacb482dSWarner Losh 		break;
269bacb482dSWarner Losh 	case PBIO_GETOPACE:
270bacb482dSWarner Losh 		*(int *)data = scp->pd[port].opace;
271bacb482dSWarner Losh 		break;
272bacb482dSWarner Losh 	default:
27351f48123SJohn Baldwin 		error = ENXIO;
274bacb482dSWarner Losh 	}
27551f48123SJohn Baldwin 	sx_xunlock(&scp->lock);
27651f48123SJohn Baldwin 	return (error);
277bacb482dSWarner Losh }
278bacb482dSWarner Losh 
279bacb482dSWarner Losh static  int
pbioopen(struct cdev * dev,int oflags,int devtype,struct thread * td)280bacb482dSWarner Losh pbioopen(struct cdev *dev, int oflags, int devtype, struct thread *td)
281bacb482dSWarner Losh {
282bacb482dSWarner Losh 	struct pbio_softc *scp;
28351f48123SJohn Baldwin 	int error, ocfg, port;
284bacb482dSWarner Losh 	int portbit;			/* Port configuration bit */
285bacb482dSWarner Losh 
2863b33d41dSDavid E. O'Brien 	port = PORT(dev);
2870db65574SJohn Baldwin 	scp = pbio_addr(dev);
288bacb482dSWarner Losh 
289bacb482dSWarner Losh 	switch (port) {
290bacb482dSWarner Losh 	case 0: portbit = 0x10; break;	/* Port A */
291bacb482dSWarner Losh 	case 1: portbit = 0x02; break;	/* Port B */
292bacb482dSWarner Losh 	case 2: portbit = 0x08; break;	/* Port CH */
293bacb482dSWarner Losh 	case 3: portbit = 0x01; break;	/* Port CL */
294bacb482dSWarner Losh 	default: return (ENODEV);
295bacb482dSWarner Losh 	}
296bacb482dSWarner Losh 	ocfg = scp->iomode;
297bacb482dSWarner Losh 
29851f48123SJohn Baldwin 	error = 0;
29951f48123SJohn Baldwin 	sx_xlock(&scp->lock);
300bacb482dSWarner Losh 	if (oflags & FWRITE)
301bacb482dSWarner Losh 		/* Writing == output; zero the bit */
302ac00fac2SWarner Losh 		pboutb(scp, PBIO_CFG, scp->iomode = (ocfg & (~portbit)));
303bacb482dSWarner Losh 	else if (oflags & FREAD)
304bacb482dSWarner Losh 		/* Reading == input; set the bit */
305ac00fac2SWarner Losh 		pboutb(scp, PBIO_CFG, scp->iomode = (ocfg | portbit));
306bacb482dSWarner Losh 	else
30751f48123SJohn Baldwin 		error = EACCES;
30851f48123SJohn Baldwin 	sx_xunlock(&scp->lock);
309bacb482dSWarner Losh 
31051f48123SJohn Baldwin 	return (error);
311bacb482dSWarner Losh }
312bacb482dSWarner Losh 
313bacb482dSWarner Losh /*
314bacb482dSWarner Losh  * Return the value of a given port on a given I/O base address
315bacb482dSWarner Losh  * Handles the split C port nibbles and blocking
316bacb482dSWarner Losh  */
317bacb482dSWarner Losh static int
portval(int port,struct pbio_softc * scp,char * val)318bacb482dSWarner Losh portval(int port, struct pbio_softc *scp, char *val)
319bacb482dSWarner Losh {
320bacb482dSWarner Losh 	int err;
321bacb482dSWarner Losh 
322bacb482dSWarner Losh 	for (;;) {
323bacb482dSWarner Losh 		switch (port) {
324bacb482dSWarner Losh 		case 0:
325ac00fac2SWarner Losh 			*val = pbinb(scp, PBIO_PORTA);
326bacb482dSWarner Losh 			break;
327bacb482dSWarner Losh 		case 1:
328ac00fac2SWarner Losh 			*val = pbinb(scp, PBIO_PORTB);
329bacb482dSWarner Losh 			break;
330bacb482dSWarner Losh 		case 2:
331ac00fac2SWarner Losh 			*val = (pbinb(scp, PBIO_PORTC) >> 4) & 0xf;
332bacb482dSWarner Losh 			break;
333bacb482dSWarner Losh 		case 3:
334ac00fac2SWarner Losh 			*val = pbinb(scp, PBIO_PORTC) & 0xf;
335bacb482dSWarner Losh 			break;
336bacb482dSWarner Losh 		default:
337bacb482dSWarner Losh 			*val = 0;
338bacb482dSWarner Losh 			break;
339bacb482dSWarner Losh 		}
340bacb482dSWarner Losh 		if (scp->pd[port].diff) {
341bacb482dSWarner Losh 			if (*val != scp->pd[port].oldval) {
342bacb482dSWarner Losh 				scp->pd[port].oldval = *val;
343bacb482dSWarner Losh 				return (0);
344bacb482dSWarner Losh 			}
34551f48123SJohn Baldwin 			err = pause_sig("pbiopl", max(1, scp->pd[port].ipace));
346bacb482dSWarner Losh 			if (err == EINTR)
347bacb482dSWarner Losh 				return (EINTR);
348bacb482dSWarner Losh 		} else
349bacb482dSWarner Losh 			return (0);
350bacb482dSWarner Losh 	}
351bacb482dSWarner Losh }
352bacb482dSWarner Losh 
353bacb482dSWarner Losh static  int
pbioread(struct cdev * dev,struct uio * uio,int ioflag)354bacb482dSWarner Losh pbioread(struct cdev *dev, struct uio *uio, int ioflag)
355bacb482dSWarner Losh {
356bacb482dSWarner Losh 	struct pbio_softc *scp;
35751f48123SJohn Baldwin 	int err, i, port, toread;
358bacb482dSWarner Losh 	char val;
359bacb482dSWarner Losh 
3603b33d41dSDavid E. O'Brien 	port = PORT(dev);
3610db65574SJohn Baldwin 	scp = pbio_addr(dev);
362bacb482dSWarner Losh 
36351f48123SJohn Baldwin 	err = 0;
36451f48123SJohn Baldwin 	sx_xlock(&scp->lock);
365bacb482dSWarner Losh 	while (uio->uio_resid > 0) {
366bacb482dSWarner Losh 		toread = min(uio->uio_resid, PBIO_BUFSIZ);
36751f48123SJohn Baldwin 		if ((err = uiomove(scp->pd[port].buff, toread, uio)) != 0)
36851f48123SJohn Baldwin 			break;
369bacb482dSWarner Losh 		for (i = 0; i < toread; i++) {
370bacb482dSWarner Losh 			if ((err = portval(port, scp, &val)) != 0)
37151f48123SJohn Baldwin 				break;
372bacb482dSWarner Losh 			scp->pd[port].buff[i] = val;
373bacb482dSWarner Losh 			if (!scp->pd[port].diff && scp->pd[port].ipace)
37451f48123SJohn Baldwin 				pause_sig("pbioip", scp->pd[port].ipace);
375bacb482dSWarner Losh 		}
376bacb482dSWarner Losh 	}
37751f48123SJohn Baldwin 	sx_xunlock(&scp->lock);
37851f48123SJohn Baldwin 	return (err);
379bacb482dSWarner Losh }
380bacb482dSWarner Losh 
381bacb482dSWarner Losh static int
pbiowrite(struct cdev * dev,struct uio * uio,int ioflag)382bacb482dSWarner Losh pbiowrite(struct cdev *dev, struct uio *uio, int ioflag)
383bacb482dSWarner Losh {
384bacb482dSWarner Losh 	struct pbio_softc *scp;
3850db65574SJohn Baldwin 	int i, port, ret, towrite;
386bacb482dSWarner Losh 	char val, oval;
387bacb482dSWarner Losh 
3883b33d41dSDavid E. O'Brien 	port = PORT(dev);
3890db65574SJohn Baldwin 	scp = pbio_addr(dev);
390bacb482dSWarner Losh 
39151f48123SJohn Baldwin 	ret = 0;
39251f48123SJohn Baldwin 	sx_xlock(&scp->lock);
393bacb482dSWarner Losh 	while (uio->uio_resid > 0) {
394bacb482dSWarner Losh 		towrite = min(uio->uio_resid, PBIO_BUFSIZ);
395bacb482dSWarner Losh 		if ((ret = uiomove(scp->pd[port].buff, towrite, uio)) != 0)
39651f48123SJohn Baldwin 			break;
397bacb482dSWarner Losh 		for (i = 0; i < towrite; i++) {
398bacb482dSWarner Losh 			val = scp->pd[port].buff[i];
399bacb482dSWarner Losh 			switch (port) {
400bacb482dSWarner Losh 			case 0:
401ac00fac2SWarner Losh 				pboutb(scp, PBIO_PORTA, val);
402bacb482dSWarner Losh 				break;
403bacb482dSWarner Losh 			case 1:
404ac00fac2SWarner Losh 				pboutb(scp, PBIO_PORTB, val);
405bacb482dSWarner Losh 				break;
406bacb482dSWarner Losh 			case 2:
407ac00fac2SWarner Losh 				oval = pbinb(scp, PBIO_PORTC);
408bacb482dSWarner Losh 				oval &= 0xf;
409bacb482dSWarner Losh 				val <<= 4;
410ac00fac2SWarner Losh 				pboutb(scp, PBIO_PORTC, val | oval);
411bacb482dSWarner Losh 				break;
412bacb482dSWarner Losh 			case 3:
413ac00fac2SWarner Losh 				oval = pbinb(scp, PBIO_PORTC);
414bacb482dSWarner Losh 				oval &= 0xf0;
415bacb482dSWarner Losh 				val &= 0xf;
416ac00fac2SWarner Losh 				pboutb(scp, PBIO_PORTC, oval | val);
417bacb482dSWarner Losh 				break;
418bacb482dSWarner Losh 			}
419bacb482dSWarner Losh 			if (scp->pd[port].opace)
42051f48123SJohn Baldwin 				pause_sig("pbioop", scp->pd[port].opace);
421bacb482dSWarner Losh 		}
422bacb482dSWarner Losh 	}
42351f48123SJohn Baldwin 	sx_xunlock(&scp->lock);
42451f48123SJohn Baldwin 	return (ret);
425bacb482dSWarner Losh }
426bacb482dSWarner Losh 
427bacb482dSWarner Losh static  int
pbiopoll(struct cdev * dev,int which,struct thread * td)428bacb482dSWarner Losh pbiopoll(struct cdev *dev, int which, struct thread *td)
429bacb482dSWarner Losh {
430bacb482dSWarner Losh 	/*
431bacb482dSWarner Losh 	 * Do processing
432bacb482dSWarner Losh 	 */
433bacb482dSWarner Losh 	return (0); /* this is the wrong value I'm sure */
434bacb482dSWarner Losh }
435