Annotation of src/sys/dev/sbus/bpp.c, Revision 1.4.2.1
1.4.2.1 ! mrg 1: /* $NetBSD$ */
1.1 pk 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/param.h>
40: #include <sys/ioctl.h>
41: #include <sys/fcntl.h>
42: #include <sys/systm.h>
43: #include <sys/kernel.h>
44: #include <sys/vnode.h>
45: #include <sys/poll.h>
46: #include <sys/select.h>
47: #include <sys/malloc.h>
48: #include <sys/proc.h>
49: #include <sys/signalvar.h>
50: #include <sys/conf.h>
51: #include <sys/errno.h>
52: #include <sys/device.h>
53:
54: #include <machine/bus.h>
1.4.2.1 ! mrg 55: #include <machine/intr.h>
1.1 pk 56: #include <machine/autoconf.h>
1.4.2.1 ! mrg 57: #include <machine/conf.h>
1.1 pk 58:
59: #include <dev/ic/lsi64854reg.h>
60: #include <dev/ic/lsi64854var.h>
61:
62: #include <dev/sbus/sbusvar.h>
63: #include <dev/sbus/bppreg.h>
64:
65: #define splbpp() spltty() /* XXX */
66:
67: #if 0
68: struct bpp_param {
69: int bpp_dss; /* data setup to strobe */
70: int bpp_dsw; /* data strobe width */
71: int bpp_outputpins; /* Select/Autofeed/Init pins */
72: int bpp_inputpins; /* Error/Select/Paperout pins */
73: };
74: #endif
75:
76: struct hwstate {
77: u_int16_t hw_hcr; /* Hardware config register */
78: u_int16_t hw_ocr; /* Operation config register */
79: u_int8_t hw_tcr; /* Transfer Control register */
80: u_int8_t hw_or; /* Output register */
81: u_int16_t hw_irq; /* IRQ; polarity bits only */
82: };
83:
84: struct bpp_softc {
85: struct lsi64854_softc sc_lsi64854; /* base device */
86: struct sbusdev sc_sd; /* sbus device */
87:
88: size_t sc_bufsz; /* temp buffer */
89: caddr_t sc_buf;
90:
91: int sc_error; /* bottom-half error */
92: int sc_flags;
93: #define BPP_OPEN 0x01 /* Device is open */
94: #define BPP_XCLUDE 0x02 /* Exclusive-open mode */
95: #define BPP_ASYNC 0x04 /* Asynchronous I/O mode */
96: #define BPP_LOCKED 0x08 /* DMA in progress */
97: #define BPP_WANT 0x10 /* Waiting for DMA */
98:
99: struct selinfo sc_rsel;
100: struct selinfo sc_wsel;
101: struct proc *sc_asyncproc; /* Process to notify if async */
102:
103: /* Hardware state */
104: struct hwstate sc_hwdefault;
105: struct hwstate sc_hwcurrent;
106: };
107:
108: static int bppmatch __P((struct device *, struct cfdata *, void *));
109: static void bppattach __P((struct device *, struct device *, void *));
110: static int bppintr __P((void *));
111: static void bpp_setparams __P((struct bpp_softc *, struct hwstate *));
112:
113: struct cfattach bpp_ca = {
114: sizeof(struct bpp_softc), bppmatch, bppattach
115: };
116:
117: extern struct cfdriver bpp_cd;
118: #define BPPUNIT(dev) (minor(dev))
119:
120:
121: int
122: bppmatch(parent, cf, aux)
123: struct device *parent;
124: struct cfdata *cf;
125: void *aux;
126: {
127: struct sbus_attach_args *sa = aux;
128:
129: return (strcmp("SUNW,bpp", sa->sa_name) == 0);
130: }
131:
132: void
133: bppattach(parent, self, aux)
134: struct device *parent, *self;
135: void *aux;
136: {
137: struct sbus_attach_args *sa = aux;
138: struct bpp_softc *dsc = (void *)self;
139: struct lsi64854_softc *sc = &dsc->sc_lsi64854;
140: int burst, sbusburst;
141: int node;
142:
143: sc->sc_bustag = sa->sa_bustag;
144: sc->sc_dmatag = sa->sa_dmatag;
145: node = sa->sa_node;
146:
147: /* Map device registers */
148: if (bus_space_map2(sa->sa_bustag,
149: sa->sa_slot,
150: sa->sa_offset,
151: sa->sa_size,
152: BUS_SPACE_MAP_LINEAR,
153: 0, &sc->sc_regs) != 0) {
154: printf("%s: cannot map registers\n", self->dv_xname);
155: return;
156: }
157:
158: /*
159: * Get transfer burst size from PROM and plug it into the
160: * controller registers. This is needed on the Sun4m; do
161: * others need it too?
162: */
163: sbusburst = ((struct sbus_softc *)parent)->sc_burst;
164: if (sbusburst == 0)
165: sbusburst = SBUS_BURST_32 - 1; /* 1->16 */
166:
167: burst = getpropint(node, "burst-sizes", -1);
168: if (burst == -1)
169: /* take SBus burst sizes */
170: burst = sbusburst;
171:
172: /* Clamp at parent's burst sizes */
173: burst &= sbusburst;
174: sc->sc_burst = (burst & SBUS_BURST_32) ? 32 :
175: (burst & SBUS_BURST_16) ? 16 : 0;
176:
177: /* Join the Sbus device family */
178: dsc->sc_sd.sd_reset = (void *)0;
179: sbus_establish(&dsc->sc_sd, self);
180:
181: /* Initialize the DMA channel */
182: sc->sc_channel = L64854_CHANNEL_PP;
183: lsi64854_attach(sc);
184:
1.3 pk 185: /* Establish interrupt handler */
186: if (sa->sa_nintr) {
187: sc->sc_intrchain = bppintr;
188: sc->sc_intrchainarg = dsc;
1.4.2.1 ! mrg 189: (void)bus_intr_establish(sa->sa_bustag, sa->sa_pri, IPL_TTY, 0,
1.3 pk 190: lsi64854_pp_intr, sc);
191: }
1.1 pk 192:
193: /* Allocate buffer XXX - should actually use dmamap_uio() */
194: dsc->sc_bufsz = 1024;
195: dsc->sc_buf = malloc(dsc->sc_bufsz, M_DEVBUF, M_NOWAIT);
196:
197: /* XXX read default state */
198: {
199: bus_space_handle_t h = sc->sc_regs;
200: struct hwstate *hw = &dsc->sc_hwdefault;
201: hw->hw_hcr = bus_space_read_2(sc->sc_bustag, h, L64854_REG_HCR);
202: hw->hw_ocr = bus_space_read_2(sc->sc_bustag, h, L64854_REG_OCR);
203: hw->hw_tcr = bus_space_read_1(sc->sc_bustag, h, L64854_REG_TCR);
204: hw->hw_or = bus_space_read_1(sc->sc_bustag, h, L64854_REG_OR);
205: }
206: }
207:
208: void
209: bpp_setparams(sc, hw)
210: struct bpp_softc *sc;
211: struct hwstate *hw;
212: {
213: u_int16_t irq;
214: bus_space_tag_t t = sc->sc_lsi64854.sc_bustag;
215: bus_space_handle_t h = sc->sc_lsi64854.sc_regs;
216:
217: bus_space_write_2(t, h, L64854_REG_HCR, hw->hw_hcr);
218: bus_space_write_2(t, h, L64854_REG_OCR, hw->hw_ocr);
219: bus_space_write_1(t, h, L64854_REG_TCR, hw->hw_tcr);
220: bus_space_write_1(t, h, L64854_REG_OR, hw->hw_or);
221:
222: /* Only change IRP settings in interrupt status register */
223: irq = bus_space_read_2(t, h, L64854_REG_ICR);
224: irq &= ~BPP_ALLIRP;
225: irq |= (hw->hw_irq & BPP_ALLIRP);
226: bus_space_write_2(t, h, L64854_REG_ICR, irq);
227: }
228:
229: int
230: bppopen(dev, flags, mode, p)
231: dev_t dev;
232: int flags, mode;
233: struct proc *p;
234: {
235: int unit = BPPUNIT(dev);
236: struct bpp_softc *sc;
237: struct lsi64854_softc *lsi;
238: u_int16_t irq;
239: int s;
240:
241: if (unit >= bpp_cd.cd_ndevs)
242: return (ENXIO);
243: sc = bpp_cd.cd_devs[unit];
244:
245: if ((sc->sc_flags & (BPP_OPEN|BPP_XCLUDE)) == (BPP_OPEN|BPP_XCLUDE))
246: return (EBUSY);
247:
248: lsi = &sc->sc_lsi64854;
249:
250: /* Set default parameters */
251: sc->sc_hwcurrent = sc->sc_hwdefault;
252: s = splbpp();
253: bpp_setparams(sc, &sc->sc_hwdefault);
254: splx(s);
255:
256: /* Enable interrupts */
257: irq = BPP_ALLEN;
258: irq |= sc->sc_hwdefault.hw_irq;
259: bus_space_write_2(lsi->sc_bustag, lsi->sc_regs, L64854_REG_ICR, irq);
260: return (0);
261: }
262:
263: int
264: bppclose(dev, flags, mode, p)
265: dev_t dev;
266: int flags, mode;
267: struct proc *p;
268: {
269: struct bpp_softc *sc = bpp_cd.cd_devs[BPPUNIT(dev)];
270: struct lsi64854_softc *lsi = &sc->sc_lsi64854;
271: u_int16_t irq;
272:
273: /* Turn off all interrupt enables */
274: irq = sc->sc_hwdefault.hw_irq | BPP_ALLIRQ;
275: irq &= ~BPP_ALLEN;
276: bus_space_write_2(lsi->sc_bustag, lsi->sc_regs, L64854_REG_ICR, irq);
277:
278: sc->sc_asyncproc = NULL;
279: sc->sc_flags = 0;
280: return (0);
281: }
282:
283: int
284: bppread(dev, uio, flags)
285: dev_t dev;
286: struct uio *uio;
287: int flags;
288: {
289:
290: return (ENXIO);
291: }
292:
293: int
294: bppwrite(dev, uio, flags)
295: dev_t dev;
296: struct uio *uio;
297: int flags;
298: {
299: struct bpp_softc *sc = bpp_cd.cd_devs[BPPUNIT(dev)];
300: struct lsi64854_softc *lsi = &sc->sc_lsi64854;
301: int error = 0;
302: int s;
303:
304: /*
1.4 pk 305: * Wait until the DMA engine is free.
1.1 pk 306: */
307: s = splbpp();
308: while ((sc->sc_flags & BPP_LOCKED) != 0) {
309: if ((flags & IO_NDELAY) != 0) {
310: splx(s);
311: return (EWOULDBLOCK);
312: }
313:
314: sc->sc_flags |= BPP_WANT;
315: error = tsleep(sc->sc_buf, PZERO|PCATCH, "bppwrite", 0);
316: if (error != 0) {
317: splx(s);
318: return (error);
319: }
320: }
321: sc->sc_flags |= BPP_LOCKED;
322: splx(s);
323:
324: /*
325: * Move data from user space into our private buffer
326: * and start DMA.
327: */
328: while (uio->uio_resid > 0) {
329: caddr_t bp = sc->sc_buf;
330: size_t len = min(sc->sc_bufsz, uio->uio_resid);
331:
332: if ((error = uiomove(bp, len, uio)) != 0)
333: break;
334:
335: while (len > 0) {
336: u_int8_t tcr;
337: size_t size = len;
338: DMA_SETUP(lsi, &bp, &len, 0, &size);
339:
340: /* Clear direction control bit */
341: tcr = bus_space_read_1(lsi->sc_bustag, lsi->sc_regs,
342: L64854_REG_TCR);
343: tcr &= ~BPP_TCR_DIR;
1.2 pk 344: bus_space_write_1(lsi->sc_bustag, lsi->sc_regs,
345: L64854_REG_TCR, tcr);
1.1 pk 346:
347: /* Enable DMA */
1.4 pk 348: s = splbpp();
1.1 pk 349: DMA_GO(lsi);
350: error = tsleep(sc, PZERO|PCATCH, "bppdma", 0);
1.4 pk 351: splx(s);
1.1 pk 352: if (error != 0)
353: goto out;
354:
355: /* Bail out if bottom half reported an error */
356: if ((error = sc->sc_error) != 0)
357: goto out;
1.4 pk 358:
359: len -= size;
1.1 pk 360: }
361: }
362:
363: out:
364: s = splbpp();
365: sc->sc_flags &= ~BPP_LOCKED;
366: if ((sc->sc_flags & BPP_WANT) != 0) {
367: sc->sc_flags &= ~BPP_WANT;
368: wakeup(sc->sc_buf);
369: }
370: splx(s);
371: return (error);
372: }
373:
374: /* move to header: */
375: #define BPPIOCSPARAM _IOW('P', 0x1, struct hwstate)
376: #define BPPIOCGPARAM _IOR('P', 0x2, struct hwstate)
377:
378: int
379: bppioctl(dev, cmd, data, flag, p)
380: dev_t dev;
381: u_long cmd;
382: caddr_t data;
383: int flag;
384: struct proc *p;
385: {
386: struct bpp_softc *sc = bpp_cd.cd_devs[BPPUNIT(dev)];
387: struct hwstate *hw, *chw;
388: int error = 0;
389: int s;
390:
391: switch(cmd) {
392: case BPPIOCSPARAM:
393: chw = &sc->sc_hwcurrent;
394: hw = (struct hwstate *)data;
395:
396: /*
397: * Extract and store user-settable bits.
398: */
399: #define _bpp_set(reg,mask) do { \
400: chw->reg &= ~(mask); \
401: chw->reg |= (hw->reg & (mask)); \
402: } while (0)
403: _bpp_set(hw_hcr, BPP_HCR_DSS_MASK|BPP_HCR_DSW_MASK);
404: _bpp_set(hw_ocr, BPP_OCR_USER);
405: _bpp_set(hw_tcr, BPP_TCR_USER);
406: _bpp_set(hw_or, BPP_OR_USER);
407: _bpp_set(hw_irq, BPP_IRQ_USER);
408: #undef _bpp_set
409:
410: /* Apply settings */
411: s = splbpp();
412: bpp_setparams(sc, chw);
413: splx(s);
414: break;
415: case BPPIOCGPARAM:
416: *((struct hwstate *)data) = sc->sc_hwcurrent;
417: break;
418: case TIOCEXCL:
419: s = splbpp();
420: sc->sc_flags |= BPP_XCLUDE;
421: splx(s);
422: break;
423: case TIOCNXCL:
424: s = splbpp();
425: sc->sc_flags &= ~BPP_XCLUDE;
426: splx(s);
427: break;
428: case FIOASYNC:
429: s = splbpp();
430: if (*(int *)data) {
431: if (sc->sc_asyncproc != NULL)
432: error = EBUSY;
433: else
434: sc->sc_asyncproc = p;
435: } else
436: sc->sc_asyncproc = NULL;
437: splx(s);
438: break;
439: default:
440: break;
441: }
442:
443: return (error);
444: }
445:
446: int
447: bpppoll(dev, events, p)
448: dev_t dev;
449: int events;
450: struct proc *p;
451: {
452: struct bpp_softc *sc = bpp_cd.cd_devs[BPPUNIT(dev)];
453: int revents = 0;
454:
455: if (events & (POLLIN | POLLRDNORM)) {
456: /* read is not yet implemented */
457: }
458:
459: if (events & (POLLOUT | POLLWRNORM)) {
460: if ((sc->sc_flags & BPP_LOCKED) == 0)
461: revents |= (POLLOUT | POLLWRNORM);
462: }
463:
464: if (revents == 0) {
465: if (events & (POLLIN | POLLRDNORM))
466: selrecord(p, &sc->sc_rsel);
467: if (events & (POLLOUT | POLLWRNORM))
468: selrecord(p, &sc->sc_wsel);
469: }
470:
471: return (revents);
472: }
473:
474: int
475: bppintr(arg)
476: void *arg;
477: {
478: struct bpp_softc *sc = arg;
479: struct lsi64854_softc *lsi = &sc->sc_lsi64854;
480: u_int16_t irq;
481:
482: irq = bus_space_read_2(lsi->sc_bustag, lsi->sc_regs, L64854_REG_ICR);
483: /* Ack all interrupts */
484: bus_space_write_2(lsi->sc_bustag, lsi->sc_regs, L64854_REG_ICR,
485: irq | BPP_ALLIRQ);
486:
487: /* Did our device interrupt? */
488: if ((irq & BPP_ALLIRQ) == 0)
489: return (0);
490:
491: if ((sc->sc_flags & BPP_LOCKED) != 0)
492: wakeup(sc);
493: else if ((sc->sc_flags & BPP_WANT) != 0) {
494: sc->sc_flags &= ~BPP_WANT;
495: wakeup(sc->sc_buf);
496: } else {
497: selwakeup(&sc->sc_wsel);
498: if (sc->sc_asyncproc != NULL)
499: psignal(sc->sc_asyncproc, SIGIO);
500: }
501: return (1);
502: }
CVSweb <webmaster@jp.NetBSD.org>