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

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

1.1     ! nbrk        1: /* $OpenBSD: aztech.c,v 1.4 2002/01/23 20:30:38 mickey Exp $ */
        !             2: /* $RuOBSD: aztech.c,v 1.11 2001/10/20 13:23:47 pva Exp $ */
        !             3:
        !             4: /*
        !             5:  * Copyright (c) 2001 Maxim Tsyplakov <tm@oganer.net>,
        !             6:  *                    Vladimir Popov <jumbo@narod.ru>
        !             7:  * All rights reserved.
        !             8:  *
        !             9:  * Redistribution and use in source and binary forms, with or without
        !            10:  * modification, are permitted provided that the following conditions
        !            11:  * are met:
        !            12:  * 1. Redistributions of source code must retain the above copyright
        !            13:  *    notice, this list of conditions and the following disclaimer.
        !            14:  * 2. Redistributions in binary form must reproduce the above copyright
        !            15:  *    notice, this list of conditions and the following disclaimer in the
        !            16:  *    documentation and/or other materials provided with the distribution.
        !            17:  *
        !            18:  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
        !            19:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
        !            20:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
        !            21:  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
        !            22:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
        !            23:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
        !            24:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
        !            25:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
        !            26:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
        !            27:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
        !            28:  */
        !            29:
        !            30: /* Aztech/PackardBell FM Radio Card device driver */
        !            31:
        !            32: /*
        !            33:  * Sanyo LM7001J Direct PLL Frequency Synthesizer:
        !            34:  *     ??? See http://www.redsword.com/tjacobs/geeb/fmcard.htm
        !            35:  *
        !            36:  * Philips TEA5712T AM/FM Stereo DTS Radio:
        !            37:  *     http://www.semiconductors.philips.com/pip/TEA5712
        !            38:  */
        !            39:
        !            40: #include <sys/param.h>
        !            41: #include <sys/systm.h>
        !            42: #include <sys/proc.h>
        !            43: #include <sys/errno.h>
        !            44: #include <sys/ioctl.h>
        !            45: #include <sys/device.h>
        !            46: #include <sys/radioio.h>
        !            47:
        !            48: #include <machine/bus.h>
        !            49:
        !            50: #include <dev/isa/isavar.h>
        !            51: #include <dev/ic/lm700x.h>
        !            52: #include <dev/radio_if.h>
        !            53:
        !            54: #define RF_25K 25
        !            55: #define RF_50K 50
        !            56: #define RF_100K        100
        !            57:
        !            58: #define MAX_VOL        3
        !            59: #define VOLUME_RATIO(x)        (255 * x / MAX_VOL)
        !            60:
        !            61: #define AZ_BASE_VALID(x)       ((x == 0x350) || (x == 0x358))
        !            62: #define AZTECH_CAPABILITIES    RADIO_CAPS_DETECT_STEREO |              \
        !            63:                                RADIO_CAPS_DETECT_SIGNAL |              \
        !            64:                                RADIO_CAPS_SET_MONO |                   \
        !            65:                                RADIO_CAPS_REFERENCE_FREQ
        !            66:
        !            67:
        !            68: #define AZTECH_STEREO  (1 << 0)
        !            69: #define AZTECH_SIGNAL  (1 << 1)
        !            70:
        !            71: #define        AZ_WREN_ON      (1 << 1)
        !            72: #define        AZ_WREN_OFF     (0 << 1)
        !            73:
        !            74: #define AZ_CLCK_ON     (1 << 6)
        !            75: #define AZ_CLCK_OFF    (0 << 6)
        !            76:
        !            77: #define AZ_DATA_ON     (1 << 7)
        !            78: #define AZ_DATA_OFF    (0 << 7)
        !            79:
        !            80: int    az_probe(struct device *, void *, void *);
        !            81: void   az_attach(struct device *, struct device * self, void *);
        !            82:
        !            83: int    az_get_info(void *, struct radio_info *);
        !            84: int    az_set_info(void *, struct radio_info *);
        !            85:
        !            86: struct radio_hw_if az_hw_if = {
        !            87:        NULL,   /* open */
        !            88:        NULL,   /* close */
        !            89:        az_get_info,
        !            90:        az_set_info,
        !            91:        NULL
        !            92: };
        !            93:
        !            94: struct az_softc {
        !            95:        struct device   sc_dev;
        !            96:
        !            97:        int             mute;
        !            98:        u_int8_t        vol;
        !            99:        u_int32_t       freq;
        !           100:        u_int32_t       rf;
        !           101:        u_int32_t       stereo;
        !           102:
        !           103:        struct lm700x_t lm;
        !           104: };
        !           105:
        !           106: struct cfattach az_ca = {
        !           107:        sizeof(struct az_softc), az_probe, az_attach
        !           108: };
        !           109:
        !           110: struct cfdriver az_cd = {
        !           111:        NULL, "az", DV_DULL
        !           112: };
        !           113:
        !           114: u_int  az_find(bus_space_tag_t, bus_space_handle_t);
        !           115: void   az_set_mute(struct az_softc *);
        !           116: void   az_set_freq(struct az_softc *, u_int32_t);
        !           117: u_int8_t       az_state(bus_space_tag_t, bus_space_handle_t);
        !           118:
        !           119: void   az_lm700x_init(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int32_t);
        !           120: void   az_lm700x_rset(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int32_t);
        !           121:
        !           122: u_int8_t       az_conv_vol(u_int8_t);
        !           123: u_int8_t       az_unconv_vol(u_int8_t);
        !           124:
        !           125: int
        !           126: az_probe(struct device *parent, void *self, void *aux)
        !           127: {
        !           128:        struct isa_attach_args *ia = aux;
        !           129:        bus_space_tag_t iot = ia->ia_iot;
        !           130:        bus_space_handle_t ioh;
        !           131:
        !           132:        int iosize = 1, iobase = ia->ia_iobase;
        !           133:
        !           134:        if (!AZ_BASE_VALID(iobase)) {
        !           135:                printf("az: configured iobase 0x%x invalid\n", iobase);
        !           136:                return (0);
        !           137:        }
        !           138:
        !           139:        if (bus_space_map(iot, iobase, iosize, 0, &ioh))
        !           140:                return (0);
        !           141:
        !           142:        if (!az_find(iot, ioh)) {
        !           143:                bus_space_unmap(iot, ioh, iosize);
        !           144:                return (0);
        !           145:        }
        !           146:
        !           147:        bus_space_unmap(iot, ioh, iosize);
        !           148:        ia->ia_iosize = iosize;
        !           149:        return (1);
        !           150: }
        !           151:
        !           152: void
        !           153: az_attach(struct device *parent, struct device *self, void *aux)
        !           154: {
        !           155:        struct az_softc *sc = (void *) self;
        !           156:        struct isa_attach_args *ia = aux;
        !           157:
        !           158:        sc->lm.iot = ia->ia_iot;
        !           159:        sc->rf = LM700X_REF_050;
        !           160:        sc->stereo = LM700X_STEREO;
        !           161:        sc->mute = 0;
        !           162:        sc->freq = MIN_FM_FREQ;
        !           163:        sc->vol = 0;
        !           164:
        !           165:        /* remap I/O */
        !           166:        if (bus_space_map(sc->lm.iot, ia->ia_iobase, ia->ia_iosize,
        !           167:                          0, &sc->lm.ioh)) {
        !           168:                printf(": bus_space_map() failed\n");
        !           169:                return;
        !           170:        }
        !           171:
        !           172:        printf(": Aztech/PackardBell\n");
        !           173:
        !           174:        /* Configure struct lm700x_t lm */
        !           175:        sc->lm.offset = 0;
        !           176:        sc->lm.wzcl = AZ_WREN_ON | AZ_CLCK_OFF | AZ_DATA_OFF;
        !           177:        sc->lm.wzch = AZ_WREN_ON | AZ_CLCK_ON  | AZ_DATA_OFF;
        !           178:        sc->lm.wocl = AZ_WREN_ON | AZ_CLCK_OFF | AZ_DATA_ON;
        !           179:        sc->lm.woch = AZ_WREN_ON | AZ_CLCK_ON  | AZ_DATA_ON;
        !           180:        sc->lm.initdata = 0;
        !           181:        sc->lm.rsetdata = AZ_DATA_ON | AZ_CLCK_ON | AZ_WREN_OFF;
        !           182:        sc->lm.init = az_lm700x_init;
        !           183:        sc->lm.rset = az_lm700x_rset;
        !           184:
        !           185:        az_set_freq(sc, sc->freq);
        !           186:
        !           187:        radio_attach_mi(&az_hw_if, sc, &sc->sc_dev);
        !           188: }
        !           189:
        !           190: /*
        !           191:  * Mute the card
        !           192:  */
        !           193: void
        !           194: az_set_mute(struct az_softc *sc)
        !           195: {
        !           196:        bus_space_write_1(sc->lm.iot, sc->lm.ioh, 0,
        !           197:            sc->mute ? 0 : sc->vol);
        !           198:        DELAY(6);
        !           199:        bus_space_write_1(sc->lm.iot, sc->lm.ioh, 0,
        !           200:            sc->mute ? 0 : sc->vol);
        !           201: }
        !           202:
        !           203: void
        !           204: az_set_freq(struct az_softc *sc, u_int32_t nfreq)
        !           205: {
        !           206:        u_int8_t vol;
        !           207:        u_int32_t reg;
        !           208:
        !           209:        vol = sc->mute ? 0 : sc->vol;
        !           210:
        !           211:        if (nfreq > MAX_FM_FREQ)
        !           212:                nfreq = MAX_FM_FREQ;
        !           213:        if (nfreq < MIN_FM_FREQ)
        !           214:                nfreq = MIN_FM_FREQ;
        !           215:
        !           216:        sc->freq = nfreq;
        !           217:
        !           218:        reg = lm700x_encode_freq(nfreq, sc->rf);
        !           219:        reg |= sc->stereo | sc->rf | LM700X_DIVIDER_FM;
        !           220:
        !           221:        lm700x_hardware_write(&sc->lm, reg, vol);
        !           222:
        !           223:        az_set_mute(sc);
        !           224: }
        !           225:
        !           226: /*
        !           227:  * Return state of the card - tuned/not tuned, mono/stereo
        !           228:  */
        !           229: u_int8_t
        !           230: az_state(bus_space_tag_t iot, bus_space_handle_t ioh)
        !           231: {
        !           232:        u_int8_t info = 0, portdata;
        !           233:
        !           234:        portdata = bus_space_read_1(iot, ioh, 0);
        !           235:
        !           236:        info |= portdata & AZTECH_STEREO ? 0 : RADIO_INFO_STEREO;
        !           237:        info |= portdata & AZTECH_SIGNAL ? 0 : RADIO_INFO_SIGNAL;
        !           238:
        !           239:        return info;
        !           240: }
        !           241:
        !           242: /*
        !           243:  * Convert volume to hardware representation.
        !           244:  * The card uses bits 00000x0x to set volume.
        !           245:  */
        !           246: u_int8_t
        !           247: az_conv_vol(u_int8_t vol)
        !           248: {
        !           249:        if (vol < VOLUME_RATIO(1))
        !           250:                return 0;
        !           251:        else if (vol >= VOLUME_RATIO(1) && vol < VOLUME_RATIO(2))
        !           252:                return 1;
        !           253:        else if (vol >= VOLUME_RATIO(2) && vol < VOLUME_RATIO(3))
        !           254:                return 4;
        !           255:        else
        !           256:                return 5;
        !           257: }
        !           258:
        !           259: /*
        !           260:  * Convert volume from hardware representation
        !           261:  */
        !           262: u_int8_t
        !           263: az_unconv_vol(u_int8_t vol)
        !           264: {
        !           265:        switch (vol) {
        !           266:        case 0:
        !           267:                return VOLUME_RATIO(0);
        !           268:        case 1:
        !           269:                return VOLUME_RATIO(1);
        !           270:        case 4:
        !           271:                return VOLUME_RATIO(2);
        !           272:        }
        !           273:        return VOLUME_RATIO(3);
        !           274: }
        !           275:
        !           276: u_int
        !           277: az_find(bus_space_tag_t iot, bus_space_handle_t ioh)
        !           278: {
        !           279:        struct az_softc sc;
        !           280:        u_int i;
        !           281:
        !           282:        sc.lm.iot = iot;
        !           283:        sc.lm.ioh = ioh;
        !           284:        sc.lm.offset = 0;
        !           285:        sc.lm.wzcl = AZ_WREN_ON | AZ_CLCK_OFF | AZ_DATA_OFF;
        !           286:        sc.lm.wzch = AZ_WREN_ON | AZ_CLCK_ON  | AZ_DATA_OFF;
        !           287:        sc.lm.wocl = AZ_WREN_ON | AZ_CLCK_OFF | AZ_DATA_ON;
        !           288:        sc.lm.woch = AZ_WREN_ON | AZ_CLCK_ON  | AZ_DATA_ON;
        !           289:        sc.lm.initdata = 0;
        !           290:        sc.lm.rsetdata = AZ_DATA_ON | AZ_CLCK_ON | AZ_WREN_OFF;
        !           291:        sc.lm.init = az_lm700x_init;
        !           292:        sc.lm.rset = az_lm700x_rset;
        !           293:        sc.rf = LM700X_REF_050;
        !           294:        sc.mute = 0;
        !           295:        sc.stereo = LM700X_STEREO;
        !           296:        sc.vol = 0;
        !           297:
        !           298:        /*
        !           299:         * Scan whole FM range. If there is a card it'll
        !           300:         * respond on some frequency.
        !           301:         */
        !           302:        for (i = MIN_FM_FREQ; i < MAX_FM_FREQ; i += 10) {
        !           303:                az_set_freq(&sc, i);
        !           304:                if (az_state(iot, ioh))
        !           305:                        return 1;
        !           306:        }
        !           307:
        !           308:        return 0;
        !           309: }
        !           310:
        !           311: void
        !           312: az_lm700x_init(bus_space_tag_t iot, bus_space_handle_t ioh, bus_size_t off,
        !           313:                u_int32_t data)
        !           314: {
        !           315:        /* Do nothing */
        !           316:        return;
        !           317: }
        !           318:
        !           319: void
        !           320: az_lm700x_rset(bus_space_tag_t iot, bus_space_handle_t ioh, bus_size_t off,
        !           321:                u_int32_t data)
        !           322: {
        !           323:        bus_space_write_1(iot, ioh, off, data);
        !           324: }
        !           325:
        !           326: int
        !           327: az_get_info(void *v, struct radio_info *ri)
        !           328: {
        !           329:        struct az_softc *sc = v;
        !           330:
        !           331:        ri->mute = sc->mute;
        !           332:        ri->volume = az_unconv_vol(sc->vol);
        !           333:        ri->stereo = sc->stereo == LM700X_STEREO ? 1 : 0;
        !           334:        ri->caps = AZTECH_CAPABILITIES;
        !           335:        ri->rfreq = lm700x_decode_ref(sc->rf);
        !           336:        ri->info = az_state(sc->lm.iot, sc->lm.ioh);
        !           337:        ri->freq = sc->freq;
        !           338:
        !           339:        /* UNSUPPORTED */
        !           340:        ri->lock = 0;
        !           341:
        !           342:        return (0);
        !           343: }
        !           344:
        !           345: int
        !           346: az_set_info(void *v, struct radio_info *ri)
        !           347: {
        !           348:        struct az_softc *sc = v;
        !           349:
        !           350:        sc->mute = ri->mute ? 1 : 0;
        !           351:        sc->vol = az_conv_vol(ri->volume);
        !           352:        sc->stereo = ri->stereo ? LM700X_STEREO : LM700X_MONO;
        !           353:        sc->rf = lm700x_encode_ref(ri->rfreq);
        !           354:
        !           355:        az_set_freq(sc, ri->freq);
        !           356:        az_set_mute(sc);
        !           357:
        !           358:        return (0);
        !           359: }

CVSweb