diff options
| author | augustss <augustss@NetBSD.org> | 2002-01-02 03:21:36 +0000 |
|---|---|---|
| committer | augustss <augustss@NetBSD.org> | 2002-01-02 03:21:36 +0000 |
| commit | f63f2e4dfe8a579c7dd63e2503cdb0b93265161b (patch) | |
| tree | 82b4e2b751ec323bc7d5054b43ba0919ff5b6bf1 /sys/dev | |
| parent | 1928358f48fe31aa5caa6291f61def6fb5b931a8 (diff) | |
Add udsbr(4), a D-Link DSB-R100 FM radio (untested).
Diffstat (limited to 'sys/dev')
| -rw-r--r-- | sys/dev/usb/files.usb | 7 | ||||
| -rw-r--r-- | sys/dev/usb/udsbr.c | 278 |
2 files changed, 284 insertions, 1 deletions
diff --git a/sys/dev/usb/files.usb b/sys/dev/usb/files.usb index 3c2bfb5fd09..7e1055dbf6a 100644 --- a/sys/dev/usb/files.usb +++ b/sys/dev/usb/files.usb @@ -1,4 +1,4 @@ -# $NetBSD: files.usb,v 1.37 2001/12/29 10:50:55 augustss Exp $ +# $NetBSD: files.usb,v 1.38 2002/01/02 03:21:36 augustss Exp $ # # Config file and device description for machine-independent USB code. # Included by ports that need it. Ports that use it must provide @@ -120,6 +120,11 @@ device uyap: ezload attach uyap at uhub file dev/usb/uyap.c uyap +# D-Link DSB-R100 FM radio +device udsbr: radio +attach udsbr at uhub +file dev/usb/udsbr.c udsbr + # Ethernet adapters # ADMtek AN986 Pegasus diff --git a/sys/dev/usb/udsbr.c b/sys/dev/usb/udsbr.c new file mode 100644 index 00000000000..56292b1db83 --- /dev/null +++ b/sys/dev/usb/udsbr.c @@ -0,0 +1,278 @@ +/* $NetBSD: udsbr.c,v 1.1 2002/01/02 03:21:36 augustss Exp $ */ + +/* + * Copyright (c) 2002 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Lennart Augustsson (lennart@augustsson.net) at + * Carlstedt Research & Technology. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__KERNEL_RCSID(0, "$NetBSD: udsbr.c,v 1.1 2002/01/02 03:21:36 augustss Exp $"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/device.h> + +#include <sys/radioio.h> +#include <dev/radio_if.h> + +#include <dev/usb/usb.h> +#include <dev/usb/usbdi.h> +#include <dev/usb/usbdi_util.h> + +#include <dev/usb/usbdevs.h> + +#define UDSBR_DEBUG + +#ifdef UDSBR_DEBUG +#define DPRINTF(x) if (udsbrdebug) logprintf x +#define DPRINTFN(n,x) if (udsbrdebug>(n)) logprintf x +int udsbrdebug = 0; +#else +#define DPRINTF(x) +#define DPRINTFN(n,x) +#endif + +#define UDSBR_CONFIG_NO 1 +#define UDSBR_IFACE_IDX 0 + +int udsbr_get_info(void *, struct radio_info *); +int udsbr_set_info(void *, struct radio_info *); +int udsbr_search(void *, int); + +struct radio_hw_if udsbr_hw_if = { + NULL, /* open */ + NULL, /* close */ + udsbr_get_info, + udsbr_set_info, + NULL +}; + +struct udsbr_softc { + USBBASEDEVICE sc_dev; + usbd_device_handle sc_udev; + usbd_interface_handle sc_iface; + + char sc_mute; + char sc_vol; + u_int32_t sc_freq; + + struct device *sc_child; + + char sc_dying; +}; + +int udsbr_req(struct udsbr_softc *sc, int ureq, int value, int index); +void udsbr_start(struct udsbr_softc *sc); +void udsbr_stop(struct udsbr_softc *sc); +void udsbr_setfreq(struct udsbr_softc *sc, int freq); +int udsbr_status(struct udsbr_softc *sc); + +USB_DECLARE_DRIVER(udsbr); + +USB_MATCH(udsbr) +{ + USB_MATCH_START(udsbr, uaa); + + DPRINTFN(50,("udsbr_match\n")); + + if (uaa->iface != NULL) + return (UMATCH_NONE); + + if (uaa->vendor != USB_VENDOR_CYPRESS || + uaa->product != USB_PRODUCT_CYPRESS_FMRADIO) + return (UMATCH_NONE); + return (UMATCH_VENDOR_PRODUCT); +} + +USB_ATTACH(udsbr) +{ + USB_ATTACH_START(udsbr, sc, uaa); + usbd_device_handle dev = uaa->device; + usbd_interface_handle iface; + char devinfo[1024]; + usbd_status err; + + DPRINTFN(10,("udsbr_attach: sc=%p\n", sc)); + + usbd_devinfo(dev, 0, devinfo); + USB_ATTACH_SETUP; + printf("%s: %s\n", USBDEVNAME(sc->sc_dev), devinfo); + + err = usbd_set_config_no(dev, UDSBR_CONFIG_NO, 1); + if (err) { + printf("%s: setting config no failed\n", + USBDEVNAME(sc->sc_dev)); + USB_ATTACH_ERROR_RETURN; + } + + err = usbd_device2interface_handle(dev, UDSBR_IFACE_IDX, &iface); + if (err) { + printf("%s: getting interface handle failed\n", + USBDEVNAME(sc->sc_dev)); + USB_ATTACH_ERROR_RETURN; + } + + sc->sc_udev = dev; + sc->sc_iface = iface; + + DPRINTFN(10, ("udsbr_attach: %p\n", sc->sc_udev)); + + usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, + USBDEV(sc->sc_dev)); + + sc->sc_child = radio_attach_mi(&udsbr_hw_if, sc, USBDEV(sc->sc_dev)); + + USB_ATTACH_SUCCESS_RETURN; +} + +USB_DETACH(udsbr) +{ + USB_DETACH_START(udsbr, sc); + int rv = 0; + + if (sc->sc_child != NULL) + rv = config_detach(sc->sc_child, flags); + + usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, + USBDEV(sc->sc_dev)); + + return (rv); +} + +int +udsbr_activate(device_ptr_t self, enum devact act) +{ + struct udsbr_softc *sc = (struct udsbr_softc *)self; + int rv = 0; + + switch (act) { + case DVACT_ACTIVATE: + return (EOPNOTSUPP); + break; + + case DVACT_DEACTIVATE: + sc->sc_dying = 1; + if (sc->sc_child != NULL) + rv = config_deactivate(sc->sc_child); + break; + } + return (rv); +} + +int +udsbr_req(struct udsbr_softc *sc, int ureq, int value, int index) +{ + usb_device_request_t req; + usbd_status err; + u_char data; + + req.bmRequestType = UT_READ_VENDOR_DEVICE; + req.bRequest = ureq; + USETW(req.wValue, value); + USETW(req.wIndex, index); + USETW(req.wLength, 1); + err = usbd_do_request(sc->sc_udev, &req, &data); + if (err) { + printf("%s: request failed err=%d\n", USBDEVNAME(sc->sc_dev), + err); + } + return !(data & 1); +} + +void +udsbr_start(struct udsbr_softc *sc) +{ + (void)udsbr_req(sc, 0x00, 0x0000, 0x00c7); + (void)udsbr_req(sc, 0x02, 0x0001, 0x0000); +} + +void +udsbr_stop(struct udsbr_softc *sc) +{ + (void)udsbr_req(sc, 0x00, 0x0016, 0x001c); + (void)udsbr_req(sc, 0x02, 0x0000, 0x0000); +} + +void +udsbr_setfreq(struct udsbr_softc *sc, int freq) +{ + DPRINTF(("udsbr_setfreq: setfreq=%d\n", freq)); + freq = freq * 80 / 1000 + 856; + (void)udsbr_req(sc, 0x01, (freq >> 8) & 0xff, freq & 0xff); + (void)udsbr_req(sc, 0x00, 0x0096, 0x00b7); + (void)udsbr_req(sc, 0x00, 0x0000, 0x0024); +} + +int +udsbr_status(struct udsbr_softc *sc) +{ + return (udsbr_req(sc, 0x00, 0x0000, 0x0024)); +} + + +int +udsbr_get_info(void *v, struct radio_info *ri) +{ + struct udsbr_softc *sc = v; + + ri->mute = sc->sc_mute; + ri->volume = sc->sc_vol ? 255 : 0; + ri->caps = RADIO_CAPS_DETECT_STEREO; + ri->rfreq = 0; + ri->lock = 0; + ri->freq = sc->sc_freq; + ri->info = udsbr_status(sc) ? RADIO_INFO_STEREO : 0; + + return (0); +} + +int +udsbr_set_info(void *v, struct radio_info *ri) +{ + struct udsbr_softc *sc = v; + + sc->sc_mute = ri->mute != 0; + sc->sc_vol = ri->volume != 0; + sc->sc_freq = ri->freq; + udsbr_setfreq(sc, sc->sc_freq); + + if (sc->sc_mute || sc->sc_vol == 0) + udsbr_stop(sc); + else + udsbr_start(sc); + + return (0); +} |
