[BACK]Return to bpp.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / dev / sbus

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>