1/* $NetBSD$ */ 2 3/*- 4 * Copyright (c) 2008, 2011 Jared D. McNeill <jmcneill@invisible.ca> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#include <sys/cdefs.h> 30__KERNEL_RCSID(0, "$NetBSD$"); 31 32#include <sys/param.h> 33#include <sys/systm.h> 34#include <sys/device.h> 35#include <sys/conf.h> 36 37#include <dev/usb/usb.h> 38#include <dev/usb/usbdi.h> 39#include <dev/usb/usbdi_util.h> 40#include <dev/usb/usbdevs.h> 41 42#include <dev/i2c/i2cvar.h> 43 44#include <dev/usb/emdtvvar.h> 45#include <dev/usb/emdtvreg.h> 46 47static void emdtv_dtv_get_devinfo(void *, 48 struct dvb_frontend_info *); 49static int emdtv_dtv_open(void *, int); 50static void emdtv_dtv_close(void *); 51static int emdtv_dtv_set_tuner(void *, 52 const struct dvb_frontend_parameters *); 53static fe_status_t emdtv_dtv_get_status(void *); 54static uint16_t emdtv_dtv_get_signal_strength(void *); 55static uint16_t emdtv_dtv_get_snr(void *); 56static int emdtv_dtv_start_transfer(void *, 57 void (*)(void *, const struct dtv_payload *), 58 void *); 59static int emdtv_dtv_stop_transfer(void *); 60 61static int emdtv_dtv_tuner_reset(void *); 62 63static void emdtv_dtv_isoc_startall(struct emdtv_softc *); 64static int emdtv_dtv_isoc_start(struct emdtv_softc *, 65 struct emdtv_isoc_xfer *); 66static void emdtv_dtv_isoc(usbd_xfer_handle, usbd_private_handle, 67 usbd_status); 68 69static const struct dtv_hw_if emdtv_dtv_if = { 70 .get_devinfo = emdtv_dtv_get_devinfo, 71 .open = emdtv_dtv_open, 72 .close = emdtv_dtv_close, 73 .set_tuner = emdtv_dtv_set_tuner, 74 .get_status = emdtv_dtv_get_status, 75 .get_signal_strength = emdtv_dtv_get_signal_strength, 76 .get_snr = emdtv_dtv_get_snr, 77 .start_transfer = emdtv_dtv_start_transfer, 78 .stop_transfer = emdtv_dtv_stop_transfer, 79}; 80 81void 82emdtv_dtv_attach(struct emdtv_softc *sc) 83{ 84 usb_endpoint_descriptor_t *ed; 85 usbd_status status; 86 int i; 87 88 for (i = 0; i < EMDTV_NXFERS; i++) { 89 sc->sc_ix[i].ix_altix = (i & 1) ? 90 &sc->sc_ix[i - 1] : &sc->sc_ix[i + 1]; 91 sc->sc_ix[i].ix_sc = sc; 92 } 93 94 ed = usbd_interface2endpoint_descriptor(sc->sc_iface, 3); 95 if (ed == NULL) { 96 aprint_error_dev(sc->sc_dev, "couldn't find endpoint 3\n"); 97 return; 98 } 99 sc->sc_isoc_maxpacketsize = UGETW(ed->wMaxPacketSize); 100 sc->sc_isoc_buflen = sc->sc_isoc_maxpacketsize * EMDTV_NFRAMES; 101 102 aprint_debug_dev(sc->sc_dev, "calling usbd_open_pipe, ep 0x%02x\n", 103 ed->bEndpointAddress); 104 status = usbd_open_pipe(sc->sc_iface, 105 ed->bEndpointAddress, USBD_EXCLUSIVE_USE, 106 &sc->sc_isoc_pipe); 107 if (status != USBD_NORMAL_COMPLETION) { 108 aprint_error_dev(sc->sc_dev, "couldn't open isoc pipe\n"); 109 usbd_set_interface(sc->sc_iface, 0); 110 return; 111 } 112 113 emdtv_write_1(sc, UR_GET_STATUS, 0x48, 0x00); 114 emdtv_write_1(sc, UR_GET_STATUS, 0x12, 0x77); 115 usbd_delay_ms(sc->sc_udev, 6); 116 117 emdtv_gpio_ctl(sc, EMDTV_GPIO_ANALOG_ON, false); 118 emdtv_gpio_ctl(sc, EMDTV_GPIO_TS1_ON, true); 119 emdtv_gpio_ctl(sc, EMDTV_GPIO_TUNER1_ON, true); 120 emdtv_gpio_ctl(sc, EMDTV_GPIO_DEMOD1_RESET, true); 121 usbd_delay_ms(sc->sc_udev, 100); 122 123 emdtv_dtv_rescan(sc, NULL, NULL); 124} 125 126void 127emdtv_dtv_detach(struct emdtv_softc *sc, int flags) 128{ 129 sc->sc_streaming = false; 130 131 if (sc->sc_dtvdev != NULL) { 132 config_detach(sc->sc_dtvdev, flags); 133 sc->sc_dtvdev = NULL; 134 } 135 136 if (sc->sc_xc3028) 137 xc3028_close(sc->sc_xc3028); 138 if (sc->sc_lg3303) 139 lg3303_close(sc->sc_lg3303); 140 141 if (sc->sc_isoc_pipe) { 142 usbd_abort_pipe(sc->sc_isoc_pipe); 143 usbd_close_pipe(sc->sc_isoc_pipe); 144 sc->sc_isoc_pipe = NULL; 145 } 146} 147 148void 149emdtv_dtv_rescan(struct emdtv_softc *sc, const char *ifattr, const int *locs) 150{ 151 struct dtv_attach_args daa; 152 153 daa.hw = &emdtv_dtv_if; 154 daa.priv = sc; 155 156 if (ifattr_match(ifattr, "dtvbus") && sc->sc_dtvdev == NULL) 157 sc->sc_dtvdev = config_found_ia(sc->sc_dev, "dtvbus", 158 &daa, dtv_print); 159} 160 161static void 162emdtv_dtv_get_devinfo(void *priv, struct dvb_frontend_info *info) 163{ 164 struct emdtv_softc *sc = priv; 165 166 memset(info, 0, sizeof(*info)); 167 strlcpy(info->name, sc->sc_board->eb_name, sizeof(info->name)); 168 info->type = FE_ATSC; 169 info->frequency_min = 54000000; 170 info->frequency_max = 858000000; 171 info->frequency_stepsize = 62500; 172 info->caps = FE_CAN_8VSB; 173} 174 175static int 176emdtv_dtv_open(void *priv, int flags) 177{ 178 struct emdtv_softc *sc = priv; 179 180 if (sc->sc_dying) 181 return ENXIO; 182 183 switch (sc->sc_board->eb_tuner) { 184 case EMDTV_TUNER_XC3028: 185 if (sc->sc_xc3028 == NULL) { 186 sc->sc_xc3028 = xc3028_open(sc->sc_dev, 187 &sc->sc_i2c, 0x61 << 1, emdtv_dtv_tuner_reset, sc, 188 XC3028); 189 } 190 if (sc->sc_xc3028 == NULL) { 191 aprint_error_dev(sc->sc_dev, "couldn't open xc3028\n"); 192 return ENXIO; 193 } 194 break; 195 case EMDTV_TUNER_XC3028L: 196 if (sc->sc_xc3028 == NULL) { 197 sc->sc_xc3028 = xc3028_open(sc->sc_dev, 198 &sc->sc_i2c, 0x61 << 1, emdtv_dtv_tuner_reset, sc, 199 XC3028L); 200 } 201 if (sc->sc_xc3028 == NULL) { 202 aprint_error_dev(sc->sc_dev, "couldn't open xc3028l\n"); 203 return ENXIO; 204 } 205 break; 206 default: 207 aprint_error_dev(sc->sc_dev, "unsupported tuner (%d)\n", 208 sc->sc_board->eb_tuner); 209 return EIO; 210 } 211 212 switch (sc->sc_board->eb_demod) { 213 case EMDTV_DEMOD_LG3303: 214 if (sc->sc_lg3303 == NULL) { 215 sc->sc_lg3303 = lg3303_open(sc->sc_dev, 216 &sc->sc_i2c, 0x1c, 0); 217 } 218 if (sc->sc_lg3303 == NULL) { 219 aprint_error_dev(sc->sc_dev, "couldn't open lg3303\n"); 220 return ENXIO; 221 } 222 break; 223 default: 224 aprint_error_dev(sc->sc_dev, "unsupported demod (%d)\n", 225 sc->sc_board->eb_demod); 226 return EIO; 227 } 228 229 return 0; 230} 231 232static void 233emdtv_dtv_close(void *priv) 234{ 235 return; 236} 237 238static int 239emdtv_dtv_set_tuner(void *priv, const struct dvb_frontend_parameters *params) 240{ 241 struct emdtv_softc *sc = priv; 242 int error; 243 244 /* Setup demod */ 245 error = ENXIO; 246 if (sc->sc_lg3303) 247 error = lg3303_set_modulation(sc->sc_lg3303, 248 params->u.vsb.modulation); 249 if (error) 250 return error; 251 252 /* Setup tuner */ 253 error = ENXIO; 254 if (sc->sc_xc3028) 255 error = xc3028_tune_dtv(sc->sc_xc3028, params); 256 257 return error; 258} 259 260static fe_status_t 261emdtv_dtv_get_status(void *priv) 262{ 263 struct emdtv_softc *sc = priv; 264 265 if (sc->sc_lg3303) 266 return lg3303_get_dtv_status(sc->sc_lg3303); 267 268 return 0; 269} 270 271uint16_t 272emdtv_dtv_get_signal_strength(void *priv) 273{ 274 struct emdtv_softc *sc = priv; 275 276 if (sc->sc_lg3303) 277 return lg3303_get_signal_strength(sc->sc_lg3303); 278 279 return 0; 280} 281 282uint16_t 283emdtv_dtv_get_snr(void *priv) 284{ 285 struct emdtv_softc *sc = priv; 286 287 if (sc->sc_lg3303) 288 return lg3303_get_snr(sc->sc_lg3303); 289 290 return 0; 291} 292 293static int 294emdtv_dtv_start_transfer(void *priv, 295 void (*cb)(void *, const struct dtv_payload *), void *arg) 296{ 297 struct emdtv_softc *sc = priv; 298 int i, s; 299 300 s = splusb(); 301 302 sc->sc_streaming = true; 303 sc->sc_dtvsubmitcb = cb; 304 sc->sc_dtvsubmitarg = arg; 305 306 aprint_debug_dev(sc->sc_dev, "allocating isoc xfers (pktsz %d)\n", 307 sc->sc_isoc_maxpacketsize); 308 309 KERNEL_LOCK(1, curlwp); 310 for (i = 0; i < EMDTV_NXFERS; i++) { 311 sc->sc_ix[i].ix_xfer = usbd_alloc_xfer(sc->sc_udev); 312 sc->sc_ix[i].ix_buf = usbd_alloc_buffer(sc->sc_ix[i].ix_xfer, 313 sc->sc_isoc_buflen); 314 aprint_debug_dev(sc->sc_dev, " ix[%d] xfer %p buf %p\n", 315 i, sc->sc_ix[i].ix_xfer, sc->sc_ix[i].ix_buf); 316 } 317 KERNEL_UNLOCK_ONE(curlwp); 318 319 aprint_debug_dev(sc->sc_dev, "starting isoc transactions\n"); 320 321 emdtv_dtv_isoc_startall(sc); 322 splx(s); 323 324 return 0; 325} 326 327static int 328emdtv_dtv_stop_transfer(void *priv) 329{ 330 struct emdtv_softc *sc = priv; 331 int i; 332 333 aprint_debug_dev(sc->sc_dev, "stopping stream\n"); 334 335 sc->sc_streaming = false; 336 337 KERNEL_LOCK(1, curlwp); 338 if (sc->sc_isoc_pipe != NULL) 339 usbd_abort_pipe(sc->sc_isoc_pipe); 340 341 for (i = 0; i < EMDTV_NXFERS; i++) 342 if (sc->sc_ix[i].ix_xfer) { 343 usbd_free_xfer(sc->sc_ix[i].ix_xfer); 344 sc->sc_ix[i].ix_xfer = NULL; 345 sc->sc_ix[i].ix_buf = NULL; 346 } 347 KERNEL_UNLOCK_ONE(curlwp); 348 349 sc->sc_dtvsubmitcb = NULL; 350 sc->sc_dtvsubmitarg = NULL; 351 352 return 0; 353} 354 355static void 356emdtv_dtv_isoc_startall(struct emdtv_softc *sc) 357{ 358 int i; 359 360 if (sc->sc_streaming == false || sc->sc_dying == true) 361 return; 362 363 for (i = 0; i < EMDTV_NXFERS; i += 2) 364 emdtv_dtv_isoc_start(sc, &sc->sc_ix[i]); 365} 366 367static int 368emdtv_dtv_isoc_start(struct emdtv_softc *sc, struct emdtv_isoc_xfer *ix) 369{ 370 int i; 371 372 if (sc->sc_isoc_pipe == NULL) 373 return EIO; 374 375 for (i = 0; i < EMDTV_NFRAMES; i++) 376 ix->ix_frlengths[i] = sc->sc_isoc_maxpacketsize; 377 378 usbd_setup_isoc_xfer(ix->ix_xfer, 379 sc->sc_isoc_pipe, 380 ix, 381 ix->ix_frlengths, 382 EMDTV_NFRAMES, 383 USBD_NO_COPY | USBD_SHORT_XFER_OK, 384 emdtv_dtv_isoc); 385 386 KERNEL_LOCK(1, curlwp); 387 usbd_transfer(ix->ix_xfer); 388 KERNEL_UNLOCK_ONE(curlwp); 389 390 return 0; 391} 392 393static void 394emdtv_dtv_isoc(usbd_xfer_handle xfer, usbd_private_handle priv, 395 usbd_status err) 396{ 397 struct emdtv_isoc_xfer *ix = priv; 398 struct emdtv_softc *sc = ix->ix_sc; 399 struct dtv_payload payload; 400 usbd_pipe_handle isoc = sc->sc_isoc_pipe; 401 uint32_t len; 402 uint8_t *buf; 403 int i; 404 405 KASSERT(xfer == ix->ix_xfer); 406 407 if (sc->sc_dying || sc->sc_dtvsubmitcb == NULL) 408 return; 409 410 if (err) { 411 if (err == USBD_STALLED) { 412 usbd_clear_endpoint_stall_async(isoc); 413 goto resched; 414 } 415 return; 416 } 417 418 usbd_get_xfer_status(xfer, NULL, NULL, &len, NULL); 419 420 if (len == 0) 421 goto resched; 422 423 buf = usbd_get_buffer(xfer); 424 if (buf == NULL) 425 goto resched; 426 427 for (i = 0; i < EMDTV_NFRAMES; i++, buf += sc->sc_isoc_maxpacketsize) { 428 if (ix->ix_frlengths[i] == 0) 429 continue; 430 payload.data = buf; 431 payload.size = ix->ix_frlengths[i]; 432 sc->sc_dtvsubmitcb(sc->sc_dtvsubmitarg, &payload); 433 } 434 435resched: 436 emdtv_dtv_isoc_start(sc, ix->ix_altix); 437} 438 439static int 440emdtv_dtv_tuner_reset(void *opaque) 441{ 442 struct emdtv_softc *sc = opaque; 443 emdtv_gpio_ctl(sc, EMDTV_GPIO_TUNER1_RESET, true); 444 return 0; 445} 446