[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     ! 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