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