root/dev/usb/udsbr.c

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

DEFINITIONS

This source file includes following definitions.
  1. udsbr_match
  2. udsbr_attach
  3. udsbr_detach
  4. udsbr_activate
  5. udsbr_req
  6. udsbr_start
  7. udsbr_stop
  8. udsbr_setfreq
  9. udsbr_status
  10. udsbr_get_info
  11. udsbr_set_info

    1 /*      $OpenBSD: udsbr.c,v 1.18 2007/06/14 10:11:15 mbalmer Exp $      */
    2 /*      $NetBSD: udsbr.c,v 1.7 2002/07/11 21:14:27 augustss Exp $       */
    3 
    4 /*
    5  * Copyright (c) 2002 The NetBSD Foundation, Inc.
    6  * All rights reserved.
    7  *
    8  * This code is derived from software contributed to The NetBSD Foundation
    9  * by Lennart Augustsson (lennart@augustsson.net).
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  * 3. All advertising materials mentioning features or use of this software
   20  *    must display the following acknowledgement:
   21  *        This product includes software developed by the NetBSD
   22  *        Foundation, Inc. and its contributors.
   23  * 4. Neither the name of The NetBSD Foundation nor the names of its
   24  *    contributors may be used to endorse or promote products derived
   25  *    from this software without specific prior written permission.
   26  *
   27  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   29  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   30  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   31  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   37  * POSSIBILITY OF SUCH DAMAGE.
   38  */
   39 
   40 /*
   41  * Driver for the D-Link DSB-R100 FM radio.
   42  * I apologize for the magic hex constants, but this is what happens
   43  * when you have to reverse engineer the driver.
   44  * Parts of the code borrowed from Linux and parts from Warner Losh's
   45  * FreeBSD driver.
   46  */
   47 
   48 #include <sys/param.h>
   49 #include <sys/systm.h>
   50 #include <sys/kernel.h>
   51 #include <sys/device.h>
   52 
   53 #include <sys/radioio.h>
   54 #include <dev/radio_if.h>
   55 
   56 #include <dev/usb/usb.h>
   57 #include <dev/usb/usbdi.h>
   58 #include <dev/usb/usbdi_util.h>
   59 
   60 #include <dev/usb/usbdevs.h>
   61 
   62 #ifdef UDSBR_DEBUG
   63 #define DPRINTF(x)      do { if (udsbrdebug) printf x; } while (0)
   64 #define DPRINTFN(n,x)   do { if (udsbrdebug>(n)) printf x; } while (0)
   65 int     udsbrdebug = 0;
   66 #else
   67 #define DPRINTF(x)
   68 #define DPRINTFN(n,x)
   69 #endif
   70 
   71 #define UDSBR_CONFIG_NO         1
   72 
   73 int     udsbr_get_info(void *, struct radio_info *);
   74 int     udsbr_set_info(void *, struct radio_info *);
   75 
   76 struct radio_hw_if udsbr_hw_if = {
   77         NULL, /* open */
   78         NULL, /* close */
   79         udsbr_get_info,
   80         udsbr_set_info,
   81         NULL
   82 };
   83 
   84 struct udsbr_softc {
   85         struct device            sc_dev;
   86         usbd_device_handle       sc_udev;
   87 
   88         char                     sc_mute;
   89         char                     sc_vol;
   90         u_int32_t                sc_freq;
   91 
   92         struct device           *sc_child;
   93 
   94         char                     sc_dying;
   95 };
   96 
   97 int     udsbr_req(struct udsbr_softc *sc, int ureq, int value, int index);
   98 void    udsbr_start(struct udsbr_softc *sc);
   99 void    udsbr_stop(struct udsbr_softc *sc);
  100 void    udsbr_setfreq(struct udsbr_softc *sc, int freq);
  101 int     udsbr_status(struct udsbr_softc *sc);
  102 
  103 int udsbr_match(struct device *, void *, void *); 
  104 void udsbr_attach(struct device *, struct device *, void *); 
  105 int udsbr_detach(struct device *, int); 
  106 int udsbr_activate(struct device *, enum devact); 
  107 
  108 struct cfdriver udsbr_cd = { 
  109         NULL, "udsbr", DV_DULL 
  110 }; 
  111 
  112 const struct cfattach udsbr_ca = { 
  113         sizeof(struct udsbr_softc), 
  114         udsbr_match, 
  115         udsbr_attach, 
  116         udsbr_detach, 
  117         udsbr_activate, 
  118 };
  119 
  120 int
  121 udsbr_match(struct device *parent, void *match, void *aux)
  122 {
  123         struct usb_attach_arg   *uaa = aux;
  124 
  125         DPRINTFN(50,("udsbr_match\n"));
  126 
  127         if (uaa->iface != NULL)
  128                 return (UMATCH_NONE);
  129 
  130         if (uaa->vendor != USB_VENDOR_CYPRESS ||
  131             uaa->product != USB_PRODUCT_CYPRESS_FMRADIO)
  132                 return (UMATCH_NONE);
  133         return (UMATCH_VENDOR_PRODUCT);
  134 }
  135 
  136 void
  137 udsbr_attach(struct device *parent, struct device *self, void *aux)
  138 {
  139         struct udsbr_softc      *sc = (struct udsbr_softc *)self;
  140         struct usb_attach_arg   *uaa = aux;
  141         usbd_device_handle      dev = uaa->device;
  142         char                    *devinfop;
  143         usbd_status             err;
  144 
  145         DPRINTFN(10,("udsbr_attach: sc=%p\n", sc));
  146 
  147         devinfop = usbd_devinfo_alloc(dev, 0);
  148         printf("\n%s: %s\n", sc->sc_dev.dv_xname, devinfop);
  149         usbd_devinfo_free(devinfop);
  150 
  151         err = usbd_set_config_no(dev, UDSBR_CONFIG_NO, 1);
  152         if (err) {
  153                 printf("%s: setting config no failed\n",
  154                     sc->sc_dev.dv_xname);
  155                 return;
  156         }
  157 
  158         sc->sc_udev = dev;
  159 
  160         DPRINTFN(10, ("udsbr_attach: %p\n", sc->sc_udev));
  161 
  162         usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
  163                            &sc->sc_dev);
  164 
  165         sc->sc_child = radio_attach_mi(&udsbr_hw_if, sc, &sc->sc_dev);
  166 }
  167 
  168 int
  169 udsbr_detach(struct device *self, int flags)
  170 {
  171         struct udsbr_softc *sc = (struct udsbr_softc *)self;
  172         int rv = 0;
  173 
  174         if (sc->sc_child != NULL)
  175                 rv = config_detach(sc->sc_child, flags);
  176 
  177         usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
  178                            &sc->sc_dev);
  179 
  180         return (rv);
  181 }
  182 
  183 int
  184 udsbr_activate(struct device *self, enum devact act)
  185 {
  186         struct udsbr_softc *sc = (struct udsbr_softc *)self;
  187         int rv = 0;
  188 
  189         switch (act) {
  190         case DVACT_ACTIVATE:
  191                 break;
  192 
  193         case DVACT_DEACTIVATE:
  194                 sc->sc_dying = 1;
  195                 if (sc->sc_child != NULL)
  196                         rv = config_deactivate(sc->sc_child);
  197                 break;
  198         }
  199         return (rv);
  200 }
  201 
  202 int
  203 udsbr_req(struct udsbr_softc *sc, int ureq, int value, int index)
  204 {
  205         usb_device_request_t req;
  206         usbd_status err;
  207         u_char data;
  208 
  209         DPRINTFN(1,("udsbr_req: ureq=0x%02x value=0x%04x index=0x%04x\n",
  210                     ureq, value, index));
  211         req.bmRequestType = UT_READ_VENDOR_DEVICE;
  212         req.bRequest = ureq;
  213         USETW(req.wValue, value);
  214         USETW(req.wIndex, index);
  215         USETW(req.wLength, 1);
  216         err = usbd_do_request(sc->sc_udev, &req, &data);
  217         if (err) {
  218                 printf("%s: request failed err=%d\n", sc->sc_dev.dv_xname,
  219                        err);
  220         }
  221         return !(data & 1);
  222 }
  223 
  224 void
  225 udsbr_start(struct udsbr_softc *sc)
  226 {
  227         (void)udsbr_req(sc, 0x00, 0x0000, 0x00c7);
  228         (void)udsbr_req(sc, 0x02, 0x0001, 0x0000);
  229 }
  230 
  231 void
  232 udsbr_stop(struct udsbr_softc *sc)
  233 {
  234         (void)udsbr_req(sc, 0x00, 0x0016, 0x001c);
  235         (void)udsbr_req(sc, 0x02, 0x0000, 0x0000);
  236 }
  237 
  238 void
  239 udsbr_setfreq(struct udsbr_softc *sc, int freq)
  240 {
  241         DPRINTF(("udsbr_setfreq: setfreq=%d\n", freq));
  242         /*
  243          * Freq now is in Hz.  We need to convert it to the frequency
  244          * that the radio wants.  This frequency is 10.7MHz above
  245          * the actual frequency.  We then need to convert to
  246          * units of 12.5kHz.  We add one to the IFM to make rounding
  247          * easier.
  248          */
  249         freq = (freq * 1000 + 10700001) / 12500;
  250         (void)udsbr_req(sc, 0x01, (freq >> 8) & 0xff, freq & 0xff);
  251         (void)udsbr_req(sc, 0x00, 0x0096, 0x00b7);
  252         usbd_delay_ms(sc->sc_udev, 240); /* wait for signal to settle */
  253 }
  254 
  255 int
  256 udsbr_status(struct udsbr_softc *sc)
  257 {
  258         return (udsbr_req(sc, 0x00, 0x0000, 0x0024));
  259 }
  260 
  261 
  262 int
  263 udsbr_get_info(void *v, struct radio_info *ri)
  264 {
  265         struct udsbr_softc *sc = v;
  266 
  267         ri->mute = sc->sc_mute;
  268         ri->volume = sc->sc_vol ? 255 : 0;
  269         ri->caps = RADIO_CAPS_DETECT_STEREO;
  270         ri->rfreq = 0;
  271         ri->lock = 0;
  272         ri->freq = sc->sc_freq;
  273         ri->info = udsbr_status(sc) ? RADIO_INFO_STEREO : 0;
  274 
  275         return (0);
  276 }
  277 
  278 int
  279 udsbr_set_info(void *v, struct radio_info *ri)
  280 {
  281         struct udsbr_softc *sc = v;
  282 
  283         sc->sc_mute = ri->mute != 0;
  284         sc->sc_vol = ri->volume != 0;
  285         sc->sc_freq = ri->freq;
  286         udsbr_setfreq(sc, sc->sc_freq);
  287 
  288         if (sc->sc_mute || sc->sc_vol == 0)
  289                 udsbr_stop(sc);
  290         else
  291                 udsbr_start(sc);
  292 
  293         return (0);
  294 }

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