1*6b664a71Sisaki /* $NetBSD: par.c,v 1.45 2024/01/07 07:58:33 isaki Exp $ */
2d21a1f43Sad
3d21a1f43Sad /*
4d21a1f43Sad * Copyright (c) 1982, 1990 The Regents of the University of California.
5d21a1f43Sad * All rights reserved.
6d21a1f43Sad *
7d21a1f43Sad * Redistribution and use in source and binary forms, with or without
8d21a1f43Sad * modification, are permitted provided that the following conditions
9d21a1f43Sad * are met:
10d21a1f43Sad * 1. Redistributions of source code must retain the above copyright
11d21a1f43Sad * notice, this list of conditions and the following disclaimer.
12d21a1f43Sad * 2. Redistributions in binary form must reproduce the above copyright
13d21a1f43Sad * notice, this list of conditions and the following disclaimer in the
14d21a1f43Sad * documentation and/or other materials provided with the distribution.
15d21a1f43Sad * 3. Neither the name of the University nor the names of its contributors
16d21a1f43Sad * may be used to endorse or promote products derived from this software
17d21a1f43Sad * without specific prior written permission.
18d21a1f43Sad *
19d21a1f43Sad * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20d21a1f43Sad * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21d21a1f43Sad * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22d21a1f43Sad * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23d21a1f43Sad * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24d21a1f43Sad * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25d21a1f43Sad * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26d21a1f43Sad * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27d21a1f43Sad * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28d21a1f43Sad * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29d21a1f43Sad * SUCH DAMAGE.
30d21a1f43Sad *
31d21a1f43Sad * @(#)ppi.c 7.3 (Berkeley) 12/16/90
32d21a1f43Sad */
33d21a1f43Sad
34d21a1f43Sad /*
35d21a1f43Sad * parallel port interface
36d21a1f43Sad */
37d21a1f43Sad
38d21a1f43Sad #include <sys/cdefs.h>
39*6b664a71Sisaki __KERNEL_RCSID(0, "$NetBSD: par.c,v 1.45 2024/01/07 07:58:33 isaki Exp $");
40d21a1f43Sad
41d21a1f43Sad #include <sys/param.h>
42d21a1f43Sad #include <sys/errno.h>
43d21a1f43Sad #include <sys/uio.h>
44d21a1f43Sad #include <sys/device.h>
45d21a1f43Sad #include <sys/malloc.h>
46d21a1f43Sad #include <sys/file.h>
47d21a1f43Sad #include <sys/systm.h>
48d21a1f43Sad #include <sys/callout.h>
49d21a1f43Sad #include <sys/proc.h>
50d21a1f43Sad #include <sys/conf.h>
51d21a1f43Sad #include <sys/kernel.h>
52d21a1f43Sad
53d21a1f43Sad #include <machine/bus.h>
54d21a1f43Sad #include <machine/cpu.h>
55d21a1f43Sad #include <machine/parioctl.h>
56d21a1f43Sad
57d21a1f43Sad #include <arch/x68k/dev/intiovar.h>
58d21a1f43Sad
59623e78a6Stsutsui #include "ioconf.h"
60623e78a6Stsutsui
61d21a1f43Sad struct par_softc {
622830b81aSisaki device_t sc_dev;
63d21a1f43Sad
64d21a1f43Sad bus_space_tag_t sc_bst;
65d21a1f43Sad bus_space_handle_t sc_bsh;
66d21a1f43Sad int sc_flags;
67d21a1f43Sad struct parparam sc_param;
68d21a1f43Sad #define sc_burst sc_param.burst
69d21a1f43Sad #define sc_timo sc_param.timo
70d21a1f43Sad #define sc_delay sc_param.delay
71d21a1f43Sad struct callout sc_timo_ch;
72d21a1f43Sad struct callout sc_start_ch;
73d21a1f43Sad } ;
74d21a1f43Sad
75d21a1f43Sad /* par registers */
76d21a1f43Sad #define PAR_DATA 1
77d21a1f43Sad #define PAR_STROBE 3
78d21a1f43Sad
79d21a1f43Sad /* sc_flags values */
80d21a1f43Sad #define PARF_ALIVE 0x01
81d21a1f43Sad #define PARF_OPEN 0x02
82d21a1f43Sad #define PARF_UIO 0x04
83d21a1f43Sad #define PARF_TIMO 0x08
84d21a1f43Sad #define PARF_DELAY 0x10
85d21a1f43Sad #define PARF_OREAD 0x40 /* no support */
86d21a1f43Sad #define PARF_OWRITE 0x80
87d21a1f43Sad
88d21a1f43Sad
89d21a1f43Sad void partimo(void *);
90d21a1f43Sad void parstart(void *);
91d21a1f43Sad void parintr(void *);
92d21a1f43Sad int parrw(dev_t, struct uio *);
93d21a1f43Sad int parhztoms(int);
94d21a1f43Sad int parmstohz(int);
95d21a1f43Sad int parsendch(struct par_softc *, u_char);
96d21a1f43Sad int parsend(struct par_softc *, u_char *, int);
97d21a1f43Sad
9861a446b0Sisaki static struct callout intr_callout;
99d21a1f43Sad
100d21a1f43Sad #define UNIT(x) minor(x)
101d21a1f43Sad
102d21a1f43Sad #ifdef DEBUG
103d21a1f43Sad #define PDB_FOLLOW 0x01
104d21a1f43Sad #define PDB_IO 0x02
105d21a1f43Sad #define PDB_INTERRUPT 0x04
106d21a1f43Sad #define PDB_NOCHECK 0x80
107d21a1f43Sad #ifdef PARDEBUG
108d21a1f43Sad int pardebug = PDB_FOLLOW | PDB_IO | PDB_INTERRUPT;
109d21a1f43Sad #else
110d21a1f43Sad int pardebug = 0;
111d21a1f43Sad #endif
112d21a1f43Sad #endif
113d21a1f43Sad
1142830b81aSisaki int parmatch(device_t, cfdata_t, void *);
1152830b81aSisaki void parattach(device_t, device_t, void *);
116d21a1f43Sad
1172830b81aSisaki CFATTACH_DECL_NEW(par, sizeof(struct par_softc),
118d21a1f43Sad parmatch, parattach, NULL, NULL);
119d21a1f43Sad
120d21a1f43Sad static int par_attached;
121d21a1f43Sad
122d21a1f43Sad dev_type_open(paropen);
123d21a1f43Sad dev_type_close(parclose);
124d21a1f43Sad dev_type_write(parwrite);
125d21a1f43Sad dev_type_ioctl(parioctl);
126d21a1f43Sad
127d21a1f43Sad const struct cdevsw par_cdevsw = {
128a68f9396Sdholland .d_open = paropen,
129a68f9396Sdholland .d_close = parclose,
130a68f9396Sdholland .d_read = noread,
131a68f9396Sdholland .d_write = parwrite,
132a68f9396Sdholland .d_ioctl = parioctl,
133a68f9396Sdholland .d_stop = nostop,
134a68f9396Sdholland .d_tty = notty,
135a68f9396Sdholland .d_poll = nopoll,
136a68f9396Sdholland .d_mmap = nommap,
137a68f9396Sdholland .d_kqfilter = nokqfilter,
138f9228f42Sdholland .d_discard = nodiscard,
139a68f9396Sdholland .d_flag = 0
140d21a1f43Sad };
141d21a1f43Sad
142d21a1f43Sad int
parmatch(device_t parent,cfdata_t cf,void * aux)1430c3cdf00Stsutsui parmatch(device_t parent, cfdata_t cf, void *aux)
144d21a1f43Sad {
145d21a1f43Sad struct intio_attach_args *ia = aux;
146d21a1f43Sad
147d21a1f43Sad /* X680x0 has only one parallel port */
148d21a1f43Sad if (strcmp(ia->ia_name, "par") || par_attached)
149d21a1f43Sad return 0;
150d21a1f43Sad
151d21a1f43Sad if (ia->ia_addr == INTIOCF_ADDR_DEFAULT)
152d21a1f43Sad ia->ia_addr = 0xe8c000;
153d21a1f43Sad ia->ia_size = 0x2000;
1540c3cdf00Stsutsui if (intio_map_allocate_region(parent, ia, INTIO_MAP_TESTONLY))
155d21a1f43Sad return 0;
156d21a1f43Sad if (ia->ia_intr == INTIOCF_INTR_DEFAULT)
157d21a1f43Sad ia->ia_intr = 99;
158d21a1f43Sad #if DIAGNOSTIC
159d21a1f43Sad if (ia->ia_intr != 99)
160d21a1f43Sad return 0;
161d21a1f43Sad #endif
162d21a1f43Sad
163d21a1f43Sad return 1;
164d21a1f43Sad }
165d21a1f43Sad
166d21a1f43Sad void
parattach(device_t parent,device_t self,void * aux)1670c3cdf00Stsutsui parattach(device_t parent, device_t self, void *aux)
168d21a1f43Sad {
1690c3cdf00Stsutsui struct par_softc *sc = device_private(self);
170d21a1f43Sad struct intio_attach_args *ia = aux;
1714c3cdcf0Schristos int r __diagused;
172d21a1f43Sad
173d21a1f43Sad par_attached = 1;
174d21a1f43Sad
1750c3cdf00Stsutsui sc->sc_dev = self;
176d21a1f43Sad sc->sc_flags = PARF_ALIVE;
1772830b81aSisaki aprint_normal(": parallel port (write only, interrupt)\n");
178d21a1f43Sad ia->ia_size = 0x2000;
1790c3cdf00Stsutsui r = intio_map_allocate_region(parent, ia, INTIO_MAP_ALLOCATE);
180d21a1f43Sad #ifdef DIAGNOSTIC
181d21a1f43Sad if (r)
182d21a1f43Sad panic("IO map for PAR corruption??");
183d21a1f43Sad #endif
184d21a1f43Sad sc->sc_bst = ia->ia_bst;
185d21a1f43Sad r = bus_space_map(sc->sc_bst,
186d21a1f43Sad ia->ia_addr, ia->ia_size,
187d21a1f43Sad BUS_SPACE_MAP_SHIFTED,
188d21a1f43Sad &sc->sc_bsh);
189d21a1f43Sad #ifdef DIAGNOSTIC
190d21a1f43Sad if (r)
191d21a1f43Sad panic("Cannot map IO space for PAR.");
192d21a1f43Sad #endif
193d21a1f43Sad
194d21a1f43Sad intio_set_sicilian_intr(intio_get_sicilian_intr() &
195d21a1f43Sad ~SICILIAN_INTR_PAR);
196d21a1f43Sad
197d21a1f43Sad intio_intr_establish(ia->ia_intr, "par",
198d21a1f43Sad (intio_intr_handler_t)parintr, (void *)1);
199d21a1f43Sad
200d21a1f43Sad callout_init(&sc->sc_timo_ch, 0);
201d21a1f43Sad callout_init(&sc->sc_start_ch, 0);
20261a446b0Sisaki callout_init(&intr_callout, 0);
203d21a1f43Sad }
204d21a1f43Sad
205d21a1f43Sad int
paropen(dev_t dev,int flags,int mode,struct lwp * l)206d21a1f43Sad paropen(dev_t dev, int flags, int mode, struct lwp *l)
207d21a1f43Sad {
208d21a1f43Sad int unit = UNIT(dev);
209d21a1f43Sad struct par_softc *sc;
210d21a1f43Sad
21140b72ee8Stsutsui sc = device_lookup_private(&par_cd, unit);
212d21a1f43Sad if (sc == NULL || !(sc->sc_flags & PARF_ALIVE))
213d21a1f43Sad return(ENXIO);
214d21a1f43Sad if (sc->sc_flags & PARF_OPEN)
215d21a1f43Sad return(EBUSY);
216d21a1f43Sad /* X680x0 can't read */
217d21a1f43Sad if ((flags & FREAD) == FREAD)
218d21a1f43Sad return (EINVAL);
219d21a1f43Sad
220d21a1f43Sad sc->sc_flags |= PARF_OPEN;
221d21a1f43Sad
222d21a1f43Sad sc->sc_flags |= PARF_OWRITE;
223d21a1f43Sad
224d21a1f43Sad sc->sc_burst = PAR_BURST;
225d21a1f43Sad sc->sc_timo = parmstohz(PAR_TIMO);
226d21a1f43Sad sc->sc_delay = parmstohz(PAR_DELAY);
227d21a1f43Sad
228d21a1f43Sad return(0);
229d21a1f43Sad }
230d21a1f43Sad
231d21a1f43Sad int
parclose(dev_t dev,int flags,int mode,struct lwp * l)232d21a1f43Sad parclose(dev_t dev, int flags, int mode, struct lwp *l)
233d21a1f43Sad {
234d21a1f43Sad int unit = UNIT(dev);
235d21a1f43Sad int s;
23640b72ee8Stsutsui struct par_softc *sc = device_lookup_private(&par_cd, unit);
237d21a1f43Sad
238d21a1f43Sad sc->sc_flags &= ~(PARF_OPEN|PARF_OWRITE);
239d21a1f43Sad
240d21a1f43Sad /* don't allow interrupts any longer */
241d21a1f43Sad s = spl1();
242d21a1f43Sad intio_set_sicilian_intr(intio_get_sicilian_intr() &
243d21a1f43Sad ~SICILIAN_INTR_PAR);
244d21a1f43Sad splx(s);
245d21a1f43Sad
246d21a1f43Sad return (0);
247d21a1f43Sad }
248d21a1f43Sad
249d21a1f43Sad void
parstart(void * arg)250d21a1f43Sad parstart(void *arg)
251d21a1f43Sad {
252d21a1f43Sad struct par_softc *sc = arg;
253d21a1f43Sad #ifdef DEBUG
254d21a1f43Sad if (pardebug & PDB_FOLLOW)
2552830b81aSisaki printf("parstart(%x)\n", device_unit(sc->sc_dev));
256d21a1f43Sad #endif
257d21a1f43Sad sc->sc_flags &= ~PARF_DELAY;
258d21a1f43Sad wakeup(sc);
259d21a1f43Sad }
260d21a1f43Sad
261d21a1f43Sad void
partimo(void * arg)262d21a1f43Sad partimo(void *arg)
263d21a1f43Sad {
264d21a1f43Sad struct par_softc *sc = arg;
265d21a1f43Sad #ifdef DEBUG
266d21a1f43Sad if (pardebug & PDB_FOLLOW)
2672830b81aSisaki printf("partimo(%x)\n", device_unit(sc->sc_dev));
268d21a1f43Sad #endif
269d21a1f43Sad sc->sc_flags &= ~(PARF_UIO|PARF_TIMO);
270d21a1f43Sad wakeup(sc);
271d21a1f43Sad }
272d21a1f43Sad
273d21a1f43Sad int
parwrite(dev_t dev,struct uio * uio,int flag)274d21a1f43Sad parwrite(dev_t dev, struct uio *uio, int flag)
275d21a1f43Sad {
276d21a1f43Sad
277d21a1f43Sad #ifdef DEBUG
278d21a1f43Sad if (pardebug & PDB_FOLLOW)
2798cf7d2d7Sisaki printf("parwrite(%x, %p)\n", UNIT(dev), uio);
280d21a1f43Sad #endif
281d21a1f43Sad return (parrw(dev, uio));
282d21a1f43Sad }
283d21a1f43Sad
284d21a1f43Sad int
parrw(dev_t dev,struct uio * uio)285d21a1f43Sad parrw(dev_t dev, struct uio *uio)
286d21a1f43Sad {
287d21a1f43Sad int unit = UNIT(dev);
28840b72ee8Stsutsui struct par_softc *sc = device_lookup_private(&par_cd, unit);
289d21a1f43Sad int len=0xdeadbeef; /* XXX: shutup gcc */
290d21a1f43Sad int s, cnt=0;
291d21a1f43Sad char *cp;
292d21a1f43Sad int error = 0;
293d21a1f43Sad int buflen;
294d21a1f43Sad char *buf;
295d21a1f43Sad
296d21a1f43Sad if (!!(sc->sc_flags & PARF_OREAD) ^ (uio->uio_rw == UIO_READ))
297d21a1f43Sad return EINVAL;
298d21a1f43Sad
299d21a1f43Sad if (uio->uio_resid == 0)
300d21a1f43Sad return(0);
301d21a1f43Sad
302d1579b2dSriastradh buflen = uimin(sc->sc_burst, uio->uio_resid);
303d21a1f43Sad buf = (char *)malloc(buflen, M_DEVBUF, M_WAITOK);
304d21a1f43Sad sc->sc_flags |= PARF_UIO;
305d21a1f43Sad if (sc->sc_timo > 0) {
306d21a1f43Sad sc->sc_flags |= PARF_TIMO;
307d21a1f43Sad callout_reset(&sc->sc_timo_ch, sc->sc_timo, partimo, sc);
308d21a1f43Sad }
309d21a1f43Sad while (uio->uio_resid > 0) {
310d1579b2dSriastradh len = uimin(buflen, uio->uio_resid);
311d21a1f43Sad cp = buf;
312d21a1f43Sad if (uio->uio_rw == UIO_WRITE) {
313d21a1f43Sad error = uiomove(cp, len, uio);
314d21a1f43Sad if (error)
315d21a1f43Sad break;
316d21a1f43Sad }
317d21a1f43Sad again:
318d21a1f43Sad s = splsoftclock();
319d21a1f43Sad /*
320d21a1f43Sad * Check if we timed out during sleep or uiomove
321d21a1f43Sad */
322d21a1f43Sad if ((sc->sc_flags & PARF_UIO) == 0) {
323d21a1f43Sad #ifdef DEBUG
324d21a1f43Sad if (pardebug & PDB_IO)
325d21a1f43Sad printf("parrw: uiomove/sleep timo, flags %x\n",
326d21a1f43Sad sc->sc_flags);
327d21a1f43Sad #endif
328d21a1f43Sad if (sc->sc_flags & PARF_TIMO) {
329d21a1f43Sad callout_stop(&sc->sc_timo_ch);
330d21a1f43Sad sc->sc_flags &= ~PARF_TIMO;
331d21a1f43Sad }
332d21a1f43Sad splx(s);
333d21a1f43Sad break;
334d21a1f43Sad }
335d21a1f43Sad splx(s);
336d21a1f43Sad /*
337d21a1f43Sad * Perform the operation
338d21a1f43Sad */
339d21a1f43Sad cnt = parsend(sc, cp, len);
340d21a1f43Sad if (cnt < 0) {
341d21a1f43Sad error = -cnt;
342d21a1f43Sad break;
343d21a1f43Sad }
344d21a1f43Sad
345d21a1f43Sad s = splsoftclock();
346d21a1f43Sad /*
347d21a1f43Sad * Operation timeout (or non-blocking), quit now.
348d21a1f43Sad */
349d21a1f43Sad if ((sc->sc_flags & PARF_UIO) == 0) {
350d21a1f43Sad #ifdef DEBUG
351d21a1f43Sad if (pardebug & PDB_IO)
352d21a1f43Sad printf("parrw: timeout/done\n");
353d21a1f43Sad #endif
354d21a1f43Sad splx(s);
355d21a1f43Sad break;
356d21a1f43Sad }
357d21a1f43Sad /*
358d21a1f43Sad * Implement inter-read delay
359d21a1f43Sad */
360d21a1f43Sad if (sc->sc_delay > 0) {
361d21a1f43Sad sc->sc_flags |= PARF_DELAY;
362d21a1f43Sad callout_reset(&sc->sc_start_ch, sc->sc_delay,
363d21a1f43Sad parstart, sc);
364d21a1f43Sad error = tsleep(sc, PCATCH|(PZERO-1), "par-cdelay", 0);
365d21a1f43Sad if (error) {
366d21a1f43Sad splx(s);
367d21a1f43Sad break;
368d21a1f43Sad }
369d21a1f43Sad }
370d21a1f43Sad splx(s);
371d21a1f43Sad /*
372d21a1f43Sad * Must not call uiomove again til we've used all data
373d21a1f43Sad * that we already grabbed.
374d21a1f43Sad */
375d21a1f43Sad if (uio->uio_rw == UIO_WRITE && cnt != len) {
376d21a1f43Sad cp += cnt;
377d21a1f43Sad len -= cnt;
378d21a1f43Sad cnt = 0;
379d21a1f43Sad goto again;
380d21a1f43Sad }
381d21a1f43Sad }
382d21a1f43Sad s = splsoftclock();
383d21a1f43Sad if (sc->sc_flags & PARF_TIMO) {
384d21a1f43Sad callout_stop(&sc->sc_timo_ch);
385d21a1f43Sad sc->sc_flags &= ~PARF_TIMO;
386d21a1f43Sad }
387d21a1f43Sad if (sc->sc_flags & PARF_DELAY) {
388d21a1f43Sad callout_stop(&sc->sc_start_ch);
389d21a1f43Sad sc->sc_flags &= ~PARF_DELAY;
390d21a1f43Sad }
391d21a1f43Sad splx(s);
392d21a1f43Sad /*
393d21a1f43Sad * Adjust for those chars that we uiomove'ed but never wrote
394d21a1f43Sad */
395d21a1f43Sad /*
396d21a1f43Sad * XXXjdolecek: this len usage is wrong, this will be incorrect
397d21a1f43Sad * if the transfer size is longer than sc_burst
398d21a1f43Sad */
399d21a1f43Sad if (uio->uio_rw == UIO_WRITE && cnt != len) {
400d21a1f43Sad uio->uio_resid += (len - cnt);
401d21a1f43Sad #ifdef DEBUG
402d21a1f43Sad if (pardebug & PDB_IO)
403d21a1f43Sad printf("parrw: short write, adjust by %d\n",
404d21a1f43Sad len-cnt);
405d21a1f43Sad #endif
406d21a1f43Sad }
407d21a1f43Sad free(buf, M_DEVBUF);
408d21a1f43Sad #ifdef DEBUG
409d21a1f43Sad if (pardebug & (PDB_FOLLOW|PDB_IO))
410d21a1f43Sad printf("parrw: return %d, resid %d\n", error, uio->uio_resid);
411d21a1f43Sad #endif
412d21a1f43Sad return (error);
413d21a1f43Sad }
414d21a1f43Sad
415d21a1f43Sad int
parioctl(dev_t dev,u_long cmd,void * data,int flag,struct lwp * l)416d21a1f43Sad parioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
417d21a1f43Sad {
41840b72ee8Stsutsui struct par_softc *sc = device_lookup_private(&par_cd, UNIT(dev));
419d21a1f43Sad struct parparam *pp, *upp;
420d21a1f43Sad int error = 0;
421d21a1f43Sad
422d21a1f43Sad switch (cmd) {
423d21a1f43Sad case PARIOCGPARAM:
424d21a1f43Sad pp = &sc->sc_param;
425d21a1f43Sad upp = (struct parparam *)data;
426d21a1f43Sad upp->burst = pp->burst;
427d21a1f43Sad upp->timo = parhztoms(pp->timo);
428d21a1f43Sad upp->delay = parhztoms(pp->delay);
429d21a1f43Sad break;
430d21a1f43Sad
431d21a1f43Sad case PARIOCSPARAM:
432d21a1f43Sad pp = &sc->sc_param;
433d21a1f43Sad upp = (struct parparam *)data;
434d21a1f43Sad if (upp->burst < PAR_BURST_MIN || upp->burst > PAR_BURST_MAX ||
435d21a1f43Sad upp->delay < PAR_DELAY_MIN || upp->delay > PAR_DELAY_MAX)
436d21a1f43Sad return(EINVAL);
437d21a1f43Sad pp->burst = upp->burst;
438d21a1f43Sad pp->timo = parmstohz(upp->timo);
439d21a1f43Sad pp->delay = parmstohz(upp->delay);
440d21a1f43Sad break;
441d21a1f43Sad
442d21a1f43Sad default:
443d21a1f43Sad return(EINVAL);
444d21a1f43Sad }
445d21a1f43Sad return (error);
446d21a1f43Sad }
447d21a1f43Sad
448d21a1f43Sad int
parhztoms(int h)449d21a1f43Sad parhztoms(int h)
450d21a1f43Sad {
451d21a1f43Sad int m = h;
452d21a1f43Sad
453d21a1f43Sad if (m > 0)
454d21a1f43Sad m = m * 1000 / hz;
455d21a1f43Sad return(m);
456d21a1f43Sad }
457d21a1f43Sad
458d21a1f43Sad int
parmstohz(int m)459d21a1f43Sad parmstohz(int m)
460d21a1f43Sad {
461d21a1f43Sad int h = m;
462d21a1f43Sad
463d21a1f43Sad if (h > 0) {
464d21a1f43Sad h = h * hz / 1000;
465d21a1f43Sad if (h == 0)
466d21a1f43Sad h = 1000 / hz;
467d21a1f43Sad }
468d21a1f43Sad return(h);
469d21a1f43Sad }
470d21a1f43Sad
471d21a1f43Sad /* stuff below here if for interrupt driven output of data thru
472d21a1f43Sad the parallel port. */
473d21a1f43Sad
474d21a1f43Sad int partimeout_pending;
475d21a1f43Sad int parsend_pending;
476d21a1f43Sad
477d21a1f43Sad void
parintr(void * arg)478d21a1f43Sad parintr(void *arg)
479d21a1f43Sad {
480d21a1f43Sad int s, mask;
481d21a1f43Sad
482d21a1f43Sad mask = (int)arg;
483d21a1f43Sad s = splclock();
484d21a1f43Sad
485d21a1f43Sad intio_set_sicilian_intr(intio_get_sicilian_intr() &
486d21a1f43Sad ~SICILIAN_INTR_PAR);
487d21a1f43Sad
488d21a1f43Sad #ifdef DEBUG
489d21a1f43Sad if (pardebug & PDB_INTERRUPT)
490d21a1f43Sad printf("parintr %d(%s)\n", mask, mask ? "FLG" : "tout");
491d21a1f43Sad #endif
492d21a1f43Sad /* if invoked from timeout handler, mask will be 0,
493d21a1f43Sad * if from interrupt, it will contain the cia-icr mask,
494d21a1f43Sad * which is != 0
495d21a1f43Sad */
496d21a1f43Sad if (mask) {
497d21a1f43Sad if (partimeout_pending)
498d21a1f43Sad callout_stop(&intr_callout);
499d21a1f43Sad if (parsend_pending)
500d21a1f43Sad parsend_pending = 0;
501d21a1f43Sad }
502d21a1f43Sad
503d21a1f43Sad /* either way, there won't be a timeout pending any longer */
504d21a1f43Sad partimeout_pending = 0;
505d21a1f43Sad
506d21a1f43Sad wakeup(parintr);
507d21a1f43Sad splx(s);
508d21a1f43Sad }
509d21a1f43Sad
510d21a1f43Sad int
parsendch(struct par_softc * sc,u_char ch)511d21a1f43Sad parsendch(struct par_softc *sc, u_char ch)
512d21a1f43Sad {
513d21a1f43Sad int error = 0;
514d21a1f43Sad int s;
515d21a1f43Sad
516d21a1f43Sad /* if either offline, busy or out of paper, wait for that
517d21a1f43Sad condition to clear */
518d21a1f43Sad s = spl1();
519d21a1f43Sad while (!error
520d21a1f43Sad && (parsend_pending
521d21a1f43Sad || !(intio_get_sicilian_intr() & SICILIAN_STAT_PAR)))
522d21a1f43Sad {
523d21a1f43Sad /* wait a second, and try again */
524d21a1f43Sad callout_reset(&intr_callout, hz, parintr, 0);
525d21a1f43Sad partimeout_pending = 1;
526d21a1f43Sad /* this is essentially a flipflop to have us wait for the
527d21a1f43Sad first character being transmitted when trying to transmit
528d21a1f43Sad the second, etc. */
529d21a1f43Sad parsend_pending = 0;
530d21a1f43Sad /* it's quite important that a parallel putc can be
531d21a1f43Sad interrupted, given the possibility to lock a printer
532d21a1f43Sad in an offline condition.. */
533d21a1f43Sad if ((error = tsleep(parintr, PCATCH|(PZERO-1), "parsendch", 0))) {
534d21a1f43Sad #ifdef DEBUG
535d21a1f43Sad if (pardebug & PDB_INTERRUPT)
536d21a1f43Sad printf("parsendch interrupted, error = %d\n", error);
537d21a1f43Sad #endif
538d21a1f43Sad if (partimeout_pending)
539d21a1f43Sad callout_stop(&intr_callout);
540d21a1f43Sad
541d21a1f43Sad partimeout_pending = 0;
542d21a1f43Sad }
543d21a1f43Sad }
544d21a1f43Sad
545d21a1f43Sad if (!error) {
546d21a1f43Sad #ifdef DEBUG
547d21a1f43Sad if (pardebug & PDB_INTERRUPT)
548d21a1f43Sad printf("#%d", ch);
549d21a1f43Sad #endif
550d21a1f43Sad bus_space_write_1(sc->sc_bst, sc->sc_bsh, PAR_DATA, ch);
551d21a1f43Sad DELAY(1); /* (DELAY(1) == 1us) > 0.5us */
552d21a1f43Sad bus_space_write_1(sc->sc_bst, sc->sc_bsh, PAR_STROBE, 0);
553d21a1f43Sad intio_set_sicilian_intr(intio_get_sicilian_intr() |
554d21a1f43Sad SICILIAN_INTR_PAR);
555d21a1f43Sad DELAY(1);
556d21a1f43Sad bus_space_write_1(sc->sc_bst, sc->sc_bsh, PAR_STROBE, 1);
557d21a1f43Sad parsend_pending = 1;
558d21a1f43Sad }
559d21a1f43Sad
560d21a1f43Sad splx(s);
561d21a1f43Sad
562d21a1f43Sad return error;
563d21a1f43Sad }
564d21a1f43Sad
565d21a1f43Sad
566d21a1f43Sad int
parsend(struct par_softc * sc,u_char * buf,int len)567d21a1f43Sad parsend(struct par_softc *sc, u_char *buf, int len)
568d21a1f43Sad {
569d21a1f43Sad int err, orig_len = len;
570d21a1f43Sad
571d21a1f43Sad for (; len; len--, buf++)
572d21a1f43Sad if ((err = parsendch(sc, *buf)))
573d21a1f43Sad return err < 0 ? -EINTR : -err;
574d21a1f43Sad
575d21a1f43Sad /* either all or nothing.. */
576d21a1f43Sad return orig_len;
577d21a1f43Sad }
578