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