udsbr.c revision 1.1
1/* $NetBSD: udsbr.c,v 1.1 2002/01/02 03:21:36 augustss Exp $ */ 2 3/* 4 * Copyright (c) 2002 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Lennart Augustsson (lennart@augustsson.net) at 9 * Carlstedt Research & Technology. 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#include <sys/cdefs.h> 41__KERNEL_RCSID(0, "$NetBSD: udsbr.c,v 1.1 2002/01/02 03:21:36 augustss Exp $"); 42 43#include <sys/param.h> 44#include <sys/systm.h> 45#include <sys/kernel.h> 46#include <sys/device.h> 47 48#include <sys/radioio.h> 49#include <dev/radio_if.h> 50 51#include <dev/usb/usb.h> 52#include <dev/usb/usbdi.h> 53#include <dev/usb/usbdi_util.h> 54 55#include <dev/usb/usbdevs.h> 56 57#define UDSBR_DEBUG 58 59#ifdef UDSBR_DEBUG 60#define DPRINTF(x) if (udsbrdebug) logprintf x 61#define DPRINTFN(n,x) if (udsbrdebug>(n)) logprintf x 62int udsbrdebug = 0; 63#else 64#define DPRINTF(x) 65#define DPRINTFN(n,x) 66#endif 67 68#define UDSBR_CONFIG_NO 1 69#define UDSBR_IFACE_IDX 0 70 71int udsbr_get_info(void *, struct radio_info *); 72int udsbr_set_info(void *, struct radio_info *); 73int udsbr_search(void *, int); 74 75struct radio_hw_if udsbr_hw_if = { 76 NULL, /* open */ 77 NULL, /* close */ 78 udsbr_get_info, 79 udsbr_set_info, 80 NULL 81}; 82 83struct udsbr_softc { 84 USBBASEDEVICE sc_dev; 85 usbd_device_handle sc_udev; 86 usbd_interface_handle sc_iface; 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 97int udsbr_req(struct udsbr_softc *sc, int ureq, int value, int index); 98void udsbr_start(struct udsbr_softc *sc); 99void udsbr_stop(struct udsbr_softc *sc); 100void udsbr_setfreq(struct udsbr_softc *sc, int freq); 101int udsbr_status(struct udsbr_softc *sc); 102 103USB_DECLARE_DRIVER(udsbr); 104 105USB_MATCH(udsbr) 106{ 107 USB_MATCH_START(udsbr, uaa); 108 109 DPRINTFN(50,("udsbr_match\n")); 110 111 if (uaa->iface != NULL) 112 return (UMATCH_NONE); 113 114 if (uaa->vendor != USB_VENDOR_CYPRESS || 115 uaa->product != USB_PRODUCT_CYPRESS_FMRADIO) 116 return (UMATCH_NONE); 117 return (UMATCH_VENDOR_PRODUCT); 118} 119 120USB_ATTACH(udsbr) 121{ 122 USB_ATTACH_START(udsbr, sc, uaa); 123 usbd_device_handle dev = uaa->device; 124 usbd_interface_handle iface; 125 char devinfo[1024]; 126 usbd_status err; 127 128 DPRINTFN(10,("udsbr_attach: sc=%p\n", sc)); 129 130 usbd_devinfo(dev, 0, devinfo); 131 USB_ATTACH_SETUP; 132 printf("%s: %s\n", USBDEVNAME(sc->sc_dev), devinfo); 133 134 err = usbd_set_config_no(dev, UDSBR_CONFIG_NO, 1); 135 if (err) { 136 printf("%s: setting config no failed\n", 137 USBDEVNAME(sc->sc_dev)); 138 USB_ATTACH_ERROR_RETURN; 139 } 140 141 err = usbd_device2interface_handle(dev, UDSBR_IFACE_IDX, &iface); 142 if (err) { 143 printf("%s: getting interface handle failed\n", 144 USBDEVNAME(sc->sc_dev)); 145 USB_ATTACH_ERROR_RETURN; 146 } 147 148 sc->sc_udev = dev; 149 sc->sc_iface = iface; 150 151 DPRINTFN(10, ("udsbr_attach: %p\n", sc->sc_udev)); 152 153 usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, 154 USBDEV(sc->sc_dev)); 155 156 sc->sc_child = radio_attach_mi(&udsbr_hw_if, sc, USBDEV(sc->sc_dev)); 157 158 USB_ATTACH_SUCCESS_RETURN; 159} 160 161USB_DETACH(udsbr) 162{ 163 USB_DETACH_START(udsbr, sc); 164 int rv = 0; 165 166 if (sc->sc_child != NULL) 167 rv = config_detach(sc->sc_child, flags); 168 169 usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, 170 USBDEV(sc->sc_dev)); 171 172 return (rv); 173} 174 175int 176udsbr_activate(device_ptr_t self, enum devact act) 177{ 178 struct udsbr_softc *sc = (struct udsbr_softc *)self; 179 int rv = 0; 180 181 switch (act) { 182 case DVACT_ACTIVATE: 183 return (EOPNOTSUPP); 184 break; 185 186 case DVACT_DEACTIVATE: 187 sc->sc_dying = 1; 188 if (sc->sc_child != NULL) 189 rv = config_deactivate(sc->sc_child); 190 break; 191 } 192 return (rv); 193} 194 195int 196udsbr_req(struct udsbr_softc *sc, int ureq, int value, int index) 197{ 198 usb_device_request_t req; 199 usbd_status err; 200 u_char data; 201 202 req.bmRequestType = UT_READ_VENDOR_DEVICE; 203 req.bRequest = ureq; 204 USETW(req.wValue, value); 205 USETW(req.wIndex, index); 206 USETW(req.wLength, 1); 207 err = usbd_do_request(sc->sc_udev, &req, &data); 208 if (err) { 209 printf("%s: request failed err=%d\n", USBDEVNAME(sc->sc_dev), 210 err); 211 } 212 return !(data & 1); 213} 214 215void 216udsbr_start(struct udsbr_softc *sc) 217{ 218 (void)udsbr_req(sc, 0x00, 0x0000, 0x00c7); 219 (void)udsbr_req(sc, 0x02, 0x0001, 0x0000); 220} 221 222void 223udsbr_stop(struct udsbr_softc *sc) 224{ 225 (void)udsbr_req(sc, 0x00, 0x0016, 0x001c); 226 (void)udsbr_req(sc, 0x02, 0x0000, 0x0000); 227} 228 229void 230udsbr_setfreq(struct udsbr_softc *sc, int freq) 231{ 232 DPRINTF(("udsbr_setfreq: setfreq=%d\n", freq)); 233 freq = freq * 80 / 1000 + 856; 234 (void)udsbr_req(sc, 0x01, (freq >> 8) & 0xff, freq & 0xff); 235 (void)udsbr_req(sc, 0x00, 0x0096, 0x00b7); 236 (void)udsbr_req(sc, 0x00, 0x0000, 0x0024); 237} 238 239int 240udsbr_status(struct udsbr_softc *sc) 241{ 242 return (udsbr_req(sc, 0x00, 0x0000, 0x0024)); 243} 244 245 246int 247udsbr_get_info(void *v, struct radio_info *ri) 248{ 249 struct udsbr_softc *sc = v; 250 251 ri->mute = sc->sc_mute; 252 ri->volume = sc->sc_vol ? 255 : 0; 253 ri->caps = RADIO_CAPS_DETECT_STEREO; 254 ri->rfreq = 0; 255 ri->lock = 0; 256 ri->freq = sc->sc_freq; 257 ri->info = udsbr_status(sc) ? RADIO_INFO_STEREO : 0; 258 259 return (0); 260} 261 262int 263udsbr_set_info(void *v, struct radio_info *ri) 264{ 265 struct udsbr_softc *sc = v; 266 267 sc->sc_mute = ri->mute != 0; 268 sc->sc_vol = ri->volume != 0; 269 sc->sc_freq = ri->freq; 270 udsbr_setfreq(sc, sc->sc_freq); 271 272 if (sc->sc_mute || sc->sc_vol == 0) 273 udsbr_stop(sc); 274 else 275 udsbr_start(sc); 276 277 return (0); 278} 279