emdtv.c revision 1.4
1/* $NetBSD: emdtv.c,v 1.4 2011/08/09 01:42:24 jmcneill Exp $ */ 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: emdtv.c,v 1.4 2011/08/09 01:42:24 jmcneill Exp $"); 31 32#include <sys/param.h> 33#include <sys/systm.h> 34#include <sys/device.h> 35#include <sys/module.h> 36#include <sys/conf.h> 37 38#include <dev/usb/usb.h> 39#include <dev/usb/usbdi.h> 40#include <dev/usb/usbdi_util.h> 41#include <dev/usb/usbdevs.h> 42 43#include <dev/usb/emdtvvar.h> 44#include <dev/usb/emdtvreg.h> 45 46static int emdtv_match(device_t, cfdata_t, void *); 47static void emdtv_attach(device_t, device_t, void *); 48static int emdtv_detach(device_t, int); 49static int emdtv_rescan(device_t, const char *, const int *); 50static void emdtv_childdet(device_t, device_t); 51static int emdtv_activate(device_t, enum devact); 52 53static bool emdtv_read_eeprom(struct emdtv_softc *); 54static void emdtv_board_setup(struct emdtv_softc *); 55 56static void emdtv_default_board_init(struct emdtv_softc *); 57 58CFATTACH_DECL2_NEW(emdtv, sizeof(struct emdtv_softc), 59 emdtv_match, emdtv_attach, emdtv_detach, emdtv_activate, 60 emdtv_rescan, emdtv_childdet); 61 62static const struct usb_devno emdtv_devices[] = { 63 { USB_VENDOR_AMD, USB_PRODUCT_AMD_TV_WONDER_600_USB }, 64 { USB_VENDOR_PINNACLE, USB_PRODUCT_PINNACLE_PCTV800E }, 65}; 66 67int emdtv_debug_regs = 0; 68 69static int 70emdtv_match(device_t parent, cfdata_t match, void *opaque) 71{ 72 struct usb_attach_arg *uaa = opaque; 73 74 return usb_lookup(emdtv_devices, uaa->vendor, uaa->product) != NULL ? 75 UMATCH_VENDOR_PRODUCT : UMATCH_NONE; 76} 77 78static void 79emdtv_attach(device_t parent, device_t self, void *opaque) 80{ 81 struct emdtv_softc *sc = device_private(self); 82 struct usb_attach_arg *uaa = opaque; 83 usbd_device_handle dev = uaa->device; 84 usbd_status status; 85 char *devinfo; 86 87 devinfo = usbd_devinfo_alloc(dev, 0); 88 aprint_naive("\n"); 89 aprint_normal(": %s\n", devinfo); 90 usbd_devinfo_free(devinfo); 91 92 sc->sc_dev = self; 93 sc->sc_udev = dev; 94 95 sc->sc_vendor = uaa->vendor; 96 sc->sc_product = uaa->product; 97 98 emdtv_i2c_attach(sc); 99 100 emdtv_read_eeprom(sc); 101 102 sc->sc_board = emdtv_board_lookup(sc->sc_vendor, sc->sc_product); 103 if (sc->sc_board == NULL) { 104 aprint_error_dev(sc->sc_dev, 105 "unsupported board 0x%04x:0x%04x\n", 106 sc->sc_vendor, sc->sc_product); 107 sc->sc_dying = true; 108 return; 109 } 110 111 emdtv_write_1(sc, 0x02, 0xa0, 0x23); 112 if (emdtv_read_1(sc, UR_GET_STATUS, 0x05) != 0) { 113 (void)emdtv_read_1(sc, 0x02, 0xa0); 114 if (emdtv_read_1(sc, 0x02, 0xa0) & 0x08) 115 aprint_debug_dev(sc->sc_dev, 116 "board requires manual gpio configuration\n"); 117 } 118 119 emdtv_board_setup(sc); 120 121 emdtv_gpio_ctl(sc, EMDTV_GPIO_ANALOG_ON, false); 122 emdtv_gpio_ctl(sc, EMDTV_GPIO_TS1_ON, false); 123 usbd_delay_ms(sc->sc_udev, 100); 124 emdtv_gpio_ctl(sc, EMDTV_GPIO_ANALOG_ON, true); 125 emdtv_gpio_ctl(sc, EMDTV_GPIO_TUNER1_ON, true); 126 usbd_delay_ms(sc->sc_udev, 100); 127 128 status = usbd_set_config_no(sc->sc_udev, 1, 1); 129 if (status != USBD_NORMAL_COMPLETION) { 130 aprint_error_dev(sc->sc_dev, "couldn't set config no\n"); 131 return; 132 } 133 134 status = usbd_device2interface_handle(sc->sc_udev, 0, &sc->sc_iface); 135 if (status != USBD_NORMAL_COMPLETION) { 136 aprint_error_dev(sc->sc_dev, "couldn't find iface handle\n"); 137 return; 138 } 139 140 status = usbd_set_interface(sc->sc_iface, 1); 141 if (status != USBD_NORMAL_COMPLETION) { 142 aprint_error_dev(sc->sc_dev, "couldn't set interface\n"); 143 return; 144 } 145 146 emdtv_dtv_attach(sc); 147 emdtv_ir_attach(sc); 148} 149 150static int 151emdtv_detach(device_t self, int flags) 152{ 153 struct emdtv_softc *sc = device_private(self); 154 usbd_status status; 155 156 sc->sc_dying = true; 157 158 emdtv_ir_detach(sc, flags); 159 emdtv_dtv_detach(sc, flags); 160 161 if (sc->sc_iface != NULL) { 162 status = usbd_set_interface(sc->sc_iface, 0); 163 if (status != USBD_NORMAL_COMPLETION) 164 aprint_error_dev(sc->sc_dev, 165 "couldn't stop stream: %s\n", usbd_errstr(status)); 166 } 167 168 emdtv_i2c_detach(sc, flags); 169 170 return 0; 171} 172 173int 174emdtv_activate(device_t self, enum devact act) 175{ 176 struct emdtv_softc *sc = device_private(self); 177 178 switch (act) { 179 case DVACT_DEACTIVATE: 180 sc->sc_dying = true; 181 break; 182 } 183 184 return 0; 185} 186 187static int 188emdtv_rescan(device_t self, const char *ifattr, const int *locs) 189{ 190 struct emdtv_softc *sc = device_private(self); 191 192 emdtv_dtv_rescan(sc, ifattr, locs); 193 194 return 0; 195} 196 197static void 198emdtv_childdet(device_t self, device_t child) 199{ 200 struct emdtv_softc *sc = device_private(self); 201 202 if (child == sc->sc_cirdev) 203 sc->sc_cirdev = NULL; 204 if (child == sc->sc_dtvdev) 205 sc->sc_dtvdev = NULL; 206} 207 208static bool 209emdtv_read_eeprom(struct emdtv_softc *sc) 210{ 211 i2c_addr_t ee = EM28XX_I2C_ADDR_EEPROM; 212 uint8_t buf, *p = sc->sc_eeprom; 213 struct emdtv_eeprom *eeprom = (struct emdtv_eeprom *)sc->sc_eeprom; 214 int block, size = sizeof(sc->sc_eeprom); 215 216 if (iic_exec(&sc->sc_i2c, I2C_OP_READ, ee, NULL, 0, NULL, 0, 0)) 217 return false; 218 buf = 0; 219 if (iic_exec(&sc->sc_i2c, I2C_OP_WRITE_WITH_STOP, ee, &buf, 1, 220 NULL, 0, 0)) 221 return false; 222 while (size > 0) { 223 block = min(size, 16); 224 if (iic_exec(&sc->sc_i2c, I2C_OP_READ, ee, NULL, 0, 225 p, block, 0)) 226 return false; 227 size -= block; 228 p += block; 229 } 230 231 aprint_normal_dev(sc->sc_dev, 232 "id 0x%08x vendor 0x%04x product 0x%04x\n", 233 eeprom->id, eeprom->vendor, eeprom->product); 234 235 sc->sc_vendor = eeprom->vendor; 236 sc->sc_product = eeprom->product; 237 238 return true; 239} 240 241static void 242emdtv_board_setup(struct emdtv_softc *sc) 243{ 244 switch (sc->sc_vendor) { 245 case USB_VENDOR_EMPIA: 246 switch (sc->sc_product) { 247 case USB_PRODUCT_EMPIA_EM2883: 248 emdtv_write_1(sc, UR_GET_STATUS, EM28XX_XCLK_REG, 0x97); 249 emdtv_write_1(sc, UR_GET_STATUS, EM28XX_I2C_CLK_REG, 250 0x40); 251 delay(10000); 252 emdtv_write_1(sc, UR_GET_STATUS, 0x08, 0x2d); 253 delay(10000); 254 break; 255 default: 256 aprint_normal_dev(sc->sc_dev, 257 "unknown EMPIA board 0x%04x/0x%04x\n", 258 sc->sc_vendor, sc->sc_product); 259 break; 260 } 261 break; 262 case USB_VENDOR_AMD: 263 switch (sc->sc_product) { 264 case USB_PRODUCT_AMD_TV_WONDER_600_USB: 265 emdtv_default_board_init(sc); 266 break; 267 default: 268 aprint_normal_dev(sc->sc_dev, 269 "unknown AMD board 0x%04x/0x%04x\n", 270 sc->sc_vendor, sc->sc_product); 271 } 272 break; 273 case USB_VENDOR_PINNACLE: 274 switch (sc->sc_product) { 275 case USB_PRODUCT_PINNACLE_PCTV800E: 276 emdtv_default_board_init(sc); 277 break; 278 default: 279 aprint_normal_dev(sc->sc_dev, 280 "unknown Pinnacle board 0x%04x/0x%04x\n", 281 sc->sc_vendor, sc->sc_product); 282 } 283 break; 284 default: 285 aprint_normal_dev(sc->sc_dev, 286 "unknown board 0x%04x:0x%04x\n", 287 sc->sc_vendor, sc->sc_product); 288 break; 289 } 290} 291 292/* 293 * Register read/write 294 */ 295uint8_t 296emdtv_read_1(struct emdtv_softc *sc, uint8_t req, uint16_t index) 297{ 298 uint8_t val; 299 emdtv_read_multi_1(sc, req, index, &val, 1); 300 return val; 301} 302 303void 304emdtv_write_1(struct emdtv_softc *sc, uint8_t req, uint16_t index, uint8_t val) 305{ 306 emdtv_write_multi_1(sc, req, index, &val, 1); 307} 308 309void 310emdtv_read_multi_1(struct emdtv_softc *sc, uint8_t req, uint16_t index, 311 uint8_t *datap, uint16_t count) 312{ 313 usb_device_request_t request; 314 usbd_status status; 315 316 request.bmRequestType = UT_READ_VENDOR_DEVICE; 317 request.bRequest = req; 318 USETW(request.wValue, 0x0000); 319 USETW(request.wIndex, index); 320 USETW(request.wLength, count); 321 322 status = usbd_do_request(sc->sc_udev, &request, datap); 323 if (status != USBD_NORMAL_COMPLETION) 324 aprint_error_dev(sc->sc_dev, "couldn't read %x/%x: %s\n", 325 req, index, usbd_errstr(status)); 326 327 if (emdtv_debug_regs) { 328 int i; 329 printf("%s [%s] c0 %02x 00 00 %02x 00 01 00 <<<", 330 __func__, status == 0 ? " OK" : "NOK", req, index); 331 for (i = 0; status == 0 && i < count; i++) 332 printf(" %02x", datap[i]); 333 printf("\n"); 334 } 335} 336 337void 338emdtv_write_multi_1(struct emdtv_softc *sc, uint8_t req, uint16_t index, 339 const uint8_t *datap, uint16_t count) 340{ 341 usb_device_request_t request; 342 usbd_status status; 343 344 request.bmRequestType = UT_WRITE_VENDOR_DEVICE; 345 request.bRequest = req; 346 USETW(request.wValue, 0x0000); 347 USETW(request.wIndex, index); 348 USETW(request.wLength, count); 349 350 status = usbd_do_request(sc->sc_udev, &request, __UNCONST(datap)); 351 if (status != USBD_NORMAL_COMPLETION) 352 aprint_error_dev(sc->sc_dev, "couldn't read %x/%x: %s\n", 353 req, index, usbd_errstr(status)); 354 355 if (emdtv_debug_regs) { 356 int i; 357 printf("%s [%s] 40 %02x 00 00 %02x 00 %02x 00 >>>", 358 __func__, status == 0 ? " OK" : "NOK", 359 req, index, count); 360 for (i = 0; i < count; ++i) 361 printf(" %02x", datap[i]); 362 printf("\n"); 363 } 364} 365 366bool 367emdtv_gpio_ctl(struct emdtv_softc *sc, emdtv_gpio_reg_t gpioreg, bool onoff) 368{ 369 const struct emdtv_board *eb = sc->sc_board; 370 uint16_t gpio_value, reg; 371 uint8_t gpio; 372 uint8_t eeprom_offset = 0x3c; 373 uint8_t val; 374 375 if (sc->sc_board->eb_manual_gpio == false) { 376 val = eeprom_offset + gpioreg; 377 emdtv_write_1(sc, 0x03, 0xa0, val); 378 gpio_value = emdtv_read_1(sc, 0x02, 0xa0); 379 } else { 380 const struct emdtv_gpio_regs *r = &eb->eb_gpio_regs; 381 switch (gpioreg) { 382 case EMDTV_GPIO_TS1_ON: 383 gpio_value = r->ts1_on; 384 break; 385 case EMDTV_GPIO_ANALOG_ON: 386 gpio_value = r->a_on; 387 break; 388 case EMDTV_GPIO_TUNER1_ON: 389 gpio_value = r->t1_on; 390 break; 391 case EMDTV_GPIO_TUNER1_RESET: 392 gpio_value = r->t1_reset; 393 break; 394 case EMDTV_GPIO_DEMOD1_RESET: 395 gpio_value = r->d1_reset; 396 break; 397 default: 398 aprint_error_dev(sc->sc_dev, 399 "unknown gpio reg %d\n", gpioreg); 400 return false; 401 } 402 } 403 404 if ((gpio_value & 0x80) == 0) { 405 aprint_error_dev(sc->sc_dev, 406 "gpio reg %d not enabled\n", gpioreg); 407 return false; 408 } 409 410 reg = gpio_value & 0x10 ? 0x04 : 0x08; 411 gpio = emdtv_read_1(sc, UR_GET_STATUS, reg); 412 if ((gpio_value & 0x40) == 0) { 413 gpio &= ~((uint8_t)(1 << (gpio_value & 7))); 414 415 if (onoff) 416 gpio |= ((gpio_value >> 5) & 1) << (gpio_value & 7); 417 else 418 gpio |= (((gpio_value >> 5) & 1) ^ 1) << 419 (gpio_value & 7); 420 emdtv_write_1(sc, UR_GET_STATUS, reg, gpio); 421 } else { 422 gpio &= ~((uint8_t)(1 << (gpio_value & 0xf))); 423 424 gpio |= ((gpio_value >> 5) & 1) << (gpio_value & 7); 425 emdtv_write_1(sc, UR_GET_STATUS, reg, gpio); 426 usbd_delay_ms(sc->sc_udev, 100); 427 428 gpio &= ~((uint8_t)(1 << (gpio_value & 0xf))); 429 gpio |= (((gpio_value >> 5) & 1) ^ 1) << (gpio_value & 7); 430 emdtv_write_1(sc, UR_GET_STATUS, reg, gpio); 431 usbd_delay_ms(sc->sc_udev, 100); 432 } 433 434 return true; 435} 436 437static void 438emdtv_default_board_init(struct emdtv_softc *sc) 439{ 440 emdtv_write_1(sc, UR_GET_STATUS, EM28XX_XCLK_REG, 0x27); 441 emdtv_write_1(sc, UR_GET_STATUS, EM28XX_I2C_CLK_REG, 0x40); 442 emdtv_write_1(sc, UR_GET_STATUS, 0x08, 0xff); 443 emdtv_write_1(sc, UR_GET_STATUS, 0x04, 0x00); 444 usbd_delay_ms(sc->sc_udev, 100); 445 emdtv_write_1(sc, UR_GET_STATUS, 0x04, 0x08); 446 usbd_delay_ms(sc->sc_udev, 100); 447 emdtv_write_1(sc, UR_GET_STATUS, 0x08, 0xff); 448 usbd_delay_ms(sc->sc_udev, 50); 449 emdtv_write_1(sc, UR_GET_STATUS, 0x08, 0x2d); 450 usbd_delay_ms(sc->sc_udev, 50); 451 emdtv_write_1(sc, UR_GET_STATUS, 0x08, 0x3d); 452 //emdtv_write_1(sc, UR_GET_STATUS, 0x0f, 0xa7); 453 usbd_delay_ms(sc->sc_udev, 10); 454} 455 456MODULE(MODULE_CLASS_DRIVER, emdtv, "cir,lg3303,xc3028"); 457 458#ifdef _MODULE 459#include "ioconf.c" 460#endif 461 462static int 463emdtv_modcmd(modcmd_t cmd, void *opaque) 464{ 465 switch (cmd) { 466 case MODULE_CMD_INIT: 467#ifdef _MODULE 468 return config_init_component(cfdriver_ioconf_emdtv, 469 cfattach_ioconf_emdtv, cfdata_ioconf_emdtv); 470#else 471 return 0; 472#endif 473 case MODULE_CMD_FINI: 474#ifdef _MODULE 475 return config_fini_component(cfdriver_ioconf_emdtv, 476 cfattach_ioconf_emdtv, cfdata_ioconf_emdtv); 477#else 478 return 0; 479#endif 480 default: 481 return ENOTTY; 482 } 483} 484