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