Annotation of sys/dev/sbus/bpp.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: bpp.c,v 1.1 2007/02/28 18:48:35 miod Exp $ */
! 2: /* $NetBSD: bpp.c,v 1.25 2005/12/11 12:23:44 christos Exp $ */
! 3:
! 4: /*-
! 5: * Copyright (c) 1998 The NetBSD Foundation, Inc.
! 6: * All rights reserved.
! 7: *
! 8: * This code is derived from software contributed to The NetBSD Foundation
! 9: * by Paul Kranenburg.
! 10: *
! 11: * Redistribution and use in source and binary forms, with or without
! 12: * modification, are permitted provided that the following conditions
! 13: * are met:
! 14: * 1. Redistributions of source code must retain the above copyright
! 15: * notice, this list of conditions and the following disclaimer.
! 16: * 2. Redistributions in binary form must reproduce the above copyright
! 17: * notice, this list of conditions and the following disclaimer in the
! 18: * documentation and/or other materials provided with the distribution.
! 19: * 3. All advertising materials mentioning features or use of this software
! 20: * must display the following acknowledgement:
! 21: * This product includes software developed by the NetBSD
! 22: * Foundation, Inc. and its contributors.
! 23: * 4. Neither the name of The NetBSD Foundation nor the names of its
! 24: * contributors may be used to endorse or promote products derived
! 25: * from this software without specific prior written permission.
! 26: *
! 27: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
! 28: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 29: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 30: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
! 31: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 32: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 33: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 34: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 35: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 36: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 37: * POSSIBILITY OF SUCH DAMAGE.
! 38: */
! 39:
! 40: #include <sys/param.h>
! 41: #include <sys/ioctl.h>
! 42: #include <sys/systm.h>
! 43: #include <sys/kernel.h>
! 44: #include <sys/errno.h>
! 45: #include <sys/device.h>
! 46: #include <sys/malloc.h>
! 47: #include <sys/proc.h>
! 48: #include <sys/vnode.h>
! 49: #include <sys/conf.h>
! 50:
! 51: #include <machine/autoconf.h>
! 52: #include <machine/bus.h>
! 53: #include <machine/conf.h>
! 54: #include <machine/intr.h>
! 55:
! 56: #include <dev/ic/lsi64854reg.h>
! 57: #include <dev/ic/lsi64854var.h>
! 58:
! 59: #include <dev/sbus/sbusvar.h>
! 60: #include <dev/sbus/bppreg.h>
! 61:
! 62: #define splbpp() spltty() /* XXX */
! 63:
! 64: #ifdef DEBUG
! 65: #define DPRINTF(x) do { if (bppdebug) printf x ; } while (0)
! 66: int bppdebug = 1;
! 67: #else
! 68: #define DPRINTF(x)
! 69: #endif
! 70:
! 71: #if 0
! 72: struct bpp_param {
! 73: int bpp_dss; /* data setup to strobe */
! 74: int bpp_dsw; /* data strobe width */
! 75: int bpp_outputpins; /* Select/Autofeed/Init pins */
! 76: int bpp_inputpins; /* Error/Select/Paperout pins */
! 77: };
! 78: #endif
! 79:
! 80: struct hwstate {
! 81: u_int16_t hw_hcr; /* Hardware config register */
! 82: u_int16_t hw_ocr; /* Operation config register */
! 83: u_int8_t hw_tcr; /* Transfer Control register */
! 84: u_int8_t hw_or; /* Output register */
! 85: u_int16_t hw_irq; /* IRQ; polarity bits only */
! 86: };
! 87:
! 88: struct bpp_softc {
! 89: struct lsi64854_softc sc_lsi64854; /* base device */
! 90:
! 91: size_t sc_bufsz; /* temp buffer */
! 92: caddr_t sc_buf;
! 93:
! 94: int sc_error; /* bottom-half error */
! 95: int sc_flags;
! 96: #define BPP_LOCKED 0x01 /* DMA in progress */
! 97: #define BPP_WANT 0x02 /* Waiting for DMA */
! 98:
! 99: /* Hardware state */
! 100: struct hwstate sc_hwstate;
! 101: };
! 102:
! 103: int bppmatch(struct device *, void *, void *);
! 104: void bppattach(struct device *, struct device *, void *);
! 105: int bppintr (void *);
! 106: void bpp_setparams(struct bpp_softc *, struct hwstate *);
! 107:
! 108: const struct cfattach bpp_ca = {
! 109: sizeof(struct bpp_softc), bppmatch, bppattach
! 110: };
! 111:
! 112: struct cfdriver bpp_cd = {
! 113: NULL, "bpp", DV_DULL
! 114: };
! 115:
! 116: #define BPPUNIT(dev) (minor(dev))
! 117:
! 118: int
! 119: bppmatch(struct device *parent, void *vcf, void *aux)
! 120: {
! 121: struct sbus_attach_args *sa = aux;
! 122:
! 123: return (strcmp("SUNW,bpp", sa->sa_name) == 0);
! 124: }
! 125:
! 126: void
! 127: bppattach(struct device *parent, struct device *self, void *aux)
! 128: {
! 129: struct sbus_attach_args *sa = aux;
! 130: struct bpp_softc *dsc = (void *)self;
! 131: struct lsi64854_softc *sc = &dsc->sc_lsi64854;
! 132: int burst, sbusburst;
! 133: int node;
! 134:
! 135: node = sa->sa_node;
! 136:
! 137: sc->sc_bustag = sa->sa_bustag;
! 138: sc->sc_dmatag = sa->sa_dmatag;
! 139:
! 140: /* Map device registers */
! 141: if (sa->sa_npromvaddrs != 0) {
! 142: if (sbus_bus_map(sa->sa_bustag, 0, sa->sa_promvaddrs[0],
! 143: sa->sa_size, /* ???? */
! 144: BUS_SPACE_MAP_PROMADDRESS, 0, &sc->sc_regs) != 0) {
! 145: printf(": cannot map registers\n", self->dv_xname);
! 146: return;
! 147: }
! 148: } else if (sbus_bus_map(sa->sa_bustag, sa->sa_slot, sa->sa_offset,
! 149: sa->sa_size, 0, 0, &sc->sc_regs) != 0) {
! 150: printf(": cannot map registers\n", self->dv_xname);
! 151: return;
! 152: }
! 153:
! 154: /* Check for the interrupt property */
! 155: if (sa->sa_nintr == 0) {
! 156: printf(": no interrupt property\n");
! 157: return;
! 158: }
! 159:
! 160: /*
! 161: * Get transfer burst size from PROM and plug it into the
! 162: * controller registers. This is needed on the Sun4m; do
! 163: * others need it too?
! 164: */
! 165: sbusburst = ((struct sbus_softc *)parent)->sc_burst;
! 166: if (sbusburst == 0)
! 167: sbusburst = SBUS_BURST_32 - 1; /* 1->16 */
! 168:
! 169: burst = getpropint(node, "burst-sizes", -1);
! 170: if (burst == -1)
! 171: /* take SBus burst sizes */
! 172: burst = sbusburst;
! 173:
! 174: /* Clamp at parent's burst sizes */
! 175: burst &= sbusburst;
! 176: sc->sc_burst = (burst & SBUS_BURST_32) ? 32 :
! 177: (burst & SBUS_BURST_16) ? 16 : 0;
! 178:
! 179: /* Initialize the DMA channel */
! 180: sc->sc_channel = L64854_CHANNEL_PP;
! 181: if (lsi64854_attach(sc) != 0)
! 182: return;
! 183:
! 184: /* Establish interrupt handler */
! 185: sc->sc_intrchain = bppintr;
! 186: sc->sc_intrchainarg = dsc;
! 187: (void)bus_intr_establish(sa->sa_bustag, sa->sa_pri, IPL_TTY, 0,
! 188: bppintr, sc, self->dv_xname);
! 189:
! 190: /* Allocate buffer XXX - should actually use dmamap_uio() */
! 191: dsc->sc_bufsz = 1024;
! 192: dsc->sc_buf = malloc(dsc->sc_bufsz, M_DEVBUF, M_NOWAIT);
! 193:
! 194: /* XXX read default state */
! 195: {
! 196: bus_space_handle_t h = sc->sc_regs;
! 197: struct hwstate *hw = &dsc->sc_hwstate;
! 198: int ack_rate = sa->sa_frequency/1000000;
! 199:
! 200: hw->hw_hcr = bus_space_read_2(sc->sc_bustag, h, L64854_REG_HCR);
! 201: hw->hw_ocr = bus_space_read_2(sc->sc_bustag, h, L64854_REG_OCR);
! 202: hw->hw_tcr = bus_space_read_1(sc->sc_bustag, h, L64854_REG_TCR);
! 203: hw->hw_or = bus_space_read_1(sc->sc_bustag, h, L64854_REG_OR);
! 204:
! 205: DPRINTF(("bpp: hcr %x ocr %x tcr %x or %x\n",
! 206: hw->hw_hcr, hw->hw_ocr, hw->hw_tcr, hw->hw_or));
! 207: /* Set these to sane values */
! 208: hw->hw_hcr = ((ack_rate<<BPP_HCR_DSS_SHFT)&BPP_HCR_DSS_MASK)
! 209: | ((ack_rate<<BPP_HCR_DSW_SHFT)&BPP_HCR_DSW_MASK);
! 210: hw->hw_ocr |= BPP_OCR_ACK_OP;
! 211: }
! 212: }
! 213:
! 214: void
! 215: bpp_setparams(struct bpp_softc *sc, struct hwstate *hw)
! 216: {
! 217: u_int16_t irq;
! 218: bus_space_tag_t t = sc->sc_lsi64854.sc_bustag;
! 219: bus_space_handle_t h = sc->sc_lsi64854.sc_regs;
! 220:
! 221: bus_space_write_2(t, h, L64854_REG_HCR, hw->hw_hcr);
! 222: bus_space_write_2(t, h, L64854_REG_OCR, hw->hw_ocr);
! 223: bus_space_write_1(t, h, L64854_REG_TCR, hw->hw_tcr);
! 224: bus_space_write_1(t, h, L64854_REG_OR, hw->hw_or);
! 225:
! 226: /* Only change IRP settings in interrupt status register */
! 227: irq = bus_space_read_2(t, h, L64854_REG_ICR);
! 228: irq &= ~BPP_ALLIRP;
! 229: irq |= (hw->hw_irq & BPP_ALLIRP);
! 230: bus_space_write_2(t, h, L64854_REG_ICR, irq);
! 231: DPRINTF(("bpp_setparams: hcr %x ocr %x tcr %x or %x, irq %x\n",
! 232: hw->hw_hcr, hw->hw_ocr, hw->hw_tcr, hw->hw_or, irq));
! 233: }
! 234:
! 235: int
! 236: bppopen(dev_t dev, int flags, int mode, struct proc *p)
! 237: {
! 238: int unit = BPPUNIT(dev);
! 239: struct bpp_softc *sc;
! 240: struct lsi64854_softc *lsi;
! 241: u_int16_t irq;
! 242: int s;
! 243:
! 244: if (unit >= bpp_cd.cd_ndevs)
! 245: return (ENXIO);
! 246: if ((sc = bpp_cd.cd_devs[unit]) == NULL)
! 247: return (ENXIO);
! 248:
! 249: lsi = &sc->sc_lsi64854;
! 250:
! 251: /* Set default parameters */
! 252: s = splbpp();
! 253: bpp_setparams(sc, &sc->sc_hwstate);
! 254: splx(s);
! 255:
! 256: /* Enable interrupts */
! 257: irq = BPP_ERR_IRQ_EN;
! 258: irq |= sc->sc_hwstate.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_t dev, int flags, int mode, struct proc *p)
! 265: {
! 266: struct bpp_softc *sc = bpp_cd.cd_devs[BPPUNIT(dev)];
! 267: struct lsi64854_softc *lsi = &sc->sc_lsi64854;
! 268: u_int16_t irq;
! 269:
! 270: /* Turn off all interrupt enables */
! 271: irq = sc->sc_hwstate.hw_irq | BPP_ALLIRQ;
! 272: irq &= ~BPP_ALLEN;
! 273: bus_space_write_2(lsi->sc_bustag, lsi->sc_regs, L64854_REG_ICR, irq);
! 274:
! 275: sc->sc_flags = 0;
! 276: return (0);
! 277: }
! 278:
! 279: int
! 280: bppwrite(dev_t dev, struct uio *uio, int flags)
! 281: {
! 282: struct bpp_softc *sc = bpp_cd.cd_devs[BPPUNIT(dev)];
! 283: struct lsi64854_softc *lsi = &sc->sc_lsi64854;
! 284: int error = 0;
! 285: int s;
! 286:
! 287: /*
! 288: * Wait until the DMA engine is free.
! 289: */
! 290: s = splbpp();
! 291: while ((sc->sc_flags & BPP_LOCKED) != 0) {
! 292: if ((flags & IO_NDELAY) != 0) {
! 293: splx(s);
! 294: return (EWOULDBLOCK);
! 295: }
! 296:
! 297: sc->sc_flags |= BPP_WANT;
! 298: error = tsleep(sc->sc_buf, PZERO | PCATCH, "bppwrite", 0);
! 299: if (error != 0) {
! 300: splx(s);
! 301: return (error);
! 302: }
! 303: }
! 304: sc->sc_flags |= BPP_LOCKED;
! 305: splx(s);
! 306:
! 307: /*
! 308: * Move data from user space into our private buffer
! 309: * and start DMA.
! 310: */
! 311: while (uio->uio_resid > 0) {
! 312: caddr_t bp = sc->sc_buf;
! 313: size_t len = min(sc->sc_bufsz, uio->uio_resid);
! 314:
! 315: if ((error = uiomove(bp, len, uio)) != 0)
! 316: break;
! 317:
! 318: while (len > 0) {
! 319: u_int8_t tcr;
! 320: size_t size = len;
! 321: DMA_SETUP(lsi, &bp, &len, 0, &size);
! 322:
! 323: #ifdef DEBUG
! 324: if (bppdebug) {
! 325: int i;
! 326: printf("bpp: writing %ld : ", len);
! 327: for (i=0; i<len; i++) printf("%c(0x%x)", bp[i], bp[i]);
! 328: printf("\n");
! 329: }
! 330: #endif
! 331:
! 332: /* Clear direction control bit */
! 333: tcr = bus_space_read_1(lsi->sc_bustag, lsi->sc_regs,
! 334: L64854_REG_TCR);
! 335: tcr &= ~BPP_TCR_DIR;
! 336: bus_space_write_1(lsi->sc_bustag, lsi->sc_regs,
! 337: L64854_REG_TCR, tcr);
! 338:
! 339: /* Enable DMA */
! 340: s = splbpp();
! 341: DMA_GO(lsi);
! 342: error = tsleep(sc, PZERO | PCATCH, "bppdma", 0);
! 343: splx(s);
! 344: if (error != 0)
! 345: goto out;
! 346:
! 347: /* Bail out if bottom half reported an error */
! 348: if ((error = sc->sc_error) != 0)
! 349: goto out;
! 350:
! 351: /*
! 352: * DMA_INTR() does this part.
! 353: *
! 354: * len -= size;
! 355: */
! 356: }
! 357: }
! 358:
! 359: out:
! 360: DPRINTF(("bpp done %x\n", error));
! 361: s = splbpp();
! 362: sc->sc_flags &= ~BPP_LOCKED;
! 363: if ((sc->sc_flags & BPP_WANT) != 0) {
! 364: sc->sc_flags &= ~BPP_WANT;
! 365: wakeup(sc->sc_buf);
! 366: }
! 367: splx(s);
! 368: return (error);
! 369: }
! 370:
! 371: int
! 372: bppioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
! 373: {
! 374: int error = 0;
! 375:
! 376: switch(cmd) {
! 377: default:
! 378: error = ENODEV;
! 379: break;
! 380: }
! 381:
! 382: return (error);
! 383: }
! 384:
! 385: int
! 386: bppintr(void *arg)
! 387: {
! 388: struct bpp_softc *sc = arg;
! 389: struct lsi64854_softc *lsi = &sc->sc_lsi64854;
! 390: u_int16_t irq;
! 391:
! 392: /* First handle any possible DMA interrupts */
! 393: if (DMA_INTR(lsi) == -1)
! 394: sc->sc_error = 1;
! 395:
! 396: irq = bus_space_read_2(lsi->sc_bustag, lsi->sc_regs, L64854_REG_ICR);
! 397: /* Ack all interrupts */
! 398: bus_space_write_2(lsi->sc_bustag, lsi->sc_regs, L64854_REG_ICR,
! 399: irq | BPP_ALLIRQ);
! 400:
! 401: DPRINTF(("bpp_intr: %x\n", irq));
! 402: /* Did our device interrupt? */
! 403: if ((irq & BPP_ALLIRQ) == 0)
! 404: return (0);
! 405:
! 406: if ((sc->sc_flags & BPP_LOCKED) != 0)
! 407: wakeup(sc);
! 408: else if ((sc->sc_flags & BPP_WANT) != 0) {
! 409: sc->sc_flags &= ~BPP_WANT;
! 410: wakeup(sc->sc_buf);
! 411: }
! 412: return (1);
! 413: }
CVSweb