summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authoraugustss <augustss@NetBSD.org>2002-01-02 03:21:36 +0000
committeraugustss <augustss@NetBSD.org>2002-01-02 03:21:36 +0000
commitf63f2e4dfe8a579c7dd63e2503cdb0b93265161b (patch)
tree82b4e2b751ec323bc7d5054b43ba0919ff5b6bf1 /sys/dev
parent1928358f48fe31aa5caa6291f61def6fb5b931a8 (diff)
Add udsbr(4), a D-Link DSB-R100 FM radio (untested).
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/usb/files.usb7
-rw-r--r--sys/dev/usb/udsbr.c278
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);
+}