[BACK]Return to sf16fmr.c CVS log [TXT][DIR] Up to [local] / sys / dev / isa

Annotation of sys/dev/isa/sf16fmr.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: sf16fmr.c,v 1.1 2002/04/25 04:56:59 mickey Exp $      */
        !             2:
        !             3: /*
        !             4:  * Copyright (c) 2002 Vladimir Popov <jumbo@narod.ru>
        !             5:  * All rights reserved.
        !             6:  *
        !             7:  * Redistribution and use in source and binary forms, with or without
        !             8:  * modification, are permitted provided that the following conditions
        !             9:  * are met:
        !            10:  * 1. Redistributions of source code must retain the above copyright
        !            11:  *    notice, this list of conditions and the following disclaimer.
        !            12:  * 2. Redistributions in binary form must reproduce the above copyright
        !            13:  *    notice, this list of conditions and the following disclaimer in the
        !            14:  *    documentation and/or other materials provided with the distribution.
        !            15:  *
        !            16:  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
        !            17:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
        !            18:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
        !            19:  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
        !            20:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
        !            21:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
        !            22:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
        !            23:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
        !            24:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
        !            25:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
        !            26:  */
        !            27:
        !            28: /* SoundForte RadioLink SF16-FMR FM Radio Card device driver */
        !            29:
        !            30: #include <sys/param.h>
        !            31: #include <sys/systm.h>
        !            32: #include <sys/proc.h>
        !            33: #include <sys/errno.h>
        !            34: #include <sys/ioctl.h>
        !            35: #include <sys/device.h>
        !            36: #include <sys/radioio.h>
        !            37:
        !            38: #include <dev/isa/isavar.h>
        !            39: #include <dev/radio_if.h>
        !            40:
        !            41: #include <dev/ic/tc921x.h>
        !            42: #include <dev/ic/pt2254a.h>
        !            43:
        !            44: #define SF16FMR_BASE_VALID(x)  (x == 0x384 || x == 0x284)
        !            45:
        !            46: #define SF16FMR_CAPABILITIES   0
        !            47:
        !            48: #define SF16FMR_FREQ_DATA      0
        !            49: #define SF16FMR_FREQ_CLOCK     1
        !            50: #define SF16FMR_FREQ_PERIOD    2
        !            51:
        !            52: #define SF16FMR_FREQ_STEADY    (1 << SF16FMR_FREQ_DATA) | \
        !            53:                                (1 << SF16FMR_FREQ_CLOCK) | \
        !            54:                                (1 << SF16FMR_FREQ_PERIOD)
        !            55:
        !            56: #define SF16FMR_VOLU_STROBE_ON (1 << 3)
        !            57: #define SF16FMR_VOLU_STROBE_OFF        (0 << 3)
        !            58: #define SF16FMR_VOLU_CLOCK_ON  (1 << 4)
        !            59: #define SF16FMR_VOLU_CLOCK_OFF (0 << 4)
        !            60: #define SF16FMR_VOLU_DATA_ON   (1 << 5)
        !            61: #define SF16FMR_VOLU_DATA_OFF  (0 << 5)
        !            62:
        !            63: int    sfr_probe(struct device *, void *, void *);
        !            64: void   sfr_attach(struct device *, struct device * self, void *);
        !            65:
        !            66: int    sfr_get_info(void *, struct radio_info *);
        !            67: int    sfr_set_info(void *, struct radio_info *);
        !            68:
        !            69: /* define our interface to the higher level radio driver */
        !            70: struct radio_hw_if sfr_hw_if = {
        !            71:        NULL, /* open */
        !            72:        NULL, /* close */
        !            73:        sfr_get_info,
        !            74:        sfr_set_info,
        !            75:        NULL
        !            76: };
        !            77:
        !            78: struct sfr_softc {
        !            79:        struct device   sc_dev;
        !            80:
        !            81:        u_int32_t       freq;
        !            82:        u_int8_t        vol;
        !            83:        int     mute;
        !            84:
        !            85:        struct tc921x_t c;
        !            86: };
        !            87:
        !            88: struct cfattach sfr_ca = {
        !            89:        sizeof(struct sfr_softc), sfr_probe, sfr_attach
        !            90: };
        !            91:
        !            92: struct cfdriver sfr_cd = {
        !            93:        NULL, "sfr", DV_DULL
        !            94: };
        !            95:
        !            96: int    sfr_find(bus_space_tag_t, bus_space_handle_t);
        !            97: u_int32_t      sfr_set_freq(struct tc921x_t *, u_int32_t);
        !            98: u_int32_t      sfr_get_freq(struct tc921x_t *);
        !            99: u_int8_t       sfr_set_vol(bus_space_tag_t, bus_space_handle_t, u_int8_t, int);
        !           100: void   sfr_send_volume(bus_space_tag_t, bus_space_handle_t, u_int32_t);
        !           101:
        !           102: int
        !           103: sfr_probe(struct device *parent, void *match, void *aux)
        !           104: {
        !           105:        struct isa_attach_args *ia = aux;
        !           106:        bus_space_tag_t iot = ia->ia_iot;
        !           107:        bus_space_handle_t ioh;
        !           108:        int iosize = 1, iobase = ia->ia_iobase;
        !           109:
        !           110:        if (!SF16FMR_BASE_VALID(iobase)) {
        !           111:                printf("sfr: configured iobase 0x%x invalid\n", iobase);
        !           112:                return (0);
        !           113:        }
        !           114:
        !           115:        if (bus_space_map(iot, iobase, iosize, 0, &ioh))
        !           116:                return (0);
        !           117:
        !           118:        if (!sfr_find(iot, ioh)) {
        !           119:                bus_space_unmap(iot, ioh, iosize);
        !           120:                return (0);
        !           121:        }
        !           122:
        !           123:        bus_space_unmap(iot, ioh, iosize);
        !           124:        ia->ia_iosize = iosize;
        !           125:        return (1);
        !           126: }
        !           127:
        !           128: void
        !           129: sfr_attach(struct device *parent, struct device *self, void *aux)
        !           130: {
        !           131:        struct sfr_softc *sc = (void *) self;
        !           132:        struct isa_attach_args *ia = aux;
        !           133:
        !           134:        sc->c.iot = ia->ia_iot;
        !           135:        sc->mute = 0;
        !           136:        sc->vol = 0;
        !           137:        sc->freq = MIN_FM_FREQ;
        !           138:        sc->c.period = SF16FMR_FREQ_PERIOD;
        !           139:        sc->c.clock = SF16FMR_FREQ_CLOCK;
        !           140:        sc->c.data = SF16FMR_FREQ_DATA;
        !           141:
        !           142:        /* remap I/O */
        !           143:        if (bus_space_map(sc->c.iot, ia->ia_iobase, ia->ia_iosize,
        !           144:                          0, &sc->c.ioh)) {
        !           145:                printf(": bus_space_map() failed\n");
        !           146:                return;
        !           147:        }
        !           148:
        !           149:        printf(": SoundForte RadioLink SF16-FMR\n");
        !           150:        sfr_set_freq(&sc->c, sc->freq);
        !           151:        sfr_set_vol(sc->c.iot, sc->c.ioh, sc->vol, sc->mute);
        !           152:
        !           153:        radio_attach_mi(&sfr_hw_if, sc, &sc->sc_dev);
        !           154: }
        !           155:
        !           156: int
        !           157: sfr_find(bus_space_tag_t iot, bus_space_handle_t ioh)
        !           158: {
        !           159:        struct sfr_softc sc;
        !           160:        u_int32_t freq;
        !           161:
        !           162:        sc.c.iot = iot;
        !           163:        sc.c.ioh = ioh;
        !           164:        sc.c.offset = 0;
        !           165:        sc.c.period = SF16FMR_FREQ_PERIOD;
        !           166:        sc.c.clock = SF16FMR_FREQ_CLOCK;
        !           167:        sc.c.data = SF16FMR_FREQ_DATA;
        !           168:
        !           169:        /*
        !           170:         * Let's try to write and read a frequency.
        !           171:         * If the written and read frequencies are
        !           172:         * the same then success.
        !           173:         */
        !           174:        sc.freq = MIN_FM_FREQ;
        !           175:        /* Initialize the tc921x chip */
        !           176:        sfr_set_freq(&sc.c, sc.freq);
        !           177:        /* Do actual frequency setting */
        !           178:        freq = sfr_set_freq(&sc.c, sc.freq);
        !           179:        if (sc.freq == freq)
        !           180:                return 1;
        !           181:
        !           182:        return 0;
        !           183: }
        !           184:
        !           185: int
        !           186: sfr_get_info(void *v, struct radio_info *ri)
        !           187: {
        !           188:        struct sfr_softc *sc = v;
        !           189:
        !           190:        ri->mute = sc->mute;
        !           191:        ri->volume = sc->vol;
        !           192:        ri->caps = SF16FMR_CAPABILITIES;
        !           193:        ri->freq  = sc->freq = sfr_get_freq(&sc->c);
        !           194:
        !           195:        /* Not supported */
        !           196:        ri->stereo = 1; /* Always stereo */
        !           197:        ri->rfreq = 0;
        !           198:        ri->lock = 0;
        !           199:
        !           200:        return (0);
        !           201: }
        !           202:
        !           203: int
        !           204: sfr_set_info(void *v, struct radio_info *ri)
        !           205: {
        !           206:        struct sfr_softc *sc = v;
        !           207:
        !           208:        sc->mute = ri->mute ? 1 : 0;
        !           209:        sc->vol = ri->volume;
        !           210:        sc->freq = sfr_set_freq(&sc->c, ri->freq);
        !           211:        sc->vol = sfr_set_vol(sc->c.iot, sc->c.ioh, sc->vol, sc->mute);
        !           212:
        !           213:        return (0);
        !           214: }
        !           215:
        !           216: u_int32_t
        !           217: sfr_set_freq(struct tc921x_t *c, u_int32_t freq) {
        !           218:         u_int32_t data = 0ul;
        !           219:
        !           220:        data |= tc921x_encode_freq(freq);
        !           221:        data |= TC921X_D0_REF_FREQ_10_KHZ;
        !           222:        data |= TC921X_D0_PULSE_SWALLOW_FM_MODE;
        !           223:        data |= TC921X_D0_OSC_7POINT2_MHZ;
        !           224:        data |= TC921X_D0_OUT_CONTROL_ON;
        !           225:        tc921x_write_addr(c, 0xD0, data);
        !           226:
        !           227:        data  = TC921X_D2_IO_PORT_OUTPUT(4);
        !           228:        tc921x_write_addr(c, 0xD2, data);
        !           229:
        !           230:        return sfr_get_freq(c);
        !           231: }
        !           232:
        !           233: u_int32_t
        !           234: sfr_get_freq(struct tc921x_t *c) {
        !           235:        return tc921x_decode_freq(tc921x_read_addr(c, 0xD1));
        !           236: }
        !           237:
        !           238: u_int8_t
        !           239: sfr_set_vol(bus_space_tag_t iot, bus_space_handle_t ioh, u_int8_t vol, int mute) {
        !           240:        u_int32_t v;
        !           241:        u_int8_t ret;
        !           242:
        !           243:        ret = mute ? 0 : vol;
        !           244:
        !           245:        v = pt2254a_encode_volume(&ret, 255);
        !           246:
        !           247:        sfr_send_volume(iot, ioh,
        !           248:                pt2254a_compose_register(v, v, USE_CHANNEL, USE_CHANNEL));
        !           249:
        !           250:        return ret;
        !           251: }
        !           252:
        !           253: void
        !           254: sfr_send_volume(bus_space_tag_t iot, bus_space_handle_t ioh, u_int32_t vol) {
        !           255:        u_int8_t one, zero;
        !           256:        int i;
        !           257:
        !           258:        one = zero  = SF16FMR_FREQ_STEADY;
        !           259:        one = zero |= SF16FMR_VOLU_STROBE_OFF;
        !           260:
        !           261:        one  |= SF16FMR_VOLU_DATA_ON;
        !           262:        zero |= SF16FMR_VOLU_DATA_OFF;
        !           263:
        !           264:        bus_space_write_1(iot, ioh, 0, SF16FMR_VOLU_STROBE_OFF | SF16FMR_FREQ_STEADY);
        !           265:
        !           266:        for (i = 0; i < PT2254A_REGISTER_LENGTH; i++) {
        !           267:                if (vol & (1 << i)) {
        !           268:                        bus_space_write_1(iot, ioh, 0,
        !           269:                                        one  | SF16FMR_VOLU_CLOCK_OFF);
        !           270:                        bus_space_write_1(iot, ioh, 0,
        !           271:                                        one  | SF16FMR_VOLU_CLOCK_ON);
        !           272:                } else {
        !           273:                        bus_space_write_1(iot, ioh, 0,
        !           274:                                        zero | SF16FMR_VOLU_CLOCK_OFF);
        !           275:                        bus_space_write_1(iot, ioh, 0,
        !           276:                                        zero | SF16FMR_VOLU_CLOCK_ON);
        !           277:                }
        !           278:        }
        !           279:
        !           280:        /* Latch the data */
        !           281:        bus_space_write_1(iot, ioh, 0, SF16FMR_VOLU_STROBE_ON | SF16FMR_FREQ_STEADY);
        !           282:        bus_space_write_1(iot, ioh, 0, SF16FMR_VOLU_STROBE_OFF | SF16FMR_FREQ_STEADY);
        !           283: }

CVSweb