root/dev/isa/radiotrack.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. rtattach
  2. rt_set_info
  3. rt_get_info
  4. rt_set_mute
  5. rt_set_freq
  6. rt_state
  7. rt_conv_vol
  8. rt_unconv_vol
  9. sfi_lm700x_init
  10. rt_lm700x_init
  11. rt_lm700x_rset

    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 }

/* [<][>][^][v][top][bottom][index][help] */