The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/isa/radiotrack.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /* $NetBSD: radiotrack.c,v 1.9 2003/07/14 15:47:16 lukem Exp $ */
    2 /* $OpenBSD: radiotrack.c,v 1.1 2001/12/05 10:27:06 mickey Exp $ */
    3 /* $RuOBSD: radiotrack.c,v 1.3 2001/10/18 16:51:36 pva Exp $ */
    4 
    5 /*
    6  * Copyright (c) 2001 Maxim Tsyplakov <tm@oganer.net>,
    7  *                    Vladimir Popov <jumbo@narod.ru>
    8  * All rights reserved.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
   20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   22  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   29  */
   30 
   31 /* AIMS Lab Radiotrack FM Radio Card device driver */
   32 
   33 /*
   34  * Sanyo LM7000 Direct PLL Frequency Synthesizer
   35  */
   36 
   37 #include <sys/cdefs.h>
   38 __KERNEL_RCSID(0, "$NetBSD: radiotrack.c,v 1.9 2003/07/14 15:47:16 lukem Exp $");
   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 5       /* XXX Find real value */
   59 #define VOLUME_RATIO(x) (255 * x / MAX_VOL)
   60 
   61 #define RT_BASE_VALID(x)        \
   62                 ((x == 0x30C) || (x == 0x20C) || (x == 0x284) || (x == 0x384))
   63 
   64 #define CARD_RADIOTRACK         0x01
   65 #define CARD_SF16FMI            0x02
   66 #define CARD_UNKNOWN            0xFF
   67 
   68 #define RTRACK_CAPABILITIES     RADIO_CAPS_DETECT_STEREO |              \
   69                                 RADIO_CAPS_DETECT_SIGNAL |              \
   70                                 RADIO_CAPS_SET_MONO |                   \
   71                                 RADIO_CAPS_REFERENCE_FREQ
   72 
   73 #define RT_WREN_ON              (1 << 0)
   74 #define RT_WREN_OFF             (0 << 0)
   75 
   76 #define RT_CLCK_ON              (1 << 1)
   77 #define RT_CLCK_OFF             (0 << 1)
   78 
   79 #define RT_DATA_ON              (1 << 2)
   80 #define RT_DATA_OFF             (0 << 2)
   81 
   82 #define RT_CARD_ON              (1 << 3)
   83 #define RT_CARD_OFF             (0 << 3)
   84 
   85 #define RT_SIGNAL_METER         (1 << 4)
   86 #define RT_SIGNAL_METER_DELAY   150000
   87 
   88 #define RT_VOLUME_DOWN          (1 << 6)
   89 #define RT_VOLUME_UP            (2 << 6)
   90 #define RT_VOLUME_STEADY        (3 << 6)
   91 #define RT_VOLUME_DELAY         100000
   92 
   93 int     rt_probe(struct device *, struct cfdata *, void *);
   94 void    rt_attach(struct device *, struct device * self, void *);
   95 int     rt_get_info(void *, struct radio_info *);
   96 int     rt_set_info(void *, struct radio_info *);
   97 
   98 struct radio_hw_if rt_hw_if = {
   99         NULL,   /* open */
  100         NULL,   /* close */
  101         rt_get_info,
  102         rt_set_info,
  103         NULL
  104 };
  105 
  106 struct rt_softc {
  107         struct device   sc_dev;
  108 
  109         int             mute;
  110         u_int8_t        vol;
  111         u_int8_t        cardtype;
  112         u_int32_t       freq;
  113         u_int32_t       rf;
  114         u_int32_t       stereo;
  115 
  116         struct lm700x_t lm;
  117 };
  118 
  119 CFATTACH_DECL(rt, sizeof(struct rt_softc),
  120     rt_probe, rt_attach, NULL, NULL);
  121 
  122 int     rt_find(bus_space_tag_t, bus_space_handle_t);
  123 void    rt_set_mute(struct rt_softc *, int);
  124 void    rt_set_freq(struct rt_softc *, u_int32_t);
  125 u_int8_t        rt_state(bus_space_tag_t, bus_space_handle_t);
  126 
  127 void    rt_lm700x_init(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int32_t);
  128 void    rt_lm700x_rset(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int32_t);
  129 
  130 u_int8_t        rt_conv_vol(u_int8_t);
  131 u_int8_t        rt_unconv_vol(u_int8_t);
  132 
  133 int
  134 rt_probe(struct device *parent, struct cfdata *cf, void *aux)
  135 {
  136         struct isa_attach_args *ia = aux;
  137         bus_space_tag_t iot = ia->ia_iot;
  138         bus_space_handle_t ioh;
  139         u_int r;
  140         int iosize = 1, iobase;
  141 
  142         if (ISA_DIRECT_CONFIG(ia))
  143                 return 0;
  144 
  145         if (ia->ia_nio < 1)
  146                 return (0);
  147 
  148         iobase = ia->ia_io[0].ir_addr;
  149 
  150         if (!RT_BASE_VALID(iobase)) {
  151                 printf("rt: configured iobase 0x%x invalid\n", iobase);
  152                 return 0;
  153         }
  154 
  155         if (bus_space_map(iot, iobase, iosize, 0, &ioh))
  156                 return 0;
  157 
  158         r = rt_find(iot, ioh);
  159 
  160         bus_space_unmap(iot, ioh, iosize);
  161 
  162         if (r != 0) {
  163                 ia->ia_nio = 1;
  164                 ia->ia_io[0].ir_size = iosize;
  165 
  166                 ia->ia_niomem = 0;
  167                 ia->ia_nirq = 0;
  168                 ia->ia_ndrq = 0;
  169 
  170                 return (1);
  171         }
  172 
  173         return (0);
  174 }
  175 
  176 void
  177 rt_attach(struct device *parent, struct device *self, void *aux)
  178 {
  179         struct rt_softc *sc = (void *) self;
  180         struct isa_attach_args *ia = aux;
  181 
  182         sc->lm.iot = ia->ia_iot;
  183         sc->rf = LM700X_REF_050;
  184         sc->stereo = LM700X_STEREO;
  185         sc->mute = 0;
  186         sc->freq = MIN_FM_FREQ;
  187         sc->vol = 0;
  188 
  189         /* remap I/O */
  190         if (bus_space_map(sc->lm.iot, ia->ia_io[0].ir_addr,
  191             ia->ia_io[0].ir_size, 0, &sc->lm.ioh))
  192                 panic(": bus_space_map() of %s failed", sc->sc_dev.dv_xname);
  193 
  194         switch (ia->ia_io[0].ir_addr) {
  195         case 0x20C:
  196                 /* FALLTHROUGH */
  197         case 0x30C:
  198                 sc->cardtype = CARD_RADIOTRACK;
  199                 printf(": AIMS Lab Radiotrack or compatible\n");
  200                 break;
  201         case 0x284:
  202                 /* FALLTHROUGH */
  203         case 0x384:
  204                 sc->cardtype = CARD_SF16FMI;
  205                 printf(": SoundForte RadioX SF16-FMI\n");
  206                 break;
  207         default:
  208                 sc->cardtype = CARD_UNKNOWN;
  209                 printf(": Unknown card\n");
  210                 break;
  211         }
  212 
  213         /* Configure struct lm700x_t lm */
  214         sc->lm.offset = 0;
  215         sc->lm.wzcl = RT_WREN_ON | RT_CLCK_OFF | RT_DATA_OFF;
  216         sc->lm.wzch = RT_WREN_ON | RT_CLCK_ON  | RT_DATA_OFF;
  217         sc->lm.wocl = RT_WREN_ON | RT_CLCK_OFF | RT_DATA_ON;
  218         sc->lm.woch = RT_WREN_ON | RT_CLCK_ON  | RT_DATA_ON;
  219         sc->lm.initdata = 0;
  220         sc->lm.rsetdata = RT_DATA_ON | RT_CLCK_ON | RT_WREN_OFF;
  221         sc->lm.init = rt_lm700x_init;
  222         sc->lm.rset = rt_lm700x_rset;
  223 
  224         rt_set_freq(sc, sc->freq);
  225 
  226         radio_attach_mi(&rt_hw_if, sc, &sc->sc_dev);
  227 }
  228 
  229 /*
  230  * Mute the card
  231  */
  232 void
  233 rt_set_mute(struct rt_softc *sc, int vol)
  234 {
  235         int val;
  236 
  237         if (sc->mute) {
  238                 bus_space_write_1(sc->lm.iot, sc->lm.ioh, 0,
  239                                 RT_VOLUME_DOWN | RT_CARD_ON);
  240                 DELAY(MAX_VOL * RT_VOLUME_DELAY);
  241                 bus_space_write_1(sc->lm.iot, sc->lm.ioh, 0,
  242                                 RT_VOLUME_STEADY | RT_CARD_ON);
  243                 bus_space_write_1(sc->lm.iot, sc->lm.ioh, 0, RT_CARD_OFF);
  244                 bus_space_write_1(sc->lm.iot, sc->lm.ioh, 0, RT_CARD_OFF);
  245         } else {
  246                 val = sc->vol - vol;
  247                 if (val < 0) {
  248                         val *= -1;
  249                         bus_space_write_1(sc->lm.iot, sc->lm.ioh, 0,
  250                                         RT_VOLUME_DOWN | RT_CARD_ON);
  251                 } else {
  252                         bus_space_write_1(sc->lm.iot, sc->lm.ioh, 0,
  253                                         RT_VOLUME_UP | RT_CARD_ON);
  254                 }
  255                 DELAY(val * RT_VOLUME_DELAY);
  256                 bus_space_write_1(sc->lm.iot, sc->lm.ioh, 0,
  257                                 RT_VOLUME_STEADY | RT_CARD_ON);
  258         }
  259 }
  260 
  261 void
  262 rt_set_freq(struct rt_softc *sc, u_int32_t nfreq)
  263 {
  264         u_int32_t reg;
  265 
  266         if (nfreq > MAX_FM_FREQ)
  267                 nfreq = MAX_FM_FREQ;
  268         if (nfreq < MIN_FM_FREQ)
  269                 nfreq = MIN_FM_FREQ;
  270 
  271         sc->freq = nfreq;
  272 
  273         reg = lm700x_encode_freq(nfreq, sc->rf);
  274         reg |= sc->stereo | sc->rf | LM700X_DIVIDER_FM;
  275 
  276         lm700x_hardware_write(&sc->lm, reg, RT_VOLUME_STEADY);
  277 
  278         rt_set_mute(sc, sc->vol);
  279 }
  280 
  281 /*
  282  * Return state of the card - tuned/not tuned, mono/stereo
  283  */
  284 u_int8_t
  285 rt_state(bus_space_tag_t iot, bus_space_handle_t ioh)
  286 {
  287         u_int8_t ret;
  288 
  289         bus_space_write_1(iot, ioh, 0,
  290                         RT_VOLUME_STEADY | RT_SIGNAL_METER | RT_CARD_ON);
  291         DELAY(RT_SIGNAL_METER_DELAY);
  292         ret = bus_space_read_1(iot, ioh, 0);
  293 
  294         switch (ret) {
  295         case 0xFD:
  296                 ret = RADIO_INFO_SIGNAL | RADIO_INFO_STEREO;
  297                 break;
  298         case 0xFF:
  299                 ret = 0;
  300                 break;
  301         default:
  302                 ret = RADIO_INFO_SIGNAL;
  303                 break;
  304         }
  305         
  306         return ret;
  307 }
  308 
  309 /*
  310  * Convert volume to hardware representation.
  311  */
  312 u_int8_t
  313 rt_conv_vol(u_int8_t vol)
  314 {
  315         if (vol < VOLUME_RATIO(1))
  316                 return 0;
  317         else if (vol >= VOLUME_RATIO(1) && vol < VOLUME_RATIO(2))
  318                 return 1;
  319         else if (vol >= VOLUME_RATIO(2) && vol < VOLUME_RATIO(3))
  320                 return 2;
  321         else if (vol >= VOLUME_RATIO(3) && vol < VOLUME_RATIO(4))
  322                 return 3;
  323         else
  324                 return 4;
  325 }
  326 
  327 /*
  328  * Convert volume from hardware representation
  329  */
  330 u_int8_t
  331 rt_unconv_vol(u_int8_t vol)
  332 {
  333         return VOLUME_RATIO(vol);
  334 }
  335 
  336 int
  337 rt_find(bus_space_tag_t iot, bus_space_handle_t ioh)
  338 {
  339         struct rt_softc sc;
  340 #if 0
  341         u_int i, scanres = 0;
  342 #endif
  343 
  344         sc.lm.iot = iot;
  345         sc.lm.ioh = ioh;
  346         sc.lm.offset = 0;
  347         sc.lm.wzcl = RT_WREN_ON | RT_CLCK_OFF | RT_DATA_OFF;
  348         sc.lm.wzch = RT_WREN_ON | RT_CLCK_ON  | RT_DATA_OFF;
  349         sc.lm.wocl = RT_WREN_ON | RT_CLCK_OFF | RT_DATA_ON;
  350         sc.lm.woch = RT_WREN_ON | RT_CLCK_ON  | RT_DATA_ON;
  351         sc.lm.initdata = 0;
  352         sc.lm.rsetdata = RT_SIGNAL_METER;
  353         sc.lm.init = rt_lm700x_init;
  354         sc.lm.rset = rt_lm700x_rset;
  355         sc.rf = LM700X_REF_050;
  356         sc.mute = 0;
  357         sc.stereo = LM700X_STEREO;
  358         sc.vol = 0;
  359 
  360         /*
  361          * Scan whole FM range. If there is a card it'll
  362          * respond on some frequency.
  363          */
  364         return 0;
  365 #if 0
  366         for (i = MIN_FM_FREQ; !scanres && i < MAX_FM_FREQ; i += 10) {
  367                 rt_set_freq(&sc, i);
  368                 scanres += rt_state(iot, ioh);
  369         }
  370 
  371         return scanres;
  372 #endif
  373 }
  374 
  375 void
  376 rt_lm700x_init(bus_space_tag_t iot, bus_space_handle_t ioh, bus_size_t off,
  377                 u_int32_t data)
  378 {
  379         /* Do nothing */
  380         return;
  381 }
  382 
  383 void
  384 rt_lm700x_rset(bus_space_tag_t iot, bus_space_handle_t ioh, bus_size_t off,
  385                 u_int32_t data)
  386 {
  387         DELAY(1000);
  388         bus_space_write_1(iot, ioh, off, RT_CARD_OFF | data);
  389         DELAY(50000);
  390         bus_space_write_1(iot, ioh, off, RT_VOLUME_STEADY | RT_CARD_ON | data);
  391 }
  392 
  393 int
  394 rt_set_info(void *v, struct radio_info *ri)
  395 {
  396         struct rt_softc *sc = v;
  397 
  398         sc->mute = ri->mute ? 1 : 0;
  399         sc->vol = rt_conv_vol(ri->volume);
  400         sc->stereo = ri->stereo ? LM700X_STEREO : LM700X_MONO;
  401         sc->rf = lm700x_encode_ref(ri->rfreq);
  402 
  403         rt_set_freq(sc, ri->freq);
  404         rt_set_mute(sc, sc->vol);
  405 
  406         return (0);
  407 }
  408 
  409 int
  410 rt_get_info(void *v, struct radio_info *ri)
  411 {
  412         struct rt_softc *sc = v;
  413 
  414         ri->mute = sc->mute;
  415         ri->volume = rt_unconv_vol(sc->vol);
  416         ri->stereo = sc->stereo == LM700X_STEREO ? 0 : 1;
  417         ri->caps = RTRACK_CAPABILITIES;
  418         ri->rfreq = lm700x_decode_ref(sc->rf);
  419         ri->info = 3 & rt_state(sc->lm.iot, sc->lm.ioh);
  420         ri->freq = sc->freq;
  421 
  422         /* UNSUPPORTED */
  423         ri->lock = 0;
  424 
  425         return (0);
  426 }

Cache object: 19f84003077b9c24ef54cb7938048f16


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.