LCOV - code coverage report
Current view: top level - dev/usb - udsbr.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 77 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 11 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: udsbr.c,v 1.27 2016/11/06 12:58:01 mpi 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             :  *
      20             :  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
      21             :  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
      22             :  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
      23             :  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
      24             :  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      25             :  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
      26             :  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
      27             :  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
      28             :  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
      29             :  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      30             :  * POSSIBILITY OF SUCH DAMAGE.
      31             :  */
      32             : 
      33             : /*
      34             :  * Driver for the D-Link DSB-R100 FM radio.
      35             :  * I apologize for the magic hex constants, but this is what happens
      36             :  * when you have to reverse engineer the driver.
      37             :  * Parts of the code borrowed from Linux and parts from Warner Losh's
      38             :  * FreeBSD driver.
      39             :  */
      40             : 
      41             : #include <sys/param.h>
      42             : #include <sys/systm.h>
      43             : #include <sys/device.h>
      44             : 
      45             : #include <sys/radioio.h>
      46             : #include <dev/radio_if.h>
      47             : 
      48             : #include <dev/usb/usb.h>
      49             : #include <dev/usb/usbdi.h>
      50             : #include <dev/usb/usbdi_util.h>
      51             : 
      52             : #include <dev/usb/usbdevs.h>
      53             : 
      54             : #ifdef UDSBR_DEBUG
      55             : #define DPRINTF(x)      do { if (udsbrdebug) printf x; } while (0)
      56             : #define DPRINTFN(n,x)   do { if (udsbrdebug>(n)) printf x; } while (0)
      57             : int     udsbrdebug = 0;
      58             : #else
      59             : #define DPRINTF(x)
      60             : #define DPRINTFN(n,x)
      61             : #endif
      62             : 
      63             : #define UDSBR_CONFIG_NO         1
      64             : 
      65             : int     udsbr_get_info(void *, struct radio_info *);
      66             : int     udsbr_set_info(void *, struct radio_info *);
      67             : 
      68             : struct radio_hw_if udsbr_hw_if = {
      69             :         NULL, /* open */
      70             :         NULL, /* close */
      71             :         udsbr_get_info,
      72             :         udsbr_set_info,
      73             :         NULL
      74             : };
      75             : 
      76             : struct udsbr_softc {
      77             :         struct device            sc_dev;
      78             :         struct usbd_device      *sc_udev;
      79             : 
      80             :         char                     sc_mute;
      81             :         char                     sc_vol;
      82             :         u_int32_t                sc_freq;
      83             : 
      84             :         struct device           *sc_child;
      85             : };
      86             : 
      87             : int     udsbr_req(struct udsbr_softc *sc, int ureq, int value, int index);
      88             : void    udsbr_start(struct udsbr_softc *sc);
      89             : void    udsbr_stop(struct udsbr_softc *sc);
      90             : void    udsbr_setfreq(struct udsbr_softc *sc, int freq);
      91             : int     udsbr_status(struct udsbr_softc *sc);
      92             : 
      93             : int udsbr_match(struct device *, void *, void *); 
      94             : void udsbr_attach(struct device *, struct device *, void *); 
      95             : int udsbr_detach(struct device *, int); 
      96             : int udsbr_activate(struct device *, int); 
      97             : 
      98             : struct cfdriver udsbr_cd = { 
      99             :         NULL, "udsbr", DV_DULL 
     100             : }; 
     101             : 
     102             : const struct cfattach udsbr_ca = { 
     103             :         sizeof(struct udsbr_softc), 
     104             :         udsbr_match, 
     105             :         udsbr_attach, 
     106             :         udsbr_detach, 
     107             :         udsbr_activate, 
     108             : };
     109             : 
     110             : int
     111           0 : udsbr_match(struct device *parent, void *match, void *aux)
     112             : {
     113           0 :         struct usb_attach_arg   *uaa = aux;
     114             : 
     115             :         DPRINTFN(50,("udsbr_match\n"));
     116             : 
     117           0 :         if (uaa->iface == NULL || uaa->configno != UDSBR_CONFIG_NO)
     118           0 :                 return (UMATCH_NONE);
     119             : 
     120           0 :         if (uaa->vendor != USB_VENDOR_CYPRESS ||
     121           0 :             uaa->product != USB_PRODUCT_CYPRESS_FMRADIO)
     122           0 :                 return (UMATCH_NONE);
     123           0 :         return (UMATCH_VENDOR_PRODUCT);
     124           0 : }
     125             : 
     126             : void
     127           0 : udsbr_attach(struct device *parent, struct device *self, void *aux)
     128             : {
     129           0 :         struct udsbr_softc      *sc = (struct udsbr_softc *)self;
     130           0 :         struct usb_attach_arg   *uaa = aux;
     131           0 :         struct usbd_device      *dev = uaa->device;
     132             : 
     133           0 :         sc->sc_udev = dev;
     134           0 :         sc->sc_child = radio_attach_mi(&udsbr_hw_if, sc, &sc->sc_dev);
     135           0 : }
     136             : 
     137             : int
     138           0 : udsbr_detach(struct device *self, int flags)
     139             : {
     140           0 :         struct udsbr_softc *sc = (struct udsbr_softc *)self;
     141             :         int rv = 0;
     142             : 
     143           0 :         if (sc->sc_child != NULL)
     144           0 :                 rv = config_detach(sc->sc_child, flags);
     145             : 
     146           0 :         return (rv);
     147             : }
     148             : 
     149             : int
     150           0 : udsbr_activate(struct device *self, int act)
     151             : {
     152           0 :         struct udsbr_softc *sc = (struct udsbr_softc *)self;
     153             :         int rv = 0;
     154             : 
     155           0 :         switch (act) {
     156             :         case DVACT_DEACTIVATE:
     157           0 :                 if (sc->sc_child != NULL)
     158           0 :                         rv = config_deactivate(sc->sc_child);
     159             :                 break;
     160             :         }
     161           0 :         return (rv);
     162             : }
     163             : 
     164             : int
     165           0 : udsbr_req(struct udsbr_softc *sc, int ureq, int value, int index)
     166             : {
     167           0 :         usb_device_request_t req;
     168             :         usbd_status err;
     169           0 :         u_char data;
     170             : 
     171             :         DPRINTFN(1,("udsbr_req: ureq=0x%02x value=0x%04x index=0x%04x\n",
     172             :                     ureq, value, index));
     173           0 :         req.bmRequestType = UT_READ_VENDOR_DEVICE;
     174           0 :         req.bRequest = ureq;
     175           0 :         USETW(req.wValue, value);
     176           0 :         USETW(req.wIndex, index);
     177           0 :         USETW(req.wLength, 1);
     178           0 :         err = usbd_do_request(sc->sc_udev, &req, &data);
     179           0 :         if (err) {
     180           0 :                 printf("%s: request failed err=%d\n", sc->sc_dev.dv_xname,
     181             :                        err);
     182           0 :         }
     183           0 :         return !(data & 1);
     184           0 : }
     185             : 
     186             : void
     187           0 : udsbr_start(struct udsbr_softc *sc)
     188             : {
     189           0 :         (void)udsbr_req(sc, 0x00, 0x0000, 0x00c7);
     190           0 :         (void)udsbr_req(sc, 0x02, 0x0001, 0x0000);
     191           0 : }
     192             : 
     193             : void
     194           0 : udsbr_stop(struct udsbr_softc *sc)
     195             : {
     196           0 :         (void)udsbr_req(sc, 0x00, 0x0016, 0x001c);
     197           0 :         (void)udsbr_req(sc, 0x02, 0x0000, 0x0000);
     198           0 : }
     199             : 
     200             : void
     201           0 : udsbr_setfreq(struct udsbr_softc *sc, int freq)
     202             : {
     203             :         DPRINTF(("udsbr_setfreq: setfreq=%d\n", freq));
     204             :         /*
     205             :          * Freq now is in Hz.  We need to convert it to the frequency
     206             :          * that the radio wants.  This frequency is 10.7MHz above
     207             :          * the actual frequency.  We then need to convert to
     208             :          * units of 12.5kHz.  We add one to the IFM to make rounding
     209             :          * easier.
     210             :          */
     211           0 :         freq = (freq * 1000 + 10700001) / 12500;
     212           0 :         (void)udsbr_req(sc, 0x01, (freq >> 8) & 0xff, freq & 0xff);
     213           0 :         (void)udsbr_req(sc, 0x00, 0x0096, 0x00b7);
     214           0 :         usbd_delay_ms(sc->sc_udev, 240); /* wait for signal to settle */
     215           0 : }
     216             : 
     217             : int
     218           0 : udsbr_status(struct udsbr_softc *sc)
     219             : {
     220           0 :         return (udsbr_req(sc, 0x00, 0x0000, 0x0024));
     221             : }
     222             : 
     223             : 
     224             : int
     225           0 : udsbr_get_info(void *v, struct radio_info *ri)
     226             : {
     227           0 :         struct udsbr_softc *sc = v;
     228             : 
     229           0 :         ri->mute = sc->sc_mute;
     230           0 :         ri->volume = sc->sc_vol ? 255 : 0;
     231           0 :         ri->caps = RADIO_CAPS_DETECT_STEREO;
     232           0 :         ri->rfreq = 0;
     233           0 :         ri->lock = 0;
     234           0 :         ri->freq = sc->sc_freq;
     235           0 :         ri->info = udsbr_status(sc) ? RADIO_INFO_STEREO : 0;
     236             : 
     237           0 :         return (0);
     238             : }
     239             : 
     240             : int
     241           0 : udsbr_set_info(void *v, struct radio_info *ri)
     242             : {
     243           0 :         struct udsbr_softc *sc = v;
     244             : 
     245           0 :         sc->sc_mute = ri->mute != 0;
     246           0 :         sc->sc_vol = ri->volume != 0;
     247           0 :         sc->sc_freq = ri->freq;
     248           0 :         udsbr_setfreq(sc, sc->sc_freq);
     249             : 
     250           0 :         if (sc->sc_mute || sc->sc_vol == 0)
     251           0 :                 udsbr_stop(sc);
     252             :         else
     253           0 :                 udsbr_start(sc);
     254             : 
     255           0 :         return (0);
     256             : }

Generated by: LCOV version 1.13