bpp.c revision 1.37 1 /* $NetBSD: bpp.c,v 1.37 2008/04/24 15:35:28 ad Exp $ */
2
3 /*-
4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Paul Kranenburg.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: bpp.c,v 1.37 2008/04/24 15:35:28 ad Exp $");
41
42 #include <sys/param.h>
43 #include <sys/ioctl.h>
44 #include <sys/fcntl.h>
45 #include <sys/systm.h>
46 #include <sys/kernel.h>
47 #include <sys/vnode.h>
48 #include <sys/poll.h>
49 #include <sys/select.h>
50 #include <sys/malloc.h>
51 #include <sys/proc.h>
52 #include <sys/signalvar.h>
53 #include <sys/conf.h>
54 #include <sys/errno.h>
55 #include <sys/device.h>
56 #include <sys/bus.h>
57 #include <sys/intr.h>
58
59 #include <machine/autoconf.h>
60
61 #include <dev/ic/lsi64854reg.h>
62 #include <dev/ic/lsi64854var.h>
63
64 #include <dev/sbus/sbusvar.h>
65 #include <dev/sbus/bppreg.h>
66
67 #include "ioconf.h"
68
69 #define splbpp() spltty() /* XXX */
70
71 #ifdef DEBUG
72 #define DPRINTF(x) do { if (bppdebug) printf x ; } while (0)
73 int bppdebug = 1;
74 #else
75 #define DPRINTF(x)
76 #endif
77
78 #if 0
79 struct bpp_param {
80 int bpp_dss; /* data setup to strobe */
81 int bpp_dsw; /* data strobe width */
82 int bpp_outputpins; /* Select/Autofeed/Init pins */
83 int bpp_inputpins; /* Error/Select/Paperout pins */
84 };
85 #endif
86
87 struct hwstate {
88 uint16_t hw_hcr; /* Hardware config register */
89 uint16_t hw_ocr; /* Operation config register */
90 uint8_t hw_tcr; /* Transfer Control register */
91 uint8_t hw_or; /* Output register */
92 uint16_t hw_irq; /* IRQ; polarity bits only */
93 };
94
95 struct bpp_softc {
96 struct lsi64854_softc sc_lsi64854; /* base device */
97 struct sbusdev sc_sd; /* sbus device */
98
99 size_t sc_bufsz; /* temp buffer */
100 uint8_t *sc_buf;
101
102 int sc_error; /* bottom-half error */
103 int sc_flags;
104 #define BPP_OPEN 0x01 /* Device is open */
105 #define BPP_XCLUDE 0x02 /* Exclusive-open mode */
106 #define BPP_ASYNC 0x04 /* Asynchronous I/O mode */
107 #define BPP_LOCKED 0x08 /* DMA in progress */
108 #define BPP_WANT 0x10 /* Waiting for DMA */
109
110 struct selinfo sc_rsel;
111 struct selinfo sc_wsel;
112 struct proc *sc_asyncproc; /* Process to notify if async */
113 void *sc_sih;
114
115 /* Hardware state */
116 struct hwstate sc_hwdefault;
117 struct hwstate sc_hwcurrent;
118 };
119
120 static int bppmatch(device_t, cfdata_t, void *);
121 static void bppattach(device_t, device_t, void *);
122 static int bppintr(void *);
123 static void bppsoftintr(void *);
124 static void bpp_setparams(struct bpp_softc *, struct hwstate *);
125
126 CFATTACH_DECL_NEW(bpp, sizeof(struct bpp_softc),
127 bppmatch, bppattach, NULL, NULL);
128
129 dev_type_open(bppopen);
130 dev_type_close(bppclose);
131 dev_type_write(bppwrite);
132 dev_type_ioctl(bppioctl);
133 dev_type_poll(bpppoll);
134 dev_type_kqfilter(bppkqfilter);
135
136 const struct cdevsw bpp_cdevsw = {
137 bppopen, bppclose, noread, bppwrite, bppioctl,
138 nostop, notty, bpppoll, nommap, bppkqfilter, D_TTY
139 };
140
141 #define BPPUNIT(dev) (minor(dev))
142
143
144 int
145 bppmatch(device_t parent, cfdata_t cf, void *aux)
146 {
147 struct sbus_attach_args *sa = aux;
148
149 return strcmp("SUNW,bpp", sa->sa_name) == 0;
150 }
151
152 void
153 bppattach(device_t parent, device_t self, void *aux)
154 {
155 struct bpp_softc *dsc = device_private(self);
156 struct lsi64854_softc *sc = &dsc->sc_lsi64854;
157 struct sbus_softc *sbsc = device_private(parent);
158 struct sbus_attach_args *sa = aux;
159 int burst, sbusburst;
160 int node;
161
162 sc->sc_dev = self;
163
164 selinit(&dsc->sc_rsel);
165 selinit(&dsc->sc_wsel);
166 dsc->sc_sih = softint_establish(SOFTINT_CLOCK, bppsoftintr, dsc);
167
168 sc->sc_bustag = sa->sa_bustag;
169 sc->sc_dmatag = sa->sa_dmatag;
170 node = sa->sa_node;
171
172 /* Map device registers */
173 if (sbus_bus_map(sa->sa_bustag,
174 sa->sa_slot, sa->sa_offset, sa->sa_size,
175 0, &sc->sc_regs) != 0) {
176 aprint_error(": cannot map registers\n");
177 return;
178 }
179
180 /*
181 * Get transfer burst size from PROM and plug it into the
182 * controller registers. This is needed on the Sun4m; do
183 * others need it too?
184 */
185 sbusburst = sbsc->sc_burst;
186 if (sbusburst == 0)
187 sbusburst = SBUS_BURST_32 - 1; /* 1->16 */
188
189 burst = prom_getpropint(node, "burst-sizes", -1);
190 if (burst == -1)
191 /* take SBus burst sizes */
192 burst = sbusburst;
193
194 /* Clamp at parent's burst sizes */
195 burst &= sbusburst;
196 sc->sc_burst = (burst & SBUS_BURST_32) ? 32 :
197 (burst & SBUS_BURST_16) ? 16 : 0;
198
199 /* Join the Sbus device family */
200 dsc->sc_sd.sd_reset = NULL;
201 sbus_establish(&dsc->sc_sd, self);
202
203 /* Initialize the DMA channel */
204 sc->sc_channel = L64854_CHANNEL_PP;
205 lsi64854_attach(sc);
206
207 /* Establish interrupt handler */
208 if (sa->sa_nintr) {
209 sc->sc_intrchain = bppintr;
210 sc->sc_intrchainarg = dsc;
211 (void)bus_intr_establish(sa->sa_bustag, sa->sa_pri, IPL_TTY,
212 bppintr, sc);
213 }
214
215 /* Allocate buffer XXX - should actually use dmamap_uio() */
216 dsc->sc_bufsz = 1024;
217 dsc->sc_buf = malloc(dsc->sc_bufsz, M_DEVBUF, M_NOWAIT);
218
219 /* XXX read default state */
220 {
221 bus_space_handle_t h = sc->sc_regs;
222 struct hwstate *hw = &dsc->sc_hwdefault;
223 int ack_rate = sa->sa_frequency / 1000000;
224
225 hw->hw_hcr = bus_space_read_2(sc->sc_bustag, h, L64854_REG_HCR);
226 hw->hw_ocr = bus_space_read_2(sc->sc_bustag, h, L64854_REG_OCR);
227 hw->hw_tcr = bus_space_read_1(sc->sc_bustag, h, L64854_REG_TCR);
228 hw->hw_or = bus_space_read_1(sc->sc_bustag, h, L64854_REG_OR);
229
230 DPRINTF(("bpp: hcr %x ocr %x tcr %x or %x\n",
231 hw->hw_hcr, hw->hw_ocr, hw->hw_tcr, hw->hw_or));
232 /* Set these to sane values */
233 hw->hw_hcr = ((ack_rate<<BPP_HCR_DSS_SHFT)&BPP_HCR_DSS_MASK)
234 | ((ack_rate<<BPP_HCR_DSW_SHFT)&BPP_HCR_DSW_MASK);
235 hw->hw_ocr |= BPP_OCR_ACK_OP;
236 }
237 }
238
239 void
240 bpp_setparams(struct bpp_softc *sc, struct hwstate *hw)
241 {
242 uint16_t irq;
243 bus_space_tag_t t = sc->sc_lsi64854.sc_bustag;
244 bus_space_handle_t h = sc->sc_lsi64854.sc_regs;
245
246 bus_space_write_2(t, h, L64854_REG_HCR, hw->hw_hcr);
247 bus_space_write_2(t, h, L64854_REG_OCR, hw->hw_ocr);
248 bus_space_write_1(t, h, L64854_REG_TCR, hw->hw_tcr);
249 bus_space_write_1(t, h, L64854_REG_OR, hw->hw_or);
250
251 /* Only change IRP settings in interrupt status register */
252 irq = bus_space_read_2(t, h, L64854_REG_ICR);
253 irq &= ~BPP_ALLIRP;
254 irq |= (hw->hw_irq & BPP_ALLIRP);
255 bus_space_write_2(t, h, L64854_REG_ICR, irq);
256 DPRINTF(("bpp_setparams: hcr %x ocr %x tcr %x or %x, irq %x\n",
257 hw->hw_hcr, hw->hw_ocr, hw->hw_tcr, hw->hw_or, irq));
258 }
259
260 int
261 bppopen(dev_t dev, int flags, int mode, struct lwp *l)
262 {
263 int unit = BPPUNIT(dev);
264 struct bpp_softc *sc;
265 struct lsi64854_softc *lsi;
266 uint16_t irq;
267 int s;
268
269 if (unit >= bpp_cd.cd_ndevs)
270 return ENXIO;
271 sc = device_lookup_private(&bpp_cd, unit);
272
273 if ((sc->sc_flags & (BPP_OPEN|BPP_XCLUDE)) == (BPP_OPEN|BPP_XCLUDE))
274 return EBUSY;
275
276 lsi = &sc->sc_lsi64854;
277
278 /* Set default parameters */
279 sc->sc_hwcurrent = sc->sc_hwdefault;
280 s = splbpp();
281 bpp_setparams(sc, &sc->sc_hwdefault);
282 splx(s);
283
284 /* Enable interrupts */
285 irq = BPP_ERR_IRQ_EN;
286 irq |= sc->sc_hwdefault.hw_irq;
287 bus_space_write_2(lsi->sc_bustag, lsi->sc_regs, L64854_REG_ICR, irq);
288 return 0;
289 }
290
291 int
292 bppclose(dev_t dev, int flags, int mode, struct lwp *l)
293 {
294 struct bpp_softc *sc;
295 struct lsi64854_softc *lsi;
296 uint16_t irq;
297
298 sc = device_lookup_private(&bpp_cd, BPPUNIT(dev));
299 lsi = &sc->sc_lsi64854;
300
301 /* Turn off all interrupt enables */
302 irq = sc->sc_hwdefault.hw_irq | BPP_ALLIRQ;
303 irq &= ~BPP_ALLEN;
304 bus_space_write_2(lsi->sc_bustag, lsi->sc_regs, L64854_REG_ICR, irq);
305
306 mutex_enter(proc_lock);
307 sc->sc_asyncproc = NULL;
308 mutex_exit(proc_lock);
309 sc->sc_flags = 0;
310 return 0;
311 }
312
313 int
314 bppwrite(dev_t dev, struct uio *uio, int flags)
315 {
316 struct bpp_softc *sc;
317 struct lsi64854_softc *lsi;
318 int error = 0;
319 int s;
320
321 sc = device_lookup_private(&bpp_cd, BPPUNIT(dev));
322 lsi = &sc->sc_lsi64854;
323
324 /*
325 * Wait until the DMA engine is free.
326 */
327 s = splbpp();
328 while ((sc->sc_flags & BPP_LOCKED) != 0) {
329 if ((flags & IO_NDELAY) != 0) {
330 splx(s);
331 return EWOULDBLOCK;
332 }
333
334 sc->sc_flags |= BPP_WANT;
335 error = tsleep(sc->sc_buf, PZERO|PCATCH, "bppwrite", 0);
336 if (error != 0) {
337 splx(s);
338 return error;
339 }
340 }
341 sc->sc_flags |= BPP_LOCKED;
342 splx(s);
343
344 /*
345 * Move data from user space into our private buffer
346 * and start DMA.
347 */
348 while (uio->uio_resid > 0) {
349 uint8_t *bp = sc->sc_buf;
350 size_t len = min(sc->sc_bufsz, uio->uio_resid);
351
352 if ((error = uiomove(bp, len, uio)) != 0)
353 break;
354
355 while (len > 0) {
356 uint8_t tcr;
357 size_t size = len;
358 DMA_SETUP(lsi, &bp, &len, 0, &size);
359
360 #ifdef DEBUG
361 if (bppdebug) {
362 int i;
363 uint8_t *b = bp;
364 printf("bpp: writing %ld : ", len);
365 for (i = 0; i < len; i++)
366 printf("%c(0x%x)", b[i], b[i]);
367 printf("\n");
368 }
369 #endif
370
371 /* Clear direction control bit */
372 tcr = bus_space_read_1(lsi->sc_bustag, lsi->sc_regs,
373 L64854_REG_TCR);
374 tcr &= ~BPP_TCR_DIR;
375 bus_space_write_1(lsi->sc_bustag, lsi->sc_regs,
376 L64854_REG_TCR, tcr);
377
378 /* Enable DMA */
379 s = splbpp();
380 DMA_GO(lsi);
381 error = tsleep(sc, PZERO|PCATCH, "bppdma", 0);
382 splx(s);
383 if (error != 0)
384 goto out;
385
386 /* Bail out if bottom half reported an error */
387 if ((error = sc->sc_error) != 0)
388 goto out;
389
390 /*
391 * lsi64854_pp_intr() does this part.
392 *
393 * len -= size;
394 */
395 }
396 }
397
398 out:
399 DPRINTF(("bpp done %x\n", error));
400 s = splbpp();
401 sc->sc_flags &= ~BPP_LOCKED;
402 if ((sc->sc_flags & BPP_WANT) != 0) {
403 sc->sc_flags &= ~BPP_WANT;
404 wakeup(sc->sc_buf);
405 }
406 splx(s);
407 return error;
408 }
409
410 /* move to header: */
411 #define BPPIOCSPARAM _IOW('P', 0x1, struct hwstate)
412 #define BPPIOCGPARAM _IOR('P', 0x2, struct hwstate)
413
414 int
415 bppioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
416 {
417 struct bpp_softc *sc;
418 struct proc *p = l->l_proc;
419 struct hwstate *hw, *chw;
420 int error = 0;
421 int s;
422
423 sc = device_lookup_private(&bpp_cd, BPPUNIT(dev));
424
425 switch(cmd) {
426 case BPPIOCSPARAM:
427 chw = &sc->sc_hwcurrent;
428 hw = (struct hwstate *)data;
429
430 /*
431 * Extract and store user-settable bits.
432 */
433 #define _bpp_set(reg,mask) do { \
434 chw->reg &= ~(mask); \
435 chw->reg |= (hw->reg & (mask)); \
436 } while (/* CONSTCOND */ 0)
437 _bpp_set(hw_hcr, BPP_HCR_DSS_MASK|BPP_HCR_DSW_MASK);
438 _bpp_set(hw_ocr, BPP_OCR_USER);
439 _bpp_set(hw_tcr, BPP_TCR_USER);
440 _bpp_set(hw_or, BPP_OR_USER);
441 _bpp_set(hw_irq, BPP_IRQ_USER);
442 #undef _bpp_set
443
444 /* Apply settings */
445 s = splbpp();
446 bpp_setparams(sc, chw);
447 splx(s);
448 break;
449 case BPPIOCGPARAM:
450 *((struct hwstate *)data) = sc->sc_hwcurrent;
451 break;
452 case TIOCEXCL:
453 s = splbpp();
454 sc->sc_flags |= BPP_XCLUDE;
455 splx(s);
456 break;
457 case TIOCNXCL:
458 s = splbpp();
459 sc->sc_flags &= ~BPP_XCLUDE;
460 splx(s);
461 break;
462 case FIOASYNC:
463 mutex_enter(proc_lock);
464 if (*(int *)data) {
465 if (sc->sc_asyncproc != NULL)
466 error = EBUSY;
467 else
468 sc->sc_asyncproc = p;
469 } else
470 sc->sc_asyncproc = NULL;
471 mutex_exit(proc_lock);
472 break;
473 default:
474 break;
475 }
476
477 return error;
478 }
479
480 int
481 bpppoll(dev_t dev, int events, struct lwp *l)
482 {
483 struct bpp_softc *sc;
484 int revents = 0;
485
486 sc = device_lookup_private(&bpp_cd, BPPUNIT(dev));
487
488 if (events & (POLLIN | POLLRDNORM)) {
489 /* read is not yet implemented */
490 }
491
492 if (events & (POLLOUT | POLLWRNORM)) {
493 if ((sc->sc_flags & BPP_LOCKED) == 0)
494 revents |= (POLLOUT | POLLWRNORM);
495 }
496
497 if (revents == 0) {
498 if (events & (POLLIN | POLLRDNORM))
499 selrecord(l, &sc->sc_rsel);
500 if (events & (POLLOUT | POLLWRNORM))
501 selrecord(l, &sc->sc_wsel);
502 }
503
504 return revents;
505 }
506
507 static void
508 filt_bpprdetach(struct knote *kn)
509 {
510 struct bpp_softc *sc = kn->kn_hook;
511 int s;
512
513 s = splbpp();
514 SLIST_REMOVE(&sc->sc_rsel.sel_klist, kn, knote, kn_selnext);
515 splx(s);
516 }
517
518 static int
519 filt_bppread(struct knote *kn, long hint)
520 {
521 /* XXX Read not yet implemented. */
522 return 0;
523 }
524
525 static const struct filterops bppread_filtops =
526 { 1, NULL, filt_bpprdetach, filt_bppread };
527
528 static void
529 filt_bppwdetach(struct knote *kn)
530 {
531 struct bpp_softc *sc = kn->kn_hook;
532 int s;
533
534 s = splbpp();
535 SLIST_REMOVE(&sc->sc_wsel.sel_klist, kn, knote, kn_selnext);
536 splx(s);
537 }
538
539 static int
540 filt_bpfwrite(struct knote *kn, long hint)
541 {
542 struct bpp_softc *sc = kn->kn_hook;
543
544 if (sc->sc_flags & BPP_LOCKED)
545 return 0;
546
547 kn->kn_data = 0; /* XXXLUKEM (thorpej): what to put here? */
548 return 1;
549 }
550
551 static const struct filterops bppwrite_filtops =
552 { 1, NULL, filt_bppwdetach, filt_bpfwrite };
553
554 int
555 bppkqfilter(dev_t dev, struct knote *kn)
556 {
557 struct bpp_softc *sc;
558 struct klist *klist;
559 int s;
560
561 sc = device_lookup_private(&bpp_cd, BPPUNIT(dev));
562
563 switch (kn->kn_filter) {
564 case EVFILT_READ:
565 klist = &sc->sc_rsel.sel_klist;
566 kn->kn_fop = &bppread_filtops;
567 break;
568
569 case EVFILT_WRITE:
570 klist = &sc->sc_wsel.sel_klist;
571 kn->kn_fop = &bppwrite_filtops;
572 break;
573
574 default:
575 return EINVAL;
576 }
577
578 kn->kn_hook = sc;
579
580 s = splbpp();
581 SLIST_INSERT_HEAD(klist, kn, kn_selnext);
582 splx(s);
583
584 return 0;
585 }
586
587 int
588 bppintr(void *arg)
589 {
590 struct bpp_softc *sc = arg;
591 struct lsi64854_softc *lsi = &sc->sc_lsi64854;
592 uint16_t irq;
593
594 /* First handle any possible DMA interrupts */
595 if (lsi64854_pp_intr((void *)lsi) == -1)
596 sc->sc_error = 1;
597
598 irq = bus_space_read_2(lsi->sc_bustag, lsi->sc_regs, L64854_REG_ICR);
599 /* Ack all interrupts */
600 bus_space_write_2(lsi->sc_bustag, lsi->sc_regs, L64854_REG_ICR,
601 irq | BPP_ALLIRQ);
602
603 DPRINTF(("%s: %x\n", __func__, irq));
604 /* Did our device interrupt? */
605 if ((irq & BPP_ALLIRQ) == 0)
606 return 0;
607
608 if ((sc->sc_flags & BPP_LOCKED) != 0)
609 wakeup(sc);
610 else if ((sc->sc_flags & BPP_WANT) != 0) {
611 sc->sc_flags &= ~BPP_WANT;
612 wakeup(sc->sc_buf);
613 } else {
614 selnotify(&sc->sc_wsel, 0, 0);
615 if (sc->sc_asyncproc != NULL)
616 softint_schedule(sc->sc_sih);
617 }
618 return 1;
619 }
620
621 static void
622 bppsoftintr(void *cookie)
623 {
624 struct bpp_softc *sc = cookie;
625
626 mutex_enter(proc_lock);
627 if (sc->sc_asyncproc)
628 psignal(sc->sc_asyncproc, SIGIO);
629 mutex_exit(proc_lock);
630 }
631