1/* $NetBSD: emdtv.c,v 1.11 2016/04/23 10:15:31 skrll 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.11 2016/04/23 10:15:31 skrll 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 = min(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
333 if (emdtv_debug_regs) {
334 int i;
335 printf("%s [%s] c0 %02x 00 00 %02x 00 01 00 <<<",
336 __func__, status == 0 ? " OK" : "NOK", req, index);
337 for (i = 0; status == 0 && i < count; i++)
338 printf(" %02x", datap[i]);
339 printf("\n");
340 }
341}
342
343void
344emdtv_write_multi_1(struct emdtv_softc *sc, uint8_t req, uint16_t index,
345 const uint8_t *datap, uint16_t count)
346{
347 usb_device_request_t request;
348 usbd_status status;
349
350 request.bmRequestType = UT_WRITE_VENDOR_DEVICE;
351 request.bRequest = req;
352 USETW(request.wValue, 0x0000);
353 USETW(request.wIndex, index);
354 USETW(request.wLength, count);
355
356 KERNEL_LOCK(1, curlwp);
357 status = usbd_do_request(sc->sc_udev, &request, __UNCONST(datap));
358 KERNEL_UNLOCK_ONE(curlwp);
359
360 if (status != USBD_NORMAL_COMPLETION)
361 aprint_error_dev(sc->sc_dev, "couldn't read %x/%x: %s\n",
362 req, index, usbd_errstr(status));
363
364 if (emdtv_debug_regs) {
365 int i;
366 printf("%s [%s] 40 %02x 00 00 %02x 00 %02x 00 >>>",
367 __func__, status == 0 ? " OK" : "NOK",
368 req, index, count);
369 for (i = 0; i < count; ++i)
370 printf(" %02x", datap[i]);
371 printf("\n");
372 }
373}
374
375bool
376emdtv_gpio_ctl(struct emdtv_softc *sc, emdtv_gpio_reg_t gpioreg, bool onoff)
377{
378 const struct emdtv_board *eb = sc->sc_board;
379 uint16_t gpio_value, reg;
380 uint8_t gpio;
381 uint8_t eeprom_offset = 0x3c;
382 uint8_t val;
383
384 if (sc->sc_board->eb_manual_gpio == false) {
385 val = eeprom_offset + gpioreg;
386 emdtv_write_1(sc, 0x03, 0xa0, val);
387 gpio_value = emdtv_read_1(sc, 0x02, 0xa0);
388 } else {
389 const struct emdtv_gpio_regs *r = &eb->eb_gpio_regs;
390 switch (gpioreg) {
391 case EMDTV_GPIO_TS1_ON:
392 gpio_value = r->ts1_on;
393 break;
394 case EMDTV_GPIO_ANALOG_ON:
395 gpio_value = r->a_on;
396 break;
397 case EMDTV_GPIO_TUNER1_ON:
398 gpio_value = r->t1_on;
399 break;
400 case EMDTV_GPIO_TUNER1_RESET:
401 gpio_value = r->t1_reset;
402 break;
403 case EMDTV_GPIO_DEMOD1_RESET:
404 gpio_value = r->d1_reset;
405 break;
406 default:
407 aprint_error_dev(sc->sc_dev,
408 "unknown gpio reg %d\n", gpioreg);
409 return false;
410 }
411 }
412
413 if ((gpio_value & 0x80) == 0) {
414 aprint_error_dev(sc->sc_dev,
415 "gpio reg %d not enabled\n", gpioreg);
416 return false;
417 }
418
419 reg = gpio_value & 0x10 ? 0x04 : 0x08;
420 gpio = emdtv_read_1(sc, UR_GET_STATUS, reg);
421 if ((gpio_value & 0x40) == 0) {
422 gpio &= ~((uint8_t)(1 << (gpio_value & 7)));
423
424 if (onoff)
425 gpio |= ((gpio_value >> 5) & 1) << (gpio_value & 7);
426 else
427 gpio |= (((gpio_value >> 5) & 1) ^ 1) <<
428 (gpio_value & 7);
429 emdtv_write_1(sc, UR_GET_STATUS, reg, gpio);
430 } else {
431 gpio &= ~((uint8_t)(1 << (gpio_value & 0xf)));
432
433 gpio |= ((gpio_value >> 5) & 1) << (gpio_value & 7);
434 emdtv_write_1(sc, UR_GET_STATUS, reg, gpio);
435 usbd_delay_ms(sc->sc_udev, 100);
436
437 gpio &= ~((uint8_t)(1 << (gpio_value & 0xf)));
438 gpio |= (((gpio_value >> 5) & 1) ^ 1) << (gpio_value & 7);
439 emdtv_write_1(sc, UR_GET_STATUS, reg, gpio);
440 usbd_delay_ms(sc->sc_udev, 100);
441 }
442
443 return true;
444}
445
446static void
447emdtv_default_board_init(struct emdtv_softc *sc)
448{
449 emdtv_write_1(sc, UR_GET_STATUS, EM28XX_XCLK_REG, 0x27);
450 emdtv_write_1(sc, UR_GET_STATUS, EM28XX_I2C_CLK_REG, 0x40);
451 emdtv_write_1(sc, UR_GET_STATUS, 0x08, 0xff);
452 emdtv_write_1(sc, UR_GET_STATUS, 0x04, 0x00);
453 usbd_delay_ms(sc->sc_udev, 100);
454 emdtv_write_1(sc, UR_GET_STATUS, 0x04, 0x08);
455 usbd_delay_ms(sc->sc_udev, 100);
456 emdtv_write_1(sc, UR_GET_STATUS, 0x08, 0xff);
457 usbd_delay_ms(sc->sc_udev, 50);
458 emdtv_write_1(sc, UR_GET_STATUS, 0x08, 0x2d);
459 usbd_delay_ms(sc->sc_udev, 50);
460 emdtv_write_1(sc, UR_GET_STATUS, 0x08, 0x3d);
461 //emdtv_write_1(sc, UR_GET_STATUS, 0x0f, 0xa7);
462 usbd_delay_ms(sc->sc_udev, 10);
463}
464
465MODULE(MODULE_CLASS_DRIVER, emdtv, "cir,lg3303,xc3028");
466
467#ifdef _MODULE
468#include "ioconf.c"
469#endif
470
471static int
472emdtv_modcmd(modcmd_t cmd, void *opaque)
473{
474 switch (cmd) {
475 case MODULE_CMD_INIT:
476#ifdef _MODULE
477 return config_init_component(cfdriver_ioconf_emdtv,
478 cfattach_ioconf_emdtv, cfdata_ioconf_emdtv);
479#else
480 return 0;
481#endif
482 case MODULE_CMD_FINI:
483#ifdef _MODULE
484 return config_fini_component(cfdriver_ioconf_emdtv,
485 cfattach_ioconf_emdtv, cfdata_ioconf_emdtv);
486#else
487 return 0;
488#endif
489 default:
490 return ENOTTY;
491 }
492}
493