root/dev/sbus/bpp.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. bppmatch
  2. bppattach
  3. bpp_setparams
  4. bppopen
  5. bppclose
  6. bppwrite
  7. bppioctl
  8. bppintr

    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 }

/* [<][>][^][v][top][bottom][index][help] */