[BACK]Return to xlights.c CVS log [TXT][DIR] Up to [local] / sys / arch / macppc / dev

Annotation of sys/arch/macppc/dev/xlights.c, Revision 1.1.1.1

1.1       nbrk        1: /* $OpenBSD: xlights.c,v 1.3 2007/06/01 08:29:30 gwk Exp $ */
                      2: /*
                      3:  * Copyright (c) 2007 Gordon Willem Klok <gwk@openbsd,org>
                      4:  *
                      5:  * Permission to use, copy, modify, and distribute this software for any
                      6:  * purpose with or without fee is hereby granted, provided that the above
                      7:  * copyright notice and this permission notice appear in all copies.
                      8:  *
                      9:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                     10:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     11:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     12:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     13:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     14:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     15:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     16:  */
                     17: #include <sys/types.h>
                     18: #include <sys/param.h>
                     19: #include <sys/systm.h>
                     20: #include <sys/proc.h>
                     21: #include <sys/device.h>
                     22: #include <sys/kthread.h>
                     23: #include <sys/timeout.h>
                     24: #include <dev/ofw/openfirm.h>
                     25:
                     26: #include <machine/bus.h>
                     27: #include <machine/autoconf.h>
                     28: #include <macppc/dev/dbdma.h>
                     29: #include <macppc/dev/i2sreg.h>
                     30:
                     31: struct xlights_softc {
                     32:        struct device                   sc_dev;
                     33:        int                             sc_node;
                     34:        int                             sc_intr;
                     35:        uint32_t                        sc_freq;
                     36:        int                             sc_dmasts;
                     37:
                     38:        u_char                          *sc_reg;
                     39:        dbdma_regmap_t                  *sc_dma;
                     40:        bus_dma_tag_t                   sc_dmat;
                     41:        bus_dmamap_t                    sc_bufmap;
                     42:        bus_dma_segment_t               sc_bufseg[1];
                     43:        dbdma_t                         sc_dbdma;
                     44:        dbdma_command_t                 *sc_dmacmd;
                     45:        uint32_t                        *sc_buf;
                     46:        uint32_t                        *sc_bufpos;
                     47:
                     48:        struct timeout                  sc_tmo;
                     49: };
                     50:
                     51: int xlights_match(struct device *, void *, void *);
                     52: void xlights_attach(struct device *, struct device *, void *);
                     53: int xlights_intr(void *);
                     54: void xlights_startdma(struct xlights_softc *);
                     55: void xlights_deferred(void *);
                     56: void xlights_theosDOT(void *);
                     57: void xlights_timeout(void *);
                     58: void xlights_pwm(struct xlights_softc *, u_char *, int);
                     59: extern void keylargo_fcr_enable(int, u_int32_t);
                     60: extern void keylargo_fcr_disable(int, u_int32_t);
                     61:
                     62: struct cfattach xlights_ca = {
                     63:        sizeof(struct xlights_softc), xlights_match,
                     64:        xlights_attach
                     65: };
                     66:
                     67: struct cfdriver xlights_cd = {
                     68:        NULL, "xlights", DV_DULL
                     69: };
                     70:
                     71: #define BL_BUFSZ PAGE_SIZE
                     72: #define BL_DBDMA_CMDS 2
                     73:
                     74: int
                     75: xlights_match(struct device *parent, void *arg, void *aux)
                     76: {
                     77:        struct confargs *ca = aux;
                     78:        int soundbus, soundchip, error;
                     79:        char compat[32];
                     80:
                     81:        if (strcmp(ca->ca_name, "i2s") != 0)
                     82:                return 0;
                     83:        if ((soundbus = OF_child(ca->ca_node)) == 0)
                     84:                return 0;
                     85:        if ((soundchip = OF_child(soundbus)) == 0)
                     86:                return 0;
                     87:
                     88:        error = OF_getprop(soundchip, "virtual", compat, sizeof(compat));
                     89:        if (error == -1) {
                     90:                error = OF_getprop(soundchip, "name", compat,
                     91:                    sizeof(compat));
                     92:
                     93:                if (error == -1 || (strcmp(compat, "lightshow")) != 0)
                     94:                        return 0;
                     95:        }
                     96:
                     97:        /* we require at least 4 registers */
                     98:        if (ca->ca_nreg / sizeof(int) < 4)
                     99:                return 0;
                    100:        /* we require at least 3 interrupts */
                    101:        if (ca->ca_nintr / sizeof(int) < 6)
                    102:                return 0;
                    103:
                    104:        return 1;
                    105: }
                    106:
                    107: void
                    108: xlights_attach(struct device *parent, struct device *self, void *aux)
                    109: {
                    110:        struct xlights_softc *sc = (struct xlights_softc *)self;
                    111:        struct confargs *ca = aux;
                    112:        int nseg, error, intr[6];
                    113:        u_int32_t reg[4];
                    114:
                    115:        sc->sc_node = OF_child(ca->ca_node);
                    116:
                    117:        OF_getprop(sc->sc_node, "reg", reg, sizeof(reg));
                    118:        ca->ca_reg[0] += ca->ca_baseaddr;
                    119:        ca->ca_reg[2] += ca->ca_baseaddr;
                    120:
                    121:        if ((sc->sc_reg = mapiodev(ca->ca_reg[0], ca->ca_reg[1])) == NULL) {
                    122:                printf(": cannot map registers\n");
                    123:                return;
                    124:        }
                    125:        sc->sc_dmat = ca->ca_dmat;
                    126:
                    127:        if ((sc->sc_dma = mapiodev(ca->ca_reg[2], ca->ca_reg[3])) == NULL) {
                    128:                printf(": cannot map DMA registers\n");
                    129:                goto nodma;
                    130:        }
                    131:
                    132:        if ((sc->sc_dbdma = dbdma_alloc(sc->sc_dmat, BL_DBDMA_CMDS)) == NULL) {
                    133:                printf(": cannot alloc DMA descriptors\n");
                    134:                goto nodbdma;
                    135:         }
                    136:        sc->sc_dmacmd = sc->sc_dbdma->d_addr;
                    137:
                    138:        if ((error = bus_dmamem_alloc(sc->sc_dmat, BL_BUFSZ, 0, 0,
                    139:                sc->sc_bufseg, 1, &nseg, BUS_DMA_NOWAIT))) {
                    140:                printf(": cannot allocate DMA mem (%d)\n", error);
                    141:                goto nodmamem;
                    142:        }
                    143:
                    144:        if ((error = bus_dmamem_map(sc->sc_dmat, sc->sc_bufseg, nseg,
                    145:            BL_BUFSZ, (caddr_t *)&sc->sc_buf, BUS_DMA_NOWAIT))) {
                    146:                printf(": cannot map DMA mem (%d)\n", error);
                    147:                goto nodmamap;
                    148:        }
                    149:        sc->sc_bufpos = sc->sc_buf;
                    150:
                    151:        if ((error = bus_dmamap_create(sc->sc_dmat, BL_BUFSZ, 1, BL_BUFSZ, 0,
                    152:            BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &sc->sc_bufmap))) {
                    153:                printf(": cannot create DMA map (%d)\n", error);
                    154:                goto nodmacreate;
                    155:        }
                    156:
                    157:        if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_bufmap, sc->sc_buf,
                    158:            BL_BUFSZ, NULL, BUS_DMA_NOWAIT))) {
                    159:                printf(": cannot load DMA map (%d)\n", error);
                    160:                goto nodmaload;
                    161:        }
                    162:        /* XXX: Should probably extract this from the clock data
                    163:         * property of the soundchip node */
                    164:        sc->sc_freq = 44100;
                    165:
                    166:        OF_getprop(sc->sc_node, "interrupts", intr, sizeof(intr));
                    167:        sc->sc_intr = intr[2];
                    168:        printf(": irq %d\n", sc->sc_intr);
                    169:
                    170:        keylargo_fcr_enable(I2SClockOffset, I2S0EN);
                    171:        out32rb(sc->sc_reg + I2S_INT, I2S_INT_CLKSTOPPEND);
                    172:        keylargo_fcr_disable(I2SClockOffset, I2S0CLKEN);
                    173:        for (error = 0; error < 1000; error++) {
                    174:                if (in32rb(sc->sc_reg + I2S_INT) & I2S_INT_CLKSTOPPEND) {
                    175:                        error = 0;
                    176:                        break;
                    177:                }
                    178:                delay(1);
                    179:        }
                    180:        if (error) {
                    181:                printf("%s: i2s timeout\n", sc->sc_dev.dv_xname);
                    182:                goto nodmaload;
                    183:        }
                    184:
                    185:        mac_intr_establish(parent, sc->sc_intr, intr[3] ? IST_LEVEL :
                    186:            IST_EDGE, IPL_AUDIO, xlights_intr, sc, sc->sc_dev.dv_xname);
                    187:
                    188:        out32rb(sc->sc_reg + I2S_FORMAT, CLKSRC_VS);
                    189:        keylargo_fcr_enable(I2SClockOffset, I2S0CLKEN);
                    190:
                    191:        kthread_create_deferred(xlights_deferred, sc);
                    192:        timeout_set(&sc->sc_tmo, xlights_timeout, sc);
                    193:        return;
                    194: nodmaload:
                    195:        bus_dmamap_destroy(sc->sc_dmat, sc->sc_bufmap);
                    196: nodmacreate:
                    197:        bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->sc_buf, BL_BUFSZ);
                    198: nodmamap:
                    199:        bus_dmamem_free(sc->sc_dmat, sc->sc_bufseg, nseg);
                    200: nodmamem:
                    201:        dbdma_free(sc->sc_dbdma);
                    202: nodbdma:
                    203:        unmapiodev((void *)sc->sc_dma, ca->ca_reg[3]);
                    204: nodma:
                    205:        unmapiodev(sc->sc_reg, ca->ca_reg[1]);
                    206: }
                    207:
                    208: void
                    209: xlights_deferred(void *v)
                    210: {
                    211:        kthread_create(xlights_theosDOT, v, NULL, "xlights");
                    212: }
                    213:
                    214: void
                    215: xlights_theosDOT(void *v)
                    216: {
                    217:        struct xlights_softc *sc = (struct xlights_softc *)v;
                    218:        u_char leds[16];
                    219:        int offset, i, s, speed;
                    220:
                    221:        while (1) {
                    222:                speed = (averunnable.ldavg[0] / 100) / 2;
                    223:                for (offset = 8; offset < 16; offset++) {
                    224:                        s = offset - 2;
                    225:                        if (s < 8) {
                    226:                                for (i = 1; i <= (8 - s); i++)
                    227:                                        leds[i - 1] = 0x7f / i;
                    228:                                s += 8 - s;
                    229:                        }
                    230:                        for (i = offset; i >= s; i--)
                    231:                                leds[i] = 0xff / (offset + 1 - s);
                    232:
                    233:                        xlights_pwm(sc, leds, speed);
                    234:                        bzero(leds, sizeof(leds));
                    235:                }
                    236:                for (offset = 7; offset >= 0; offset--) {
                    237:                        s = offset + 2;
                    238:                        if (s > 7) {
                    239:                                for (i = 1; i <= (s - 7); i++)
                    240:                                        leds[15 - (i - 1)] = (0xff / (s - 7)) / i;
                    241:                                s-= s - 7;
                    242:                        }
                    243:                        for (i = offset; i <= s; i++)
                    244:                                leds[i] = 0xff  / (offset + 1) - s;
                    245:                        xlights_pwm(sc, leds, speed);
                    246:                        bzero(leds, sizeof(leds));
                    247:                }
                    248:        }
                    249: }
                    250:
                    251: void
                    252: xlights_pwm(struct xlights_softc *sc, u_char *leds, int msecs)
                    253: {
                    254:        uint32_t *p;
                    255:        int s, l, k, nsamp;
                    256:        uint32_t freq[16] = {0};
                    257:
                    258:        p = sc->sc_bufpos;
                    259:
                    260:        nsamp = sc->sc_freq / 1000 * msecs;
                    261:
                    262:        for (k = 1; k < nsamp;) {
                    263:                if (p - sc->sc_buf < BL_BUFSZ / sizeof(uint32_t)) {
                    264:                        s = 0;
                    265:                        for (l = 0; l < 16; l++) {
                    266:                                s >>= 1;
                    267:                                if (leds[l] &&
                    268:                                    ((k - freq[l]) == (0xff / leds[l]))) {
                    269:                                        s |= 1 << 15;
                    270:                                        freq[l] = k;
                    271:                                }
                    272:                        }
                    273:                        *p = (s << 17) | (s >> 15);
                    274:                        p++;
                    275:                        k++;
                    276:                        sc->sc_bufpos++;
                    277:                } else {
                    278:                        xlights_startdma(sc);
                    279:                        while (sc->sc_dmasts)
                    280:                                tsleep(sc->sc_buf, PWAIT, "blinken", 0);
                    281:                        sc->sc_bufpos = p = sc->sc_buf;
                    282:                }
                    283:        }
                    284: }
                    285:
                    286: void
                    287: xlights_startdma(struct xlights_softc *sc)
                    288: {
                    289:        dbdma_command_t *cmdp = sc->sc_dmacmd;
                    290:
                    291:        sc->sc_dmasts = 1;
                    292:        timeout_add(&sc->sc_tmo, 250);
                    293:
                    294:        DBDMA_BUILD(cmdp, DBDMA_CMD_OUT_LAST, 0,
                    295:            sc->sc_bufmap->dm_segs[0].ds_len,
                    296:            sc->sc_bufmap->dm_segs[0].ds_addr, DBDMA_INT_ALWAYS,
                    297:            DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
                    298:        cmdp++;
                    299:
                    300:        DBDMA_BUILD(cmdp, DBDMA_CMD_STOP, 0, 0, 0, DBDMA_INT_NEVER,
                    301:            DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
                    302:
                    303:        dbdma_start(sc->sc_dma, sc->sc_dbdma);
                    304: }
                    305:
                    306: void
                    307: xlights_timeout(void *v)
                    308: {
                    309:        struct xlights_softc *sc = (struct xlights_softc *)v;
                    310:
                    311:        dbdma_reset(sc->sc_dma);
                    312:        timeout_del(&sc->sc_tmo);
                    313:        sc->sc_dmasts = 0;
                    314:        wakeup(sc->sc_buf);
                    315: }
                    316:
                    317: int
                    318: xlights_intr(void *v)
                    319: {
                    320:        struct xlights_softc *sc = (struct xlights_softc *)v;
                    321:        int status;
                    322:        dbdma_command_t *cmd;
                    323:
                    324:        cmd = sc->sc_dmacmd;
                    325:        status = dbdma_ld16(&cmd->d_status);
                    326:        if (sc->sc_dmasts) {
                    327:                sc->sc_dmasts = 0;
                    328:                timeout_del(&sc->sc_tmo);
                    329:                wakeup(sc->sc_buf);
                    330:                return (1);
                    331:        }
                    332:        return (0);
                    333: }

CVSweb