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/usb/ufm.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 /*-
    2  * Copyright (c) 2001-2007 M. Warner Losh
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions, and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
   18  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  *
   26  * This code is based on ugen.c and ulpt.c developed by Lennart Augustsson.
   27  * This code includes software developed by the NetBSD Foundation, Inc. and
   28  * its contributors.
   29  */
   30 
   31 #include <sys/cdefs.h>
   32 __FBSDID("$FreeBSD: releng/7.3/sys/dev/usb/ufm.c 170969 2007-06-21 14:42:34Z imp $");
   33 
   34 #include <sys/param.h>
   35 #include <sys/systm.h>
   36 #include <sys/kernel.h>
   37 #include <sys/malloc.h>
   38 #include <sys/module.h>
   39 #include <sys/bus.h>
   40 #include <sys/ioccom.h>
   41 #include <sys/fcntl.h>
   42 #include <sys/filio.h>
   43 #include <sys/conf.h>
   44 #include <sys/uio.h>
   45 #include <sys/tty.h>
   46 #include <sys/file.h>
   47 #include <sys/selinfo.h>
   48 #include <sys/poll.h>
   49 #include <sys/sysctl.h>
   50 
   51 #include <dev/usb/usb.h>
   52 #include <dev/usb/usbdi.h>
   53 #include <dev/usb/usbdi_util.h>
   54 
   55 #include "usbdevs.h"
   56 #include <dev/usb/dsbr100io.h>
   57 
   58 #ifdef USB_DEBUG
   59 #define DPRINTF(x)      if (ufmdebug) printf x
   60 #define DPRINTFN(n,x)   if (ufmdebug>(n)) printf x
   61 int     ufmdebug = 0;
   62 SYSCTL_NODE(_hw_usb, OID_AUTO, ufm, CTLFLAG_RW, 0, "USB ufm");
   63 SYSCTL_INT(_hw_usb_ufm, OID_AUTO, debug, CTLFLAG_RW,
   64            &ufmdebug, 0, "ufm debug level");
   65 #else
   66 #define DPRINTF(x)
   67 #define DPRINTFN(n,x)
   68 #endif
   69 
   70 d_open_t  ufmopen;
   71 d_close_t ufmclose;
   72 d_ioctl_t ufmioctl;
   73 
   74 static struct cdevsw ufm_cdevsw = {
   75         .d_version =    D_VERSION,
   76         .d_flags =      D_NEEDGIANT,
   77         .d_open =       ufmopen,
   78         .d_close =      ufmclose,
   79         .d_ioctl =      ufmioctl,
   80         .d_name =       "ufm",
   81 };
   82 
   83 #define FM_CMD0         0x00
   84 #define FM_CMD_SET_FREQ 0x01
   85 #define FM_CMD2         0x02
   86 
   87 struct ufm_softc {
   88         device_t sc_dev;
   89         usbd_device_handle sc_udev;
   90         usbd_interface_handle sc_iface;
   91 
   92         int sc_opened;
   93         int sc_epaddr;
   94         int sc_freq;
   95 
   96         int sc_refcnt;
   97 };
   98 
   99 #define UFMUNIT(n) (minor(n))
  100 
  101 static device_probe_t ufm_match;
  102 static device_attach_t ufm_attach;
  103 static device_detach_t ufm_detach;
  104 
  105 static device_method_t ufm_methods[] = {
  106         /* Device interface */
  107         DEVMETHOD(device_probe,         ufm_match),
  108         DEVMETHOD(device_attach,        ufm_attach),
  109         DEVMETHOD(device_detach,        ufm_detach),
  110 
  111         { 0, 0 }
  112 };
  113 
  114 static driver_t ufm_driver = {
  115         "ufm",
  116         ufm_methods,
  117         sizeof(struct ufm_softc)
  118 };
  119 
  120 static devclass_t ufm_devclass;
  121 
  122 static int
  123 ufm_match(device_t self)
  124 {
  125         struct usb_attach_arg *uaa = device_get_ivars(self);
  126         usb_device_descriptor_t *dd;
  127 
  128         DPRINTFN(10,("ufm_match\n"));
  129         if (!uaa->iface)
  130                 return UMATCH_NONE;
  131 
  132         dd = usbd_get_device_descriptor(uaa->device);
  133 
  134         if (dd &&
  135             ((UGETW(dd->idVendor) == USB_VENDOR_CYPRESS &&
  136             UGETW(dd->idProduct) == USB_PRODUCT_CYPRESS_FMRADIO)))
  137                 return UMATCH_VENDOR_PRODUCT;
  138         else
  139                 return UMATCH_NONE;
  140 }
  141 
  142 static int
  143 ufm_attach(device_t self)
  144 {
  145         struct ufm_softc *sc = device_get_softc(self);
  146         struct usb_attach_arg *uaa = device_get_ivars(self);
  147         usb_endpoint_descriptor_t *edesc;
  148         usbd_device_handle udev;
  149         usbd_interface_handle iface;
  150         u_int8_t epcount;
  151         usbd_status r;
  152         char * ermsg = "<none>";
  153 
  154         DPRINTFN(10,("ufm_attach: sc=%p\n", sc));
  155         sc->sc_dev = self;
  156         sc->sc_udev = udev = uaa->device;
  157 
  158         if ((!uaa->device) || (!uaa->iface)) {
  159                 ermsg = "device or iface";
  160                 goto nobulk;
  161         }
  162         sc->sc_iface = iface = uaa->iface;
  163         sc->sc_opened = 0;
  164         sc->sc_refcnt = 0;
  165 
  166         r = usbd_endpoint_count(iface, &epcount);
  167         if (r != USBD_NORMAL_COMPLETION) {
  168                 ermsg = "endpoints";
  169                 goto nobulk;
  170         }
  171 
  172         edesc = usbd_interface2endpoint_descriptor(iface, 0);
  173         if (!edesc) {
  174                 ermsg = "interface endpoint";
  175                 goto nobulk;
  176         }
  177         sc->sc_epaddr = edesc->bEndpointAddress;
  178 
  179         /* XXX no error trapping, no storing of struct cdev **/
  180         (void) make_dev(&ufm_cdevsw, device_get_unit(self),
  181                         UID_ROOT, GID_OPERATOR,
  182                         0644, "ufm%d", device_get_unit(self));
  183         DPRINTFN(10, ("ufm_attach: %p\n", sc->sc_udev));
  184         return 0;
  185 
  186  nobulk:
  187         device_printf(sc->sc_dev, "could not find %s\n", ermsg);
  188         return ENXIO;
  189 }
  190 
  191 
  192 int
  193 ufmopen(struct cdev *dev, int flag, int mode, struct thread *td)
  194 {
  195         struct ufm_softc *sc;
  196 
  197         int unit = UFMUNIT(dev);
  198         sc = devclass_get_softc(ufm_devclass, unit);
  199         if (sc == NULL)
  200                 return (ENXIO);
  201 
  202         DPRINTFN(5, ("ufmopen: flag=%d, mode=%d, unit=%d\n",
  203                      flag, mode, unit));
  204 
  205         if (sc->sc_opened)
  206                 return (EBUSY);
  207 
  208         if ((flag & (FWRITE|FREAD)) != (FWRITE|FREAD))
  209                 return (EACCES);
  210 
  211         sc->sc_opened = 1;
  212         return (0);
  213 }
  214 
  215 int
  216 ufmclose(struct cdev *dev, int flag, int mode, struct thread *td)
  217 {
  218         struct ufm_softc *sc;
  219 
  220         int unit = UFMUNIT(dev);
  221         sc = devclass_get_softc(ufm_devclass, unit);
  222 
  223         DPRINTFN(5, ("ufmclose: flag=%d, mode=%d, unit=%d\n", flag, mode, unit));
  224         sc->sc_opened = 0;
  225         sc->sc_refcnt = 0;
  226         return 0;
  227 }
  228 
  229 static int
  230 ufm_do_req(struct ufm_softc *sc, u_int8_t reqtype, u_int8_t request,
  231     u_int16_t value, u_int16_t index, u_int8_t len, void *retbuf)
  232 {
  233         int s;
  234         usb_device_request_t req;
  235         usbd_status err;
  236 
  237         s = splusb();
  238         req.bmRequestType = reqtype;
  239         req.bRequest = request;
  240         USETW(req.wValue, value);
  241         USETW(req.wIndex, index);
  242         USETW(req.wLength, len);
  243         err = usbd_do_request_flags(sc->sc_udev, &req, retbuf, 0, NULL,
  244             USBD_DEFAULT_TIMEOUT);
  245         splx(s);
  246         if (err)
  247                 return (EIO);
  248         return (0);
  249 }
  250 
  251 static int
  252 ufm_set_freq(struct ufm_softc *sc, caddr_t addr)
  253 {
  254         int freq = *(int *)addr;
  255         u_int8_t ret;
  256 
  257         /*
  258          * Freq now is in Hz.  We need to convert it to the frequency
  259          * that the radio wants.  This frequency is 10.7MHz above
  260          * the actual frequency.  We then need to convert to
  261          * units of 12.5kHz.  We add one to the IFM to make rounding
  262          * easier.
  263          */
  264         sc->sc_freq = freq;
  265         freq = (freq + 10700001) / 12500;
  266         /* This appears to set the frequency */
  267         if (ufm_do_req(sc, UT_READ_VENDOR_DEVICE, FM_CMD_SET_FREQ, freq >> 8,
  268             freq, 1, &ret) != 0)
  269                 return (EIO);
  270         /* Not sure what this does */
  271         if (ufm_do_req(sc, UT_READ_VENDOR_DEVICE, FM_CMD0, 0x96, 0xb7, 1,
  272             &ret) != 0)
  273                 return (EIO);
  274         return (0);
  275 }
  276 
  277 static int
  278 ufm_get_freq(struct ufm_softc *sc, caddr_t addr)
  279 {
  280         int *valp = (int *)addr;
  281         *valp = sc->sc_freq;
  282         return (0);
  283 }
  284 
  285 static int
  286 ufm_start(struct ufm_softc *sc, caddr_t addr)
  287 {
  288         u_int8_t ret;
  289 
  290         if (ufm_do_req(sc, UT_READ_VENDOR_DEVICE, FM_CMD0, 0x00, 0xc7,
  291             1, &ret))
  292                 return (EIO);
  293         if (ufm_do_req(sc, UT_READ_VENDOR_DEVICE, FM_CMD2, 0x01, 0x00,
  294             1, &ret))
  295                 return (EIO);
  296         if (ret & 0x1)
  297                 return (EIO);
  298         return (0);
  299 }
  300 
  301 static int
  302 ufm_stop(struct ufm_softc *sc, caddr_t addr)
  303 {
  304         u_int8_t ret;
  305 
  306         if (ufm_do_req(sc, UT_READ_VENDOR_DEVICE, FM_CMD0, 0x16, 0x1C,
  307             1, &ret))
  308                 return (EIO);
  309         if (ufm_do_req(sc, UT_READ_VENDOR_DEVICE, FM_CMD2, 0x00, 0x00,
  310             1, &ret))
  311                 return (EIO);
  312         return (0);
  313 }
  314 
  315 static int
  316 ufm_get_stat(struct ufm_softc *sc, caddr_t addr)
  317 {
  318         u_int8_t ret;
  319 
  320         /*
  321          * Note, there's a 240ms settle time before the status
  322          * will be valid, so tsleep that amount.  hz/4 is a good
  323          * approximation of that.  Since this is a short sleep
  324          * we don't try to catch any signals to keep things
  325          * simple.
  326          */
  327         tsleep(sc, 0, "ufmwait", hz/4);
  328         if (ufm_do_req(sc, UT_READ_VENDOR_DEVICE, FM_CMD0, 0x00, 0x24,
  329             1, &ret))
  330                 return (EIO);
  331         *(int *)addr = ret;
  332 
  333         return (0);
  334 }
  335 
  336 int
  337 ufmioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
  338 {
  339         struct ufm_softc *sc;
  340 
  341         int unit = UFMUNIT(dev);
  342         int error = 0;
  343 
  344         sc = devclass_get_softc(ufm_devclass, unit);
  345 
  346         switch (cmd) {
  347         case FM_SET_FREQ:
  348                 error = ufm_set_freq(sc, addr);
  349                 break;
  350         case FM_GET_FREQ:
  351                 error = ufm_get_freq(sc, addr);
  352                 break;
  353         case FM_START:
  354                 error = ufm_start(sc, addr);
  355                 break;
  356         case FM_STOP:
  357                 error = ufm_stop(sc, addr);
  358                 break;
  359         case FM_GET_STAT:
  360                 error = ufm_get_stat(sc, addr);
  361                 break;
  362         default:
  363                 return ENOTTY;
  364                 break;
  365         }
  366         return error;
  367 }
  368 
  369 static int
  370 ufm_detach(device_t self)
  371 {
  372         return 0;
  373 }
  374 
  375 MODULE_DEPEND(ufm, usb, 1, 1, 1);
  376 DRIVER_MODULE(ufm, uhub, ufm_driver, ufm_devclass, usbd_driver_load, 0);

Cache object: c77b0a6605547d760ae16eba594dcaf6


[ 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.