Annotation of sys/dev/isa/radiotrack.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: radiotrack.c,v 1.4 2002/08/28 21:20:48 mickey Exp $ */
! 2: /* $RuOBSD: radiotrack.c,v 1.3 2001/10/18 16:51:36 pva Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 2001, 2002 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: /* AIMS Lab Radiotrack FM Radio Card device driver */
! 31:
! 32: /*
! 33: * Sanyo LM7000 Direct PLL Frequency Synthesizer
! 34: */
! 35:
! 36: #include <sys/param.h>
! 37: #include <sys/systm.h>
! 38: #include <sys/ioctl.h>
! 39: #include <sys/device.h>
! 40: #include <sys/radioio.h>
! 41:
! 42: #include <machine/bus.h>
! 43:
! 44: #include <dev/ic/lm700x.h>
! 45: #include <dev/isa/isavar.h>
! 46: #include <dev/isa/rtreg.h>
! 47: #include <dev/isa/rtvar.h>
! 48: #include <dev/radio_if.h>
! 49:
! 50: void rtattach(struct rt_softc *);
! 51: int rt_get_info(void *, struct radio_info *);
! 52: int rt_set_info(void *, struct radio_info *);
! 53:
! 54: struct radio_hw_if rt_hw_if = {
! 55: NULL, /* open */
! 56: NULL, /* close */
! 57: rt_get_info,
! 58: rt_set_info,
! 59: NULL
! 60: };
! 61:
! 62: struct cfdriver rt_cd = {
! 63: NULL, "rt", DV_DULL
! 64: };
! 65:
! 66: void rt_set_mute(struct rt_softc *, int);
! 67: void rt_set_freq(struct rt_softc *, u_int32_t);
! 68: u_int8_t rt_state(bus_space_tag_t, bus_space_handle_t);
! 69:
! 70: void sfi_lm700x_init(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int32_t);
! 71: void rt_lm700x_init(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int32_t);
! 72: void rt_lm700x_rset(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int32_t);
! 73:
! 74: u_int8_t rt_conv_vol(u_int8_t);
! 75: u_int8_t rt_unconv_vol(u_int8_t);
! 76:
! 77: void
! 78: rtattach(struct rt_softc *sc) {
! 79: sc->sc_freq = MIN_FM_FREQ;
! 80: sc->sc_mute = 0;
! 81: sc->sc_vol = 0;
! 82: sc->sc_rf = LM700X_REF_050;
! 83: sc->sc_stereo = LM700X_STEREO;
! 84:
! 85: sc->lm.wzcl = RT_WREN_ON | RT_CLCK_OFF | RT_DATA_OFF;
! 86: sc->lm.wzch = RT_WREN_ON | RT_CLCK_ON | RT_DATA_OFF;
! 87: sc->lm.wocl = RT_WREN_ON | RT_CLCK_OFF | RT_DATA_ON;
! 88: sc->lm.woch = RT_WREN_ON | RT_CLCK_ON | RT_DATA_ON;
! 89:
! 90: switch (sc->sc_ct) {
! 91: case CARD_RADIOTRACK:
! 92: sc->lm.initdata = 0;
! 93: sc->lm.rsetdata = RT_SIGNAL_METER;
! 94: sc->lm.init = rt_lm700x_init;
! 95: sc->lm.rset = rt_lm700x_rset;
! 96: break;
! 97: case CARD_SF16FMI:
! 98: sc->lm.initdata = RT_CARD_OFF;
! 99: sc->lm.rsetdata = RT_CARD_ON;
! 100: sc->lm.init = sfi_lm700x_init;
! 101: sc->lm.rset = sfi_lm700x_init;
! 102: break;
! 103: }
! 104:
! 105: rt_set_freq(sc, sc->sc_freq);
! 106: rt_set_mute(sc, sc->sc_vol);
! 107:
! 108: radio_attach_mi(&rt_hw_if, sc, &sc->sc_dev);
! 109: }
! 110:
! 111: int
! 112: rt_set_info(void *v, struct radio_info *ri)
! 113: {
! 114: struct rt_softc *sc = v;
! 115:
! 116: sc->sc_mute = ri->mute ? 1 : 0;
! 117: sc->sc_rf = lm700x_encode_ref(ri->rfreq);
! 118:
! 119: switch (sc->sc_ct) {
! 120: case CARD_RADIOTRACK:
! 121: sc->sc_vol = rt_conv_vol(ri->volume);
! 122: break;
! 123: case CARD_SF16FMI:
! 124: sc->sc_vol = ri->volume ? 1 : 0;
! 125: break;
! 126: }
! 127: /*
! 128: * Though SF16-FMI does not set stereo/mono
! 129: * it won't hurt to have this
! 130: */
! 131: sc->sc_stereo = ri->stereo ? LM700X_STEREO : LM700X_MONO;
! 132:
! 133: rt_set_freq(sc, ri->freq);
! 134: rt_set_mute(sc, sc->sc_vol);
! 135:
! 136: return (0);
! 137: }
! 138:
! 139: int
! 140: rt_get_info(void *v, struct radio_info *ri)
! 141: {
! 142: struct rt_softc *sc = v;
! 143:
! 144: switch (sc->sc_ct) {
! 145: case CARD_RADIOTRACK:
! 146: ri->caps = RTRACK_CAPABILITIES;
! 147: ri->info = 3 & rt_state(sc->lm.iot, sc->lm.ioh);
! 148: ri->volume = rt_unconv_vol(sc->sc_vol);
! 149: break;
! 150: case CARD_SF16FMI:
! 151: ri->caps = SF16FMI_CAPABILITIES;
! 152: ri->volume = sc->sc_vol ? 255 : 0;
! 153: ri->info = 0; /* UNSUPPORTED */
! 154: break;
! 155: default:
! 156: /* No such card */
! 157: return (1);
! 158: }
! 159:
! 160: ri->mute = sc->sc_mute;
! 161: ri->stereo = sc->sc_stereo == LM700X_STEREO ? 0 : 1;
! 162: ri->rfreq = lm700x_decode_ref(sc->sc_rf);
! 163: ri->freq = sc->sc_freq;
! 164:
! 165: /* UNSUPPORTED */
! 166: ri->lock = 0;
! 167:
! 168: return (0);
! 169: }
! 170:
! 171: /*
! 172: * Mute the card
! 173: */
! 174: void
! 175: rt_set_mute(struct rt_softc *sc, int vol)
! 176: {
! 177: int val;
! 178:
! 179: if (sc->sc_ct == CARD_UNKNOWN)
! 180: return;
! 181:
! 182: if (sc->sc_ct == CARD_SF16FMI) {
! 183: val = vol ? RT_CARD_ON : RT_CARD_OFF;
! 184: bus_space_write_1(sc->lm.iot, sc->lm.ioh, 0,
! 185: sc->sc_mute ? RT_CARD_OFF : val);
! 186: return;
! 187: }
! 188:
! 189: /* CARD_RADIOTRACK */
! 190: if (sc->sc_mute) {
! 191: bus_space_write_1(sc->lm.iot, sc->lm.ioh, 0,
! 192: RT_VOLUME_DOWN | RT_CARD_ON);
! 193: DELAY(MAX_VOL * RT_VOLUME_DELAY);
! 194: bus_space_write_1(sc->lm.iot, sc->lm.ioh, 0,
! 195: RT_VOLUME_STEADY | RT_CARD_ON);
! 196: bus_space_write_1(sc->lm.iot, sc->lm.ioh, 0, RT_CARD_OFF);
! 197: bus_space_write_1(sc->lm.iot, sc->lm.ioh, 0, RT_CARD_OFF);
! 198: } else {
! 199: val = sc->sc_vol - vol;
! 200: if (val < 0) {
! 201: val *= -1;
! 202: bus_space_write_1(sc->lm.iot, sc->lm.ioh, 0,
! 203: RT_VOLUME_DOWN | RT_CARD_ON);
! 204: } else {
! 205: bus_space_write_1(sc->lm.iot, sc->lm.ioh, 0,
! 206: RT_VOLUME_UP | RT_CARD_ON);
! 207: }
! 208: DELAY(val * RT_VOLUME_DELAY);
! 209: bus_space_write_1(sc->lm.iot, sc->lm.ioh, 0,
! 210: RT_VOLUME_STEADY | RT_CARD_ON);
! 211: }
! 212: }
! 213:
! 214: void
! 215: rt_set_freq(struct rt_softc *sc, u_int32_t nfreq)
! 216: {
! 217: u_int32_t reg;
! 218:
! 219: if (nfreq > MAX_FM_FREQ)
! 220: nfreq = MAX_FM_FREQ;
! 221: if (nfreq < MIN_FM_FREQ)
! 222: nfreq = MIN_FM_FREQ;
! 223:
! 224: sc->sc_freq = nfreq;
! 225:
! 226: reg = lm700x_encode_freq(nfreq, sc->sc_rf);
! 227: reg |= sc->sc_stereo | sc->sc_rf | LM700X_DIVIDER_FM;
! 228:
! 229: lm700x_hardware_write(&sc->lm, reg, RT_VOLUME_STEADY);
! 230:
! 231: rt_set_mute(sc, sc->sc_vol);
! 232: }
! 233:
! 234: /*
! 235: * Return state of the card - tuned/not tuned, mono/stereo
! 236: */
! 237: u_int8_t
! 238: rt_state(bus_space_tag_t iot, bus_space_handle_t ioh)
! 239: {
! 240: u_int8_t ret;
! 241:
! 242: bus_space_write_1(iot, ioh, 0,
! 243: RT_VOLUME_STEADY | RT_SIGNAL_METER | RT_CARD_ON);
! 244: DELAY(RT_SIGNAL_METER_DELAY);
! 245: ret = bus_space_read_1(iot, ioh, 0);
! 246:
! 247: switch (ret) {
! 248: case 0xFD:
! 249: ret = RADIO_INFO_SIGNAL | RADIO_INFO_STEREO;
! 250: break;
! 251: case 0xFF:
! 252: ret = 0;
! 253: break;
! 254: default:
! 255: ret = RADIO_INFO_SIGNAL;
! 256: break;
! 257: }
! 258:
! 259: return ret;
! 260: }
! 261:
! 262: /*
! 263: * Convert volume to hardware representation.
! 264: */
! 265: u_int8_t
! 266: rt_conv_vol(u_int8_t vol)
! 267: {
! 268: if (vol < VOLUME_RATIO(1))
! 269: return 0;
! 270: else if (vol >= VOLUME_RATIO(1) && vol < VOLUME_RATIO(2))
! 271: return 1;
! 272: else if (vol >= VOLUME_RATIO(2) && vol < VOLUME_RATIO(3))
! 273: return 2;
! 274: else if (vol >= VOLUME_RATIO(3) && vol < VOLUME_RATIO(4))
! 275: return 3;
! 276: else
! 277: return 4;
! 278: }
! 279:
! 280: /*
! 281: * Convert volume from hardware representation
! 282: */
! 283: u_int8_t
! 284: rt_unconv_vol(u_int8_t vol)
! 285: {
! 286: return VOLUME_RATIO(vol);
! 287: }
! 288:
! 289: void
! 290: sfi_lm700x_init(bus_space_tag_t iot, bus_space_handle_t ioh, bus_size_t off,
! 291: u_int32_t data)
! 292: {
! 293: bus_space_write_1(iot, ioh, off, data);
! 294: }
! 295:
! 296: void
! 297: rt_lm700x_init(bus_space_tag_t iot, bus_space_handle_t ioh, bus_size_t off,
! 298: u_int32_t data)
! 299: {
! 300: /* Do nothing */
! 301: return;
! 302: }
! 303:
! 304: void
! 305: rt_lm700x_rset(bus_space_tag_t iot, bus_space_handle_t ioh, bus_size_t off,
! 306: u_int32_t data)
! 307: {
! 308: DELAY(1000);
! 309: bus_space_write_1(iot, ioh, off, RT_CARD_OFF | data);
! 310: DELAY(50000);
! 311: bus_space_write_1(iot, ioh, off, RT_VOLUME_STEADY | RT_CARD_ON | data);
! 312: }
CVSweb