emdtv.c revision 1.18
1/* $NetBSD: emdtv.c,v 1.18 2022/06/26 22:49:09 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.18 2022/06/26 22:49:09 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 sc->sc_subdevs_attached = true; 152} 153 154static int 155emdtv_detach(device_t self, int flags) 156{ 157 struct emdtv_softc *sc = device_private(self); 158 usbd_status status; 159 int error; 160 161 sc->sc_dying = true; 162 163 error = config_detach_children(self, flags); 164 if (error) 165 return error; 166 167 if (sc->sc_subdevs_attached) { 168 emdtv_ir_detach(sc, flags); 169 emdtv_dtv_detach(sc, flags); 170 } 171 172 if (sc->sc_iface != NULL) { 173 status = usbd_set_interface(sc->sc_iface, 0); 174 if (status != USBD_NORMAL_COMPLETION) 175 aprint_error_dev(sc->sc_dev, 176 "couldn't stop stream: %s\n", usbd_errstr(status)); 177 } 178 179 emdtv_i2c_detach(sc, flags); 180 181 return 0; 182} 183 184int 185emdtv_activate(device_t self, enum devact act) 186{ 187 struct emdtv_softc *sc = device_private(self); 188 189 switch (act) { 190 case DVACT_DEACTIVATE: 191 sc->sc_dying = true; 192 break; 193 } 194 195 return 0; 196} 197 198static int 199emdtv_rescan(device_t self, const char *ifattr, const int *locs) 200{ 201 struct emdtv_softc *sc = device_private(self); 202 203 emdtv_dtv_rescan(sc, ifattr, locs); 204 205 return 0; 206} 207 208static void 209emdtv_childdet(device_t self, device_t child) 210{ 211 struct emdtv_softc *sc = device_private(self); 212 213 if (child == sc->sc_cirdev) 214 sc->sc_cirdev = NULL; 215 if (child == sc->sc_dtvdev) 216 sc->sc_dtvdev = NULL; 217} 218 219static bool 220emdtv_read_eeprom(struct emdtv_softc *sc) 221{ 222 i2c_addr_t ee = EM28XX_I2C_ADDR_EEPROM; 223 uint8_t buf, *p = sc->sc_eeprom; 224 struct emdtv_eeprom *eeprom = (struct emdtv_eeprom *)sc->sc_eeprom; 225 int block, size = sizeof(sc->sc_eeprom); 226 227 if (iic_exec(&sc->sc_i2c, I2C_OP_READ, ee, NULL, 0, NULL, 0, 0)) 228 return false; 229 buf = 0; 230 if (iic_exec(&sc->sc_i2c, I2C_OP_WRITE_WITH_STOP, ee, &buf, 1, 231 NULL, 0, 0)) 232 return false; 233 while (size > 0) { 234 block = uimin(size, 16); 235 if (iic_exec(&sc->sc_i2c, I2C_OP_READ, ee, NULL, 0, 236 p, block, 0)) 237 return false; 238 size -= block; 239 p += block; 240 } 241 242 aprint_normal_dev(sc->sc_dev, 243 "id 0x%08x vendor 0x%04x product 0x%04x\n", 244 eeprom->id, eeprom->vendor, eeprom->product); 245 246 sc->sc_vendor = eeprom->vendor; 247 sc->sc_product = eeprom->product; 248 249 return true; 250} 251 252static void 253emdtv_board_setup(struct emdtv_softc *sc) 254{ 255 switch (sc->sc_vendor) { 256 case USB_VENDOR_EMPIA: 257 switch (sc->sc_product) { 258 case USB_PRODUCT_EMPIA_EM2883: 259 emdtv_write_1(sc, UR_GET_STATUS, EM28XX_XCLK_REG, 0x97); 260 emdtv_write_1(sc, UR_GET_STATUS, EM28XX_I2C_CLK_REG, 261 0x40); 262 delay(10000); 263 emdtv_write_1(sc, UR_GET_STATUS, 0x08, 0x2d); 264 delay(10000); 265 break; 266 default: 267 aprint_normal_dev(sc->sc_dev, 268 "unknown EMPIA board 0x%04x/0x%04x\n", 269 sc->sc_vendor, sc->sc_product); 270 break; 271 } 272 break; 273 case USB_VENDOR_AMD: 274 switch (sc->sc_product) { 275 case USB_PRODUCT_AMD_TV_WONDER_600_USB: 276 emdtv_default_board_init(sc); 277 break; 278 default: 279 aprint_normal_dev(sc->sc_dev, 280 "unknown AMD board 0x%04x/0x%04x\n", 281 sc->sc_vendor, sc->sc_product); 282 } 283 break; 284 case USB_VENDOR_PINNACLE: 285 switch (sc->sc_product) { 286 case USB_PRODUCT_PINNACLE_PCTV800E: 287 emdtv_default_board_init(sc); 288 break; 289 default: 290 aprint_normal_dev(sc->sc_dev, 291 "unknown Pinnacle board 0x%04x/0x%04x\n", 292 sc->sc_vendor, sc->sc_product); 293 } 294 break; 295 default: 296 aprint_normal_dev(sc->sc_dev, 297 "unknown board 0x%04x:0x%04x\n", 298 sc->sc_vendor, sc->sc_product); 299 break; 300 } 301} 302 303/* 304 * Register read/write 305 */ 306uint8_t 307emdtv_read_1(struct emdtv_softc *sc, uint8_t req, uint16_t index) 308{ 309 uint8_t val; 310 emdtv_read_multi_1(sc, req, index, &val, 1); 311 return val; 312} 313 314void 315emdtv_write_1(struct emdtv_softc *sc, uint8_t req, uint16_t index, uint8_t val) 316{ 317 emdtv_write_multi_1(sc, req, index, &val, 1); 318} 319 320void 321emdtv_read_multi_1(struct emdtv_softc *sc, uint8_t req, uint16_t index, 322 uint8_t *datap, uint16_t count) 323{ 324 usb_device_request_t request; 325 usbd_status status; 326 327 request.bmRequestType = UT_READ_VENDOR_DEVICE; 328 request.bRequest = req; 329 USETW(request.wValue, 0x0000); 330 USETW(request.wIndex, index); 331 USETW(request.wLength, count); 332 333 KERNEL_LOCK(1, curlwp); 334 status = usbd_do_request(sc->sc_udev, &request, datap); 335 KERNEL_UNLOCK_ONE(curlwp); 336 337 if (status != USBD_NORMAL_COMPLETION) { 338 aprint_error_dev(sc->sc_dev, "couldn't read %x/%x: %s\n", 339 req, index, usbd_errstr(status)); 340 memset(datap, 0, count); 341 } 342 343 if (emdtv_debug_regs) { 344 int i; 345 printf("%s [%s] c0 %02x 00 00 %02x 00 01 00 <<<", 346 __func__, status == 0 ? " OK" : "NOK", req, index); 347 for (i = 0; status == 0 && i < count; i++) 348 printf(" %02x", datap[i]); 349 printf("\n"); 350 } 351} 352 353void 354emdtv_write_multi_1(struct emdtv_softc *sc, uint8_t req, uint16_t index, 355 const uint8_t *datap, uint16_t count) 356{ 357 usb_device_request_t request; 358 usbd_status status; 359 360 request.bmRequestType = UT_WRITE_VENDOR_DEVICE; 361 request.bRequest = req; 362 USETW(request.wValue, 0x0000); 363 USETW(request.wIndex, index); 364 USETW(request.wLength, count); 365 366 KERNEL_LOCK(1, curlwp); 367 status = usbd_do_request(sc->sc_udev, &request, __UNCONST(datap)); 368 KERNEL_UNLOCK_ONE(curlwp); 369 370 if (status != USBD_NORMAL_COMPLETION) 371 aprint_error_dev(sc->sc_dev, "couldn't read %x/%x: %s\n", 372 req, index, usbd_errstr(status)); 373 374 if (emdtv_debug_regs) { 375 int i; 376 printf("%s [%s] 40 %02x 00 00 %02x 00 %02x 00 >>>", 377 __func__, status == 0 ? " OK" : "NOK", 378 req, index, count); 379 for (i = 0; i < count; ++i) 380 printf(" %02x", datap[i]); 381 printf("\n"); 382 } 383} 384 385bool 386emdtv_gpio_ctl(struct emdtv_softc *sc, emdtv_gpio_reg_t gpioreg, bool onoff) 387{ 388 const struct emdtv_board *eb = sc->sc_board; 389 uint16_t gpio_value, reg; 390 uint8_t gpio; 391 uint8_t eeprom_offset = 0x3c; 392 uint8_t val; 393 394 if (sc->sc_board->eb_manual_gpio == false) { 395 val = eeprom_offset + gpioreg; 396 emdtv_write_1(sc, 0x03, 0xa0, val); 397 gpio_value = emdtv_read_1(sc, 0x02, 0xa0); 398 } else { 399 const struct emdtv_gpio_regs *r = &eb->eb_gpio_regs; 400 switch (gpioreg) { 401 case EMDTV_GPIO_TS1_ON: 402 gpio_value = r->ts1_on; 403 break; 404 case EMDTV_GPIO_ANALOG_ON: 405 gpio_value = r->a_on; 406 break; 407 case EMDTV_GPIO_TUNER1_ON: 408 gpio_value = r->t1_on; 409 break; 410 case EMDTV_GPIO_TUNER1_RESET: 411 gpio_value = r->t1_reset; 412 break; 413 case EMDTV_GPIO_DEMOD1_RESET: 414 gpio_value = r->d1_reset; 415 break; 416 default: 417 aprint_error_dev(sc->sc_dev, 418 "unknown gpio reg %d\n", gpioreg); 419 return false; 420 } 421 } 422 423 if ((gpio_value & 0x80) == 0) { 424 aprint_error_dev(sc->sc_dev, 425 "gpio reg %d not enabled\n", gpioreg); 426 return false; 427 } 428 429 reg = gpio_value & 0x10 ? 0x04 : 0x08; 430 gpio = emdtv_read_1(sc, UR_GET_STATUS, reg); 431 if ((gpio_value & 0x40) == 0) { 432 gpio &= ~((uint8_t)(1 << (gpio_value & 7))); 433 434 if (onoff) 435 gpio |= ((gpio_value >> 5) & 1) << (gpio_value & 7); 436 else 437 gpio |= (((gpio_value >> 5) & 1) ^ 1) << 438 (gpio_value & 7); 439 emdtv_write_1(sc, UR_GET_STATUS, reg, gpio); 440 } else { 441 gpio &= ~((uint8_t)(1 << (gpio_value & 0xf))); 442 443 gpio |= ((gpio_value >> 5) & 1) << (gpio_value & 7); 444 emdtv_write_1(sc, UR_GET_STATUS, reg, gpio); 445 usbd_delay_ms(sc->sc_udev, 100); 446 447 gpio &= ~((uint8_t)(1 << (gpio_value & 0xf))); 448 gpio |= (((gpio_value >> 5) & 1) ^ 1) << (gpio_value & 7); 449 emdtv_write_1(sc, UR_GET_STATUS, reg, gpio); 450 usbd_delay_ms(sc->sc_udev, 100); 451 } 452 453 return true; 454} 455 456static void 457emdtv_default_board_init(struct emdtv_softc *sc) 458{ 459 emdtv_write_1(sc, UR_GET_STATUS, EM28XX_XCLK_REG, 0x27); 460 emdtv_write_1(sc, UR_GET_STATUS, EM28XX_I2C_CLK_REG, 0x40); 461 emdtv_write_1(sc, UR_GET_STATUS, 0x08, 0xff); 462 emdtv_write_1(sc, UR_GET_STATUS, 0x04, 0x00); 463 usbd_delay_ms(sc->sc_udev, 100); 464 emdtv_write_1(sc, UR_GET_STATUS, 0x04, 0x08); 465 usbd_delay_ms(sc->sc_udev, 100); 466 emdtv_write_1(sc, UR_GET_STATUS, 0x08, 0xff); 467 usbd_delay_ms(sc->sc_udev, 50); 468 emdtv_write_1(sc, UR_GET_STATUS, 0x08, 0x2d); 469 usbd_delay_ms(sc->sc_udev, 50); 470 emdtv_write_1(sc, UR_GET_STATUS, 0x08, 0x3d); 471 //emdtv_write_1(sc, UR_GET_STATUS, 0x0f, 0xa7); 472 usbd_delay_ms(sc->sc_udev, 10); 473} 474 475MODULE(MODULE_CLASS_DRIVER, emdtv, "cir,lg3303,xc3028"); 476 477#ifdef _MODULE 478#include "ioconf.c" 479#endif 480 481static int 482emdtv_modcmd(modcmd_t cmd, void *opaque) 483{ 484 switch (cmd) { 485 case MODULE_CMD_INIT: 486#ifdef _MODULE 487 return config_init_component(cfdriver_ioconf_emdtv, 488 cfattach_ioconf_emdtv, cfdata_ioconf_emdtv); 489#else 490 return 0; 491#endif 492 case MODULE_CMD_FINI: 493#ifdef _MODULE 494 return config_fini_component(cfdriver_ioconf_emdtv, 495 cfattach_ioconf_emdtv, cfdata_ioconf_emdtv); 496#else 497 return 0; 498#endif 499 default: 500 return ENOTTY; 501 } 502} 503