Module Name: src Committed By: jmcneill Date: Sat Jul 9 15:00:45 UTC 2011
Modified Files: src/sys/dev/i2c: au8522.c au8522var.h xc5k.c xc5kreg.h xc5kvar.h src/sys/dev/usb: auvitek.c auvitek_board.c auvitek_i2c.c auvitek_video.c auvitekvar.h Added Files: src/sys/dev/i2c: au8522mod.h au8522mod_8vsb.h au8522mod_qam256.h au8522mod_qam64.h src/sys/dev/usb: auvitek_dtv.c Log Message: add digital capture support To generate a diff of this commit: cvs rdiff -u -r1.3 -r1.4 src/sys/dev/i2c/au8522.c cvs rdiff -u -r0 -r1.1 src/sys/dev/i2c/au8522mod.h \ src/sys/dev/i2c/au8522mod_8vsb.h src/sys/dev/i2c/au8522mod_qam256.h \ src/sys/dev/i2c/au8522mod_qam64.h cvs rdiff -u -r1.2 -r1.3 src/sys/dev/i2c/au8522var.h src/sys/dev/i2c/xc5k.c cvs rdiff -u -r1.1 -r1.2 src/sys/dev/i2c/xc5kreg.h src/sys/dev/i2c/xc5kvar.h cvs rdiff -u -r1.3 -r1.4 src/sys/dev/usb/auvitek.c \ src/sys/dev/usb/auvitek_video.c cvs rdiff -u -r1.2 -r1.3 src/sys/dev/usb/auvitek_board.c \ src/sys/dev/usb/auvitekvar.h cvs rdiff -u -r0 -r1.1 src/sys/dev/usb/auvitek_dtv.c cvs rdiff -u -r1.1 -r1.2 src/sys/dev/usb/auvitek_i2c.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/i2c/au8522.c diff -u src/sys/dev/i2c/au8522.c:1.3 src/sys/dev/i2c/au8522.c:1.4 --- src/sys/dev/i2c/au8522.c:1.3 Thu May 26 23:42:05 2011 +++ src/sys/dev/i2c/au8522.c Sat Jul 9 15:00:43 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: au8522.c,v 1.3 2011/05/26 23:42:05 jmcneill Exp $ */ +/* $NetBSD: au8522.c,v 1.4 2011/07/09 15:00:43 jmcneill Exp $ */ /*- * Copyright (c) 2010 Jared D. McNeill <jmcne...@invisible.ca> @@ -31,7 +31,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: au8522.c,v 1.3 2011/05/26 23:42:05 jmcneill Exp $"); +__KERNEL_RCSID(0, "$NetBSD: au8522.c,v 1.4 2011/07/09 15:00:43 jmcneill Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -41,10 +41,13 @@ #include <sys/kmem.h> #include <sys/module.h> +#include <dev/dtv/dtvio.h> + #include <dev/i2c/i2cvar.h> #include <dev/i2c/au8522reg.h> #include <dev/i2c/au8522var.h> +#include <dev/i2c/au8522mod.h> static int au8522_reset(struct au8522 *); static int au8522_read_1(struct au8522 *, uint16_t, uint8_t *); @@ -187,8 +190,31 @@ return 0; } +static int +au8522_set_if(struct au8522 *au) +{ + uint8_t ifinit[3]; + unsigned int n; + + switch (au->if_freq) { + case 6000000: /* 6MHz */ + ifinit[0] = 0xfb; + ifinit[1] = 0x8e; + ifinit[2] = 0x39; + break; + default: + aprint_error_dev(au->parent, "au8522: unsupported if freq %dHz\n", au->if_freq); + return EINVAL; + } + + for (n = 0; n < __arraycount(ifinit); n++) + au8522_write_1(au, 0x80b5 + n, ifinit[n]); + + return 0; +} + struct au8522 * -au8522_open(device_t parent, i2c_tag_t i2c, i2c_addr_t addr) +au8522_open(device_t parent, i2c_tag_t i2c, i2c_addr_t addr, unsigned int if_freq) { struct au8522 *au; @@ -198,6 +224,8 @@ au->parent = parent; au->i2c = i2c; au->i2c_addr = addr; + au->current_modulation = -1; + au->if_freq = if_freq; if (au8522_reset(au)) goto failed; @@ -271,6 +299,90 @@ } } +int +au8522_set_modulation(struct au8522 *au, fe_modulation_t modulation) +{ + const struct au8522_modulation_table *modtab = NULL; + size_t modtablen; + unsigned int n; + + switch (modulation) { + case VSB_8: + modtab = au8522_modulation_8vsb; + modtablen = __arraycount(au8522_modulation_8vsb); + break; + case QAM_64: + modtab = au8522_modulation_qam64; + modtablen = __arraycount(au8522_modulation_qam64); + break; + case QAM_256: + modtab = au8522_modulation_qam256; + modtablen = __arraycount(au8522_modulation_qam256); + break; + default: + return EINVAL; + } + + for (n = 0; n < modtablen; n++) + au8522_write_1(au, modtab[n].reg, modtab[n].val); + + au8522_set_if(au); + + au->current_modulation = modulation; + + return 0; +} + +void +au8522_set_gate(struct au8522 *au, bool onoff) +{ + au8522_write_1(au, AU8522_REG_TUNERCTL, onoff ? AU8522_TUNERCTL_EN : 0); +} + +fe_status_t +au8522_get_dtv_status(struct au8522 *au) +{ + fe_status_t status = 0; + uint8_t val; + + //printf("%s: current_modulation = %d\n", __func__, + // au->current_modulation); + + switch (au->current_modulation) { + case VSB_8: + if (au8522_read_1(au, 0x4088, &val)) + return 0; + if ((val & 0x03) == 0x03) { + status |= FE_HAS_SIGNAL; + status |= FE_HAS_CARRIER; + status |= FE_HAS_VITERBI; + } + break; + case QAM_64: + case QAM_256: + if (au8522_read_1(au, 0x4541, &val)) + return 0; + if (val & 0x80) { + status |= FE_HAS_VITERBI; + } + if (val & 0x20) { + status |= FE_HAS_SIGNAL; + status |= FE_HAS_CARRIER; + } + break; + default: + break; + } + + if (status & FE_HAS_VITERBI) { + status |= FE_HAS_SYNC; + status |= FE_HAS_LOCK; + } + + //printf("%s: status = 0x%x\n", __func__, status); + return status; +} + MODULE(MODULE_CLASS_DRIVER, au8522, NULL); static int Index: src/sys/dev/i2c/au8522var.h diff -u src/sys/dev/i2c/au8522var.h:1.2 src/sys/dev/i2c/au8522var.h:1.3 --- src/sys/dev/i2c/au8522var.h:1.2 Thu May 26 23:42:05 2011 +++ src/sys/dev/i2c/au8522var.h Sat Jul 9 15:00:44 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: au8522var.h,v 1.2 2011/05/26 23:42:05 jmcneill Exp $ */ +/* $NetBSD: au8522var.h,v 1.3 2011/07/09 15:00:44 jmcneill Exp $ */ /*- * Copyright (c) 2010 Jared D. McNeill <jmcne...@invisible.ca> @@ -30,11 +30,16 @@ #define _AU8522VAR_H #include <dev/i2c/i2cvar.h> +#include <dev/dtv/dtvio.h> struct au8522 { device_t parent; i2c_tag_t i2c; i2c_addr_t i2c_addr; + + unsigned int if_freq; + + fe_modulation_t current_modulation; }; typedef enum { @@ -51,7 +56,7 @@ AU8522_AINPUT_SIF, } au8522_ainput_t; -struct au8522 * au8522_open(device_t, i2c_tag_t, i2c_addr_t); +struct au8522 * au8522_open(device_t, i2c_tag_t, i2c_addr_t, unsigned int); void au8522_close(struct au8522 *); void au8522_enable(struct au8522 *, bool); @@ -59,5 +64,8 @@ au8522_vinput_t, au8522_ainput_t); int au8522_get_signal(struct au8522 *); void au8522_set_audio(struct au8522 *, bool); +int au8522_set_modulation(struct au8522 *, fe_modulation_t); +void au8522_set_gate(struct au8522 *, bool); +fe_status_t au8522_get_dtv_status(struct au8522 *); #endif /* !_AU8522VAR_H */ Index: src/sys/dev/i2c/xc5k.c diff -u src/sys/dev/i2c/xc5k.c:1.2 src/sys/dev/i2c/xc5k.c:1.3 --- src/sys/dev/i2c/xc5k.c:1.2 Tue Dec 28 00:11:50 2010 +++ src/sys/dev/i2c/xc5k.c Sat Jul 9 15:00:44 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: xc5k.c,v 1.2 2010/12/28 00:11:50 jmcneill Exp $ */ +/* $NetBSD: xc5k.c,v 1.3 2011/07/09 15:00:44 jmcneill Exp $ */ /*- * Copyright (c) 2010 Jared D. McNeill <jmcne...@invisible.ca> @@ -31,7 +31,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: xc5k.c,v 1.2 2010/12/28 00:11:50 jmcneill Exp $"); +__KERNEL_RCSID(0, "$NetBSD: xc5k.c,v 1.3 2011/07/09 15:00:44 jmcneill Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -51,6 +51,9 @@ #define XC5K_FIRMWARE_DRVNAME "xc5k" #define XC5K_FIRMWARE_IMGNAME "dvb-fe-xc5000-1.6.114.fw" +#define XC5K_FREQ_MIN 1000000 +#define XC5K_FREQ_MAX 1023000000 + static kmutex_t xc5k_firmware_lock; static int xc5k_reset(struct xc5k *); @@ -126,7 +129,7 @@ xc5k_firmware_open(struct xc5k *xc) { firmware_handle_t fwh; - uint16_t product_id; + uint16_t product_id, xcversion, xcbuild; uint8_t *fw = NULL; size_t fwlen; int error; @@ -156,6 +159,18 @@ aprint_normal_dev(xc->parent, "xc5k: loading firmware '%s/%s'\n", XC5K_FIRMWARE_DRVNAME, XC5K_FIRMWARE_IMGNAME); error = xc5k_firmware_upload(xc, fw, fwlen); + if (!error) { + xc5k_read_2(xc, XC5K_REG_VERSION, &xcversion); + xc5k_read_2(xc, XC5K_REG_BUILD, &xcbuild); + if (!error) + aprint_normal_dev(xc->parent, + "xc5k: hw %d.%d, fw %d.%d.%d\n", + (xcversion >> 12) & 0xf, + (xcversion >> 8) & 0xf, + (xcversion >> 4) & 0xf, + xcversion & 0xf, + xcbuild); + } done: if (fw) @@ -228,7 +243,8 @@ struct xc5k * xc5k_open(device_t parent, i2c_tag_t i2c, i2c_addr_t addr, - xc5k_reset_cb reset, void *reset_priv) + xc5k_reset_cb reset, void *reset_priv, unsigned int if_freq, + fe_type_t fe_type) { struct xc5k *xc; uint16_t product_id; @@ -241,6 +257,8 @@ xc->i2c_addr = addr; xc->reset = reset; xc->reset_priv = reset_priv; + xc->if_freq = if_freq; + xc->fe_type = fe_type; if (xc5k_read_2(xc, XC5K_REG_PRODUCT_ID, &product_id)) goto failed; @@ -275,7 +293,7 @@ } int -xc5k_tune(struct xc5k *xc, struct xc5k_params *params) +xc5k_tune_video(struct xc5k *xc, struct xc5k_params *params) { uint16_t amode, vmode; uint16_t lock, freq; @@ -298,9 +316,11 @@ return EIO; if (xc5k_write_2(xc, XC5K_REG_AUDIO_MODE, amode)) return EIO; + if (xc5k_write_2(xc, XC5K_REG_OUTAMP, XC5K_OUTAMP_ANALOG)) + return EIO; freq = (params->frequency * 62500) / 15625; #ifdef XC5K_DEBUG - printf("xc5k_tune: frequency=%u (%u Hz)\n", params->frequency, + printf("xc5k_tune_video: frequency=%u (%u Hz)\n", params->frequency, params->frequency * 62500); printf(" freq=%u\n", freq); #endif @@ -312,7 +332,7 @@ if (xc5k_read_2(xc, XC5K_REG_LOCK, &lock)) return EIO; #ifdef XC5K_DEBUG - printf("xc5k_tune: lock=0x%04x\n", lock); + printf("xc5k_tune_video: lock=0x%04x\n", lock); #endif if (lock == 1) break; @@ -322,6 +342,98 @@ return 0; } +int +xc5k_tune_dtv(struct xc5k *xc, const struct dvb_frontend_parameters *params) +{ + uint16_t amode, vmode; + uint32_t freq, ifout; + int signal_source; + fe_modulation_t modulation; + + if (xc->fe_type == FE_ATSC) + modulation = params->u.vsb.modulation; + else if (xc->fe_type == FE_QAM) + modulation = params->u.qam.modulation; + else + return EINVAL; + + switch (modulation) { + case VSB_8: + case VSB_16: + signal_source = XC5K_SIGNAL_SOURCE_AIR; + switch (xc->fe_type) { + case FE_ATSC: + amode = XC5K_AUDIO_MODE_DTV6; + vmode = XC5K_VIDEO_MODE_DTV6; + freq = params->frequency - 1750000; + break; + default: + return EINVAL; + } + break; + case QAM_16: + case QAM_32: + case QAM_64: + case QAM_128: + case QAM_256: + signal_source = XC5K_SIGNAL_SOURCE_CABLE; + switch (xc->fe_type) { + case FE_ATSC: + amode = XC5K_AUDIO_MODE_DTV6; + vmode = XC5K_VIDEO_MODE_DTV6; + freq = params->frequency - 1750000; + break; + case FE_QAM: + amode = XC5K_AUDIO_MODE_DTV78; + vmode = XC5K_VIDEO_MODE_DTV78; + freq = params->frequency - 2750000; + break; + default: + return EINVAL; + } + break; + default: + return EINVAL; + } + + if (freq > XC5K_FREQ_MAX || freq < XC5K_FREQ_MIN) + return ERANGE; + + if (xc5k_write_2(xc, XC5K_REG_SIGNAL_SOURCE, signal_source)) + return EIO; + if (xc5k_write_2(xc, XC5K_REG_VIDEO_MODE, vmode)) + return EIO; + if (xc5k_write_2(xc, XC5K_REG_AUDIO_MODE, amode)) + return EIO; + ifout = ((xc->if_freq / 1000) * 1024) / 1000; + if (xc5k_write_2(xc, XC5K_REG_IF_OUT, ifout)) + return EIO; + if (xc5k_write_2(xc, XC5K_REG_OUTAMP, XC5K_OUTAMP_DIGITAL)) + return EIO; + freq = (uint16_t)(freq / 15625); + if (xc5k_write_2(xc, XC5K_REG_FINER_FREQ, freq)) + return EIO; + + return 0; +} + +fe_status_t +xc5k_get_status(struct xc5k *xc) +{ + uint16_t lock_status; + fe_status_t festatus = 0; + + if (xc5k_read_2(xc, XC5K_REG_LOCK, &lock_status)) + return 0; + if (lock_status & XC5K_LOCK_LOCKED) { + festatus |= FE_HAS_LOCK; + if ((lock_status & XC5K_LOCK_NOSIGNAL) == 0) + festatus |= FE_HAS_SIGNAL; + } + + return festatus; +} + MODULE(MODULE_CLASS_DRIVER, xc5k, NULL); static int @@ -329,7 +441,7 @@ { switch (cmd) { case MODULE_CMD_INIT: - mutex_init(&xc5k_firmware_lock, MUTEX_DEFAULT, IPL_VM); + mutex_init(&xc5k_firmware_lock, MUTEX_DEFAULT, IPL_NONE); return 0; case MODULE_CMD_FINI: mutex_destroy(&xc5k_firmware_lock); Index: src/sys/dev/i2c/xc5kreg.h diff -u src/sys/dev/i2c/xc5kreg.h:1.1 src/sys/dev/i2c/xc5kreg.h:1.2 --- src/sys/dev/i2c/xc5kreg.h:1.1 Mon Dec 27 15:42:11 2010 +++ src/sys/dev/i2c/xc5kreg.h Sat Jul 9 15:00:44 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: xc5kreg.h,v 1.1 2010/12/27 15:42:11 jmcneill Exp $ */ +/* $NetBSD: xc5kreg.h,v 1.2 2011/07/09 15:00:44 jmcneill Exp $ */ /*- * Copyright (c) 2010 Jared D. McNeill <jmcne...@invisible.ca> @@ -33,13 +33,24 @@ #define XC5K_REG_INIT 0x00 #define XC5K_REG_VIDEO_MODE 0x01 #define XC5K_VIDEO_MODE_BTSC 0x8028 +#define XC5K_VIDEO_MODE_DTV6 0x8002 +#define XC5K_VIDEO_MODE_DTV7 0x8007 +#define XC5K_VIDEO_MODE_DTV8 0x800b +#define XC5K_VIDEO_MODE_DTV78 0x801b #define XC5K_REG_AUDIO_MODE 0x02 #define XC5K_AUDIO_MODE_BTSC 0x0400 +#define XC5K_AUDIO_MODE_DTV6 0x00c0 +#define XC5K_AUDIO_MODE_DTV7 0x00c0 +#define XC5K_AUDIO_MODE_DTV8 0x00c0 +#define XC5K_AUDIO_MODE_DTV78 0x00c0 #define XC5K_REG_RF_FREQ 0x03 #define XC5K_REG_D_CODE 0x04 #define XC5K_REG_IF_OUT 0x05 #define XC5K_REG_SEEK_MODE 0x07 #define XC5K_REG_POWER_DOWN 0x0a +#define XC5K_REG_OUTAMP 0x0b +#define XC5K_OUTAMP_DIGITAL 0x008a +#define XC5K_OUTAMP_ANALOG 0x0009 #define XC5K_REG_SIGNAL_SOURCE 0x0d #define XC5K_SIGNAL_SOURCE_AIR 0 #define XC5K_SIGNAL_SOURCE_CABLE 1 @@ -54,6 +65,8 @@ #define XC5K_REG_FRAME_LINES 0x02 #define XC5K_REG_HSYNC_FREQ 0x03 #define XC5K_REG_LOCK 0x04 +#define XC5K_LOCK_LOCKED 0x0001 +#define XC5K_LOCK_NOSIGNAL 0x0002 #define XC5K_REG_FREQ_ERR 0x05 #define XC5K_REG_SNR 0x06 #define XC5K_REG_VERSION 0x07 Index: src/sys/dev/i2c/xc5kvar.h diff -u src/sys/dev/i2c/xc5kvar.h:1.1 src/sys/dev/i2c/xc5kvar.h:1.2 --- src/sys/dev/i2c/xc5kvar.h:1.1 Mon Dec 27 15:42:11 2010 +++ src/sys/dev/i2c/xc5kvar.h Sat Jul 9 15:00:44 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: xc5kvar.h,v 1.1 2010/12/27 15:42:11 jmcneill Exp $ */ +/* $NetBSD: xc5kvar.h,v 1.2 2011/07/09 15:00:44 jmcneill Exp $ */ /*- * Copyright (c) 2010 Jared D. McNeill <jmcne...@invisible.ca> @@ -30,6 +30,7 @@ #define _XC5KVAR_H #include <dev/i2c/i2cvar.h> +#include <dev/dtv/dtvio.h> #include <dev/video_if.h> typedef int (*xc5k_reset_cb)(void *); @@ -41,6 +42,9 @@ xc5k_reset_cb reset; void *reset_priv; + + unsigned int if_freq; + fe_type_t fe_type; }; struct xc5k_params { @@ -50,8 +54,10 @@ }; struct xc5k * xc5k_open(device_t, i2c_tag_t, i2c_addr_t, - xc5k_reset_cb, void *); + xc5k_reset_cb, void *, unsigned int, fe_type_t); void xc5k_close(struct xc5k *); -int xc5k_tune(struct xc5k *, struct xc5k_params *); +int xc5k_tune_video(struct xc5k *, struct xc5k_params *); +int xc5k_tune_dtv(struct xc5k *, const struct dvb_frontend_parameters *); +fe_status_t xc5k_get_status(struct xc5k *); #endif /* !_XC5KVAR_H */ Index: src/sys/dev/usb/auvitek.c diff -u src/sys/dev/usb/auvitek.c:1.3 src/sys/dev/usb/auvitek.c:1.4 --- src/sys/dev/usb/auvitek.c:1.3 Tue Dec 28 04:02:33 2010 +++ src/sys/dev/usb/auvitek.c Sat Jul 9 15:00:44 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: auvitek.c,v 1.3 2010/12/28 04:02:33 jmcneill Exp $ */ +/* $NetBSD: auvitek.c,v 1.4 2011/07/09 15:00:44 jmcneill Exp $ */ /*- * Copyright (c) 2010 Jared D. McNeill <jmcne...@invisible.ca> @@ -31,7 +31,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: auvitek.c,v 1.3 2010/12/28 04:02:33 jmcneill Exp $"); +__KERNEL_RCSID(0, "$NetBSD: auvitek.c,v 1.4 2011/07/09 15:00:44 jmcneill Exp $"); #include <sys/types.h> #include <sys/param.h> @@ -115,7 +115,9 @@ sc->sc_dying = sc->sc_running = 0; - mutex_init(&sc->sc_subdev_lock, MUTEX_DEFAULT, IPL_VM); + mutex_init(&sc->sc_subdev_lock, MUTEX_DEFAULT, IPL_NONE); + mutex_init(&sc->sc_ab.ab_lock, MUTEX_DEFAULT, IPL_USB); + cv_init(&sc->sc_ab.ab_cv, "auvitekbulk"); err = usbd_set_config_index(dev, 0, 1); if (err) { @@ -123,14 +125,23 @@ usbd_errstr(err)); return; } - err = usbd_device2interface_handle(dev, 0, &sc->sc_iface); + err = usbd_device2interface_handle(dev, 0, &sc->sc_isoc_iface); + if (err) { + aprint_error_dev(self, "couldn't get interface handle: %s\n", + usbd_errstr(err)); + return; + } + err = usbd_device2interface_handle(dev, 3, &sc->sc_bulk_iface); if (err) { aprint_error_dev(self, "couldn't get interface handle: %s\n", usbd_errstr(err)); return; } - err = usbd_set_interface(sc->sc_iface, AUVITEK_XFER_ALTNO); + sc->sc_ax.ax_sc = sc->sc_ab.ab_sc = sc; + sc->sc_ax.ax_endpt = sc->sc_ab.ab_endpt = -1; + + err = usbd_set_interface(sc->sc_isoc_iface, AUVITEK_XFER_ALTNO); if (err) { aprint_error_dev(self, "couldn't set interface: %s\n", usbd_errstr(err)); @@ -138,13 +149,11 @@ } nep = 0; - usbd_endpoint_count(sc->sc_iface, &nep); - sc->sc_ax.ax_sc = sc; - sc->sc_ax.ax_endpt = -1; + usbd_endpoint_count(sc->sc_isoc_iface, &nep); for (i = 0; i < nep; i++) { int dir, type; - ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i); + ed = usbd_interface2endpoint_descriptor(sc->sc_isoc_iface, i); if (ed == NULL) { aprint_error_dev(self, "couldn't read endpoint descriptor %d\n", i); @@ -154,21 +163,22 @@ dir = UE_GET_DIR(ed->bEndpointAddress); type = UE_GET_XFERTYPE(ed->bmAttributes); - if (dir == UE_DIR_IN && type == UE_ISOCHRONOUS) { + if (dir == UE_DIR_IN && type == UE_ISOCHRONOUS && + sc->sc_ax.ax_endpt == -1) { sc->sc_ax.ax_endpt = ed->bEndpointAddress; sc->sc_ax.ax_maxpktlen = UE_GET_SIZE(UGETW(ed->wMaxPacketSize)) * (UE_GET_TRANS(UGETW(ed->wMaxPacketSize)) + 1); - break; } } - err = usbd_set_interface(sc->sc_iface, 0); + + err = usbd_set_interface(sc->sc_isoc_iface, 0); if (err) { aprint_error_dev(self, "couldn't set interface: %s\n", usbd_errstr(err)); - sc->sc_dying = 1; return; } + if (sc->sc_ax.ax_endpt == -1) { aprint_error_dev(self, "couldn't find isoc endpoint\n"); sc->sc_dying = 1; @@ -183,11 +193,60 @@ aprint_debug_dev(self, "isoc endpoint 0x%02x size %d\n", sc->sc_ax.ax_endpt, sc->sc_ax.ax_maxpktlen); + nep = 0; + usbd_endpoint_count(sc->sc_bulk_iface, &nep); + for (i = 0; i < nep; i++) { + int dir, type; + + ed = usbd_interface2endpoint_descriptor(sc->sc_bulk_iface, i); + if (ed == NULL) { + aprint_error_dev(self, + "couldn't read endpoint descriptor %d\n", i); + continue; + } + + dir = UE_GET_DIR(ed->bEndpointAddress); + type = UE_GET_XFERTYPE(ed->bmAttributes); + + if (dir == UE_DIR_IN && type == UE_BULK && + sc->sc_ab.ab_endpt == -1) { + sc->sc_ab.ab_endpt = ed->bEndpointAddress; + } + } + + if (sc->sc_ab.ab_endpt == -1) { + aprint_error_dev(self, "couldn't find bulk endpoint\n"); + sc->sc_dying = 1; + return; + } + + for (i = 0; i < AUVITEK_NBULK_XFERS; i++) { + sc->sc_ab.ab_bx[i].bx_sc = sc; + sc->sc_ab.ab_bx[i].bx_xfer = usbd_alloc_xfer(sc->sc_udev); + if (sc->sc_ab.ab_bx[i].bx_xfer == NULL) { + aprint_error_dev(self, "couldn't allocate xfer\n"); + sc->sc_dying = 1; + return; + } + sc->sc_ab.ab_bx[i].bx_buffer = usbd_alloc_buffer( + sc->sc_ab.ab_bx[i].bx_xfer, AUVITEK_BULK_BUFLEN); + if (sc->sc_ab.ab_bx[i].bx_buffer == NULL) { + aprint_error_dev(self, + "couldn't allocate xfer buffer\n"); + sc->sc_dying = 1; + return; + } + } + + aprint_debug_dev(self, "bulk endpoint 0x%02x size %d\n", + sc->sc_ab.ab_endpt, AUVITEK_BULK_BUFLEN); + auvitek_board_init(sc); auvitek_i2c_attach(sc); - sc->sc_au8522 = au8522_open(self, &sc->sc_i2c, 0x8e >> 1); + sc->sc_au8522 = au8522_open(self, &sc->sc_i2c, 0x8e >> 1, + auvitek_board_get_if_frequency(sc)); if (sc->sc_au8522 == NULL) { aprint_error_dev(sc->sc_dev, "couldn't initialize decoder\n"); sc->sc_dying = 1; @@ -196,17 +255,20 @@ auvitek_video_attach(sc); auvitek_audio_attach(sc); + auvitek_dtv_attach(sc); } static int auvitek_detach(device_t self, int flags) { struct auvitek_softc *sc = device_private(self); + unsigned int i; sc->sc_dying = 1; pmf_device_deregister(self); + auvitek_dtv_detach(sc, flags); auvitek_audio_detach(sc, flags); auvitek_video_detach(sc, flags); @@ -219,6 +281,13 @@ mutex_destroy(&sc->sc_subdev_lock); + for (i = 0; i < AUVITEK_NBULK_XFERS; i++) { + if (sc->sc_ab.ab_bx[i].bx_xfer) + usbd_free_xfer(sc->sc_ab.ab_bx[i].bx_xfer); + } + cv_destroy(&sc->sc_ab.ab_cv); + mutex_destroy(&sc->sc_ab.ab_lock); + return 0; } @@ -242,6 +311,8 @@ struct auvitek_softc *sc = device_private(self); auvitek_video_childdet(sc, child); + auvitek_audio_childdet(sc, child); + auvitek_dtv_childdet(sc, child); } uint8_t @@ -287,7 +358,7 @@ usbd_errstr(err)); } -MODULE(MODULE_CLASS_DRIVER, auvitek, "au8522,xc5k"); +MODULE(MODULE_CLASS_DRIVER, auvitek, "au8522,xc5k,dtv"); #ifdef _MODULE #include "ioconf.c" Index: src/sys/dev/usb/auvitek_video.c diff -u src/sys/dev/usb/auvitek_video.c:1.3 src/sys/dev/usb/auvitek_video.c:1.4 --- src/sys/dev/usb/auvitek_video.c:1.3 Thu May 26 23:42:39 2011 +++ src/sys/dev/usb/auvitek_video.c Sat Jul 9 15:00:45 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: auvitek_video.c,v 1.3 2011/05/26 23:42:39 jmcneill Exp $ */ +/* $NetBSD: auvitek_video.c,v 1.4 2011/07/09 15:00:45 jmcneill Exp $ */ /*- * Copyright (c) 2010 Jared D. McNeill <jmcne...@invisible.ca> @@ -31,7 +31,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: auvitek_video.c,v 1.3 2011/05/26 23:42:39 jmcneill Exp $"); +__KERNEL_RCSID(0, "$NetBSD: auvitek_video.c,v 1.4 2011/07/09 15:00:45 jmcneill Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -100,9 +100,8 @@ uint8_t *, uint32_t); static void auvitek_videobuf_weave(struct auvitek_softc *, uint8_t *, uint32_t); -static int auvitek_tuner_reset(void *); -static const struct video_hw_if auvitek_hw_if = { +static const struct video_hw_if auvitek_video_if = { .open = auvitek_open, .close = auvitek_close, .get_devname = auvitek_get_devname, @@ -133,7 +132,7 @@ { snprintf(sc->sc_businfo, sizeof(sc->sc_businfo), "usb:%08x", sc->sc_udev->cookie.cookie); - sc->sc_videodev = video_attach_mi(&auvitek_hw_if, sc->sc_dev); + sc->sc_videodev = video_attach_mi(&auvitek_video_if, sc->sc_dev); return (sc->sc_videodev != NULL); } @@ -167,7 +166,9 @@ mutex_enter(&sc->sc_subdev_lock); if (sc->sc_xc5k == NULL) { sc->sc_xc5k = xc5k_open(sc->sc_dev, &sc->sc_i2c, 0xc2 >> 1, - auvitek_tuner_reset, sc); + auvitek_board_tuner_reset, sc, + auvitek_board_get_if_frequency(sc), + FE_ATSC); } mutex_exit(&sc->sc_subdev_lock); @@ -525,7 +526,7 @@ params.frequency = vf->frequency; if (sc->sc_au8522) au8522_set_audio(sc->sc_au8522, false); - error = xc5k_tune(sc->sc_xc5k, ¶ms); + error = xc5k_tune_video(sc->sc_xc5k, ¶ms); if (sc->sc_au8522) au8522_set_audio(sc->sc_au8522, true); if (error) @@ -548,7 +549,7 @@ usbd_status err; int i; - err = usbd_set_interface(sc->sc_iface, AUVITEK_XFER_ALTNO); + err = usbd_set_interface(sc->sc_isoc_iface, AUVITEK_XFER_ALTNO); if (err != USBD_NORMAL_COMPLETION) { aprint_error_dev(sc->sc_dev, "couldn't set altno %d: %s\n", AUVITEK_XFER_ALTNO, usbd_errstr(err)); @@ -562,7 +563,7 @@ ax->ax_nframes = nframes; ax->ax_uframe_len = uframe_len; - for (i = 0; i < AUVITEK_NXFERS; i++) { + for (i = 0; i < AUVITEK_NISOC_XFERS; i++) { struct auvitek_isoc *isoc = &ax->ax_i[i]; isoc->i_ax = ax; isoc->i_frlengths = @@ -570,7 +571,7 @@ KM_SLEEP); } - err = usbd_open_pipe(sc->sc_iface, ax->ax_endpt, + err = usbd_open_pipe(sc->sc_isoc_iface, ax->ax_endpt, USBD_EXCLUSIVE_USE, &ax->ax_pipe); if (err != USBD_NORMAL_COMPLETION) { aprint_error_dev(sc->sc_dev, "couldn't open pipe: %s\n", @@ -578,7 +579,7 @@ return EIO; } - for (i = 0; i < AUVITEK_NXFERS; i++) { + for (i = 0; i < AUVITEK_NISOC_XFERS; i++) { struct auvitek_isoc *isoc = &ax->ax_i[i]; isoc->i_xfer = usbd_alloc_xfer(sc->sc_udev); @@ -613,7 +614,7 @@ ax->ax_pipe = NULL; } - for (i = 0; i < AUVITEK_NXFERS; i++) { + for (i = 0; i < AUVITEK_NISOC_XFERS; i++) { struct auvitek_isoc *isoc = &ax->ax_i[i]; if (isoc->i_xfer != NULL) { usbd_free_buffer(isoc->i_xfer); @@ -628,7 +629,7 @@ } usbd_delay_ms(sc->sc_udev, 1000); - err = usbd_set_interface(sc->sc_iface, 0); + err = usbd_set_interface(sc->sc_isoc_iface, 0); if (err != USBD_NORMAL_COMPLETION) { aprint_error_dev(sc->sc_dev, "couldn't set zero bw interface: %s\n", @@ -649,7 +650,7 @@ ax->ax_av.av_eb = ax->ax_av.av_ob = 0; ax->ax_av.av_stride = 720 * 2; - for (i = 0; i < AUVITEK_NXFERS; i++) { + for (i = 0; i < AUVITEK_NISOC_XFERS; i++) { error = auvitek_isoc_start1(&ax->ax_i[i]); if (error) return error; @@ -797,11 +798,3 @@ resid -= wlen; } } - -static int -auvitek_tuner_reset(void *priv) -{ - struct auvitek_softc *sc = priv; - - return auvitek_board_tuner_reset(sc); -} Index: src/sys/dev/usb/auvitek_board.c diff -u src/sys/dev/usb/auvitek_board.c:1.2 src/sys/dev/usb/auvitek_board.c:1.3 --- src/sys/dev/usb/auvitek_board.c:1.2 Tue Dec 28 04:02:33 2010 +++ src/sys/dev/usb/auvitek_board.c Sat Jul 9 15:00:44 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: auvitek_board.c,v 1.2 2010/12/28 04:02:33 jmcneill Exp $ */ +/* $NetBSD: auvitek_board.c,v 1.3 2011/07/09 15:00:44 jmcneill Exp $ */ /*- * Copyright (c) 2010 Jared D. McNeill <jmcne...@invisible.ca> @@ -31,7 +31,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: auvitek_board.c,v 1.2 2010/12/28 04:02:33 jmcneill Exp $"); +__KERNEL_RCSID(0, "$NetBSD: auvitek_board.c,v 1.3 2011/07/09 15:00:44 jmcneill Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -97,8 +97,9 @@ } int -auvitek_board_tuner_reset(struct auvitek_softc *sc) +auvitek_board_tuner_reset(void *priv) { + struct auvitek_softc *sc = priv; uint8_t val; switch (sc->sc_board) { @@ -117,3 +118,9 @@ return 0; } + +unsigned int +auvitek_board_get_if_frequency(struct auvitek_softc *sc) +{ + return 6000000; /* 6MHz */ +} Index: src/sys/dev/usb/auvitekvar.h diff -u src/sys/dev/usb/auvitekvar.h:1.2 src/sys/dev/usb/auvitekvar.h:1.3 --- src/sys/dev/usb/auvitekvar.h:1.2 Tue Dec 28 04:02:33 2010 +++ src/sys/dev/usb/auvitekvar.h Sat Jul 9 15:00:45 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: auvitekvar.h,v 1.2 2010/12/28 04:02:33 jmcneill Exp $ */ +/* $NetBSD: auvitekvar.h,v 1.3 2011/07/09 15:00:45 jmcneill Exp $ */ /*- * Copyright (c) 2010 Jared D. McNeill <jmcne...@invisible.ca> @@ -30,6 +30,8 @@ #define _AUVITEKVAR_H #include <sys/mutex.h> +#include <sys/condvar.h> +#include <sys/kthread.h> #include <dev/usb/usb.h> #include <dev/usb/usbdi.h> @@ -47,8 +49,10 @@ AUVITEK_BOARD_HVR_950Q, }; -#define AUVITEK_NXFERS 8 +#define AUVITEK_NISOC_XFERS 16 +#define AUVITEK_NBULK_XFERS 1 #define AUVITEK_XFER_ALTNO 5 +#define AUVITEK_BULK_BUFLEN 58658 /* BDA driver uses the same */ struct auvitek_isoc { struct auvitek_xfer *i_ax; @@ -69,7 +73,7 @@ int ax_endpt; uint16_t ax_maxpktlen; usbd_pipe_handle ax_pipe; - struct auvitek_isoc ax_i[AUVITEK_NXFERS]; + struct auvitek_isoc ax_i[AUVITEK_NISOC_XFERS]; uint32_t ax_nframes; uint32_t ax_uframe_len; uint8_t ax_frinfo; @@ -77,15 +81,32 @@ struct auvitek_videobuf ax_av; }; +struct auvitek_bulk_xfer { + struct auvitek_softc *bx_sc; + usbd_xfer_handle bx_xfer; + uint8_t *bx_buffer; +}; + +struct auvitek_bulk { + struct auvitek_softc *ab_sc; + int ab_endpt; + usbd_pipe_handle ab_pipe; + struct auvitek_bulk_xfer ab_bx[AUVITEK_NBULK_XFERS]; + bool ab_running; + kmutex_t ab_lock; + kcondvar_t ab_cv; +}; + struct auvitek_softc { device_t sc_dev; - device_t sc_videodev, sc_audiodev; + device_t sc_videodev, sc_dtvdev, sc_audiodev; struct i2c_controller sc_i2c; kmutex_t sc_i2c_lock; usbd_device_handle sc_udev; int sc_uport; - usbd_interface_handle sc_iface; + usbd_interface_handle sc_isoc_iface; + usbd_interface_handle sc_bulk_iface; char sc_running; char sc_dying; @@ -102,6 +123,7 @@ uint32_t sc_curfreq; struct auvitek_xfer sc_ax; + struct auvitek_bulk sc_ab; char sc_businfo[32]; }; @@ -117,7 +139,8 @@ /* auvitek_board.c */ void auvitek_board_init(struct auvitek_softc *); -int auvitek_board_tuner_reset(struct auvitek_softc *); +int auvitek_board_tuner_reset(void *); +unsigned int auvitek_board_get_if_frequency(struct auvitek_softc *); /* auvitek_i2c.c */ int auvitek_i2c_attach(struct auvitek_softc *); @@ -128,4 +151,9 @@ int auvitek_video_detach(struct auvitek_softc *, int); void auvitek_video_childdet(struct auvitek_softc *, device_t); +/* auvitek_dtv.c */ +int auvitek_dtv_attach(struct auvitek_softc *); +int auvitek_dtv_detach(struct auvitek_softc *, int); +void auvitek_dtv_childdet(struct auvitek_softc *, device_t); + #endif /* !_AUVITEKVAR_H */ Index: src/sys/dev/usb/auvitek_i2c.c diff -u src/sys/dev/usb/auvitek_i2c.c:1.1 src/sys/dev/usb/auvitek_i2c.c:1.2 --- src/sys/dev/usb/auvitek_i2c.c:1.1 Mon Dec 27 15:42:11 2010 +++ src/sys/dev/usb/auvitek_i2c.c Sat Jul 9 15:00:45 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: auvitek_i2c.c,v 1.1 2010/12/27 15:42:11 jmcneill Exp $ */ +/* $NetBSD: auvitek_i2c.c,v 1.2 2011/07/09 15:00:45 jmcneill Exp $ */ /*- * Copyright (c) 2010 Jared D. McNeill <jmcne...@invisible.ca> @@ -31,7 +31,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: auvitek_i2c.c,v 1.1 2010/12/27 15:42:11 jmcneill Exp $"); +__KERNEL_RCSID(0, "$NetBSD: auvitek_i2c.c,v 1.2 2011/07/09 15:00:45 jmcneill Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -121,7 +121,7 @@ uint8_t v; unsigned int i; - KASSERT(mutex_owned(&sc->sc_i2c_lock)); + //KASSERT(mutex_owned(&sc->sc_i2c_lock)); auvitek_write_1(sc, AU0828_REG_I2C_MBMODE, 1); auvitek_write_1(sc, AU0828_REG_I2C_CLKDIV, sc->sc_i2c_clkdiv); @@ -160,7 +160,7 @@ uint8_t v; unsigned int i, fifolen; - KASSERT(mutex_owned(&sc->sc_i2c_lock)); + //KASSERT(mutex_owned(&sc->sc_i2c_lock)); auvitek_write_1(sc, AU0828_REG_I2C_MBMODE, 1); auvitek_write_1(sc, AU0828_REG_I2C_CLKDIV, sc->sc_i2c_clkdiv); Added files: Index: src/sys/dev/i2c/au8522mod.h diff -u /dev/null src/sys/dev/i2c/au8522mod.h:1.1 --- /dev/null Sat Jul 9 15:00:45 2011 +++ src/sys/dev/i2c/au8522mod.h Sat Jul 9 15:00:43 2011 @@ -0,0 +1,41 @@ +/* $NetBSD: au8522mod.h,v 1.1 2011/07/09 15:00:43 jmcneill Exp $ */ + +/*- + * Copyright (c) 2011 Jared D. McNeill <jmcne...@invisible.ca> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _AU8522MOD_H +#define _AU8522MOD_H + +struct au8522_modulation_table { + uint16_t reg; + uint8_t val; +}; + +#include <dev/i2c/au8522mod_8vsb.h> +#include <dev/i2c/au8522mod_qam64.h> +#include <dev/i2c/au8522mod_qam256.h> + +#endif /* !_AU8522MOD_H */ Index: src/sys/dev/i2c/au8522mod_8vsb.h diff -u /dev/null src/sys/dev/i2c/au8522mod_8vsb.h:1.1 --- /dev/null Sat Jul 9 15:00:46 2011 +++ src/sys/dev/i2c/au8522mod_8vsb.h Sat Jul 9 15:00:43 2011 @@ -0,0 +1,57 @@ +/* $NetBSD: au8522mod_8vsb.h,v 1.1 2011/07/09 15:00:43 jmcneill Exp $ */ + +/*- + * Copyright (c) 2011 Jared D. McNeill <jmcne...@invisible.ca> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +static const struct au8522_modulation_table au8522_modulation_8vsb[] = { + { 0x8090, 0x84 }, + { 0x4092, 0x11 }, + { 0x2005, 0x00 }, + { 0x8091, 0x80 }, + { 0x80a3, 0x0c }, + { 0x80a4, 0xe8 }, + { 0x8081, 0xc4 }, + { 0x80a5, 0x40 }, + { 0x80a7, 0x40 }, + { 0x80a6, 0x67 }, + { 0x8262, 0x20 }, + { 0x821c, 0x30 }, + { 0x80d8, 0x1a }, + { 0x8227, 0xa0 }, + { 0x8121, 0xff }, + { 0x80a8, 0xf0 }, + { 0x80a9, 0x05 }, + { 0x80aa, 0x77 }, + { 0x80ab, 0xf0 }, + { 0x80ac, 0x05 }, + { 0x80ad, 0x77 }, + { 0x80ae, 0x41 }, + { 0x80af, 0x66 }, + { 0x821b, 0xcc }, + { 0x821d, 0x80 }, + { 0x80a4, 0xe8 }, + { 0x8231, 0x13 }, +}; Index: src/sys/dev/i2c/au8522mod_qam256.h diff -u /dev/null src/sys/dev/i2c/au8522mod_qam256.h:1.1 --- /dev/null Sat Jul 9 15:00:46 2011 +++ src/sys/dev/i2c/au8522mod_qam256.h Sat Jul 9 15:00:43 2011 @@ -0,0 +1,102 @@ +/* $NetBSD: au8522mod_qam256.h,v 1.1 2011/07/09 15:00:43 jmcneill Exp $ */ + +/*- + * Copyright (c) 2011 Jared D. McNeill <jmcne...@invisible.ca> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +static const struct au8522_modulation_table au8522_modulation_qam256[] = { + { 0x80a3, 0x09 }, + { 0x80a4, 0x00 }, + { 0x8081, 0xc4 }, + { 0x80a5, 0x40 }, + { 0x80aa, 0x77 }, + { 0x80ad, 0x77 }, + { 0x80a6, 0x67 }, + { 0x8262, 0x20 }, + { 0x821c, 0x30 }, + { 0x80b8, 0x3e }, + { 0x80b9, 0xf0 }, + { 0x80ba, 0x01 }, + { 0x80bb, 0x18 }, + { 0x80bc, 0x50 }, + { 0x80bd, 0x00 }, + { 0x80be, 0xea }, + { 0x80bf, 0xef }, + { 0x80c0, 0xfc }, + { 0x80c1, 0xbd }, + { 0x80c2, 0x1f }, + { 0x80c3, 0xfc }, + { 0x80c4, 0xdd }, + { 0x80c5, 0xaf }, + { 0x80c6, 0x00 }, + { 0x80c7, 0x38 }, + { 0x80c8, 0x30 }, + { 0x80c9, 0x05 }, + { 0x80ca, 0x4a }, + { 0x80cb, 0xd0 }, + { 0x80cc, 0x01 }, + { 0x80cd, 0xd9 }, + { 0x80ce, 0x6f }, + { 0x80cf, 0xf9 }, + { 0x80d0, 0x70 }, + { 0x80d1, 0xdf }, + { 0x80d2, 0xf7 }, + { 0x80d3, 0xc2 }, + { 0x80d4, 0xdf }, + { 0x80d5, 0x02 }, + { 0x80d6, 0x9a }, + { 0x80d7, 0xd0 }, + { 0x8250, 0x0d }, + { 0x8251, 0xcd }, + { 0x8252, 0xe0 }, + { 0x8253, 0x05 }, + { 0x8254, 0xa7 }, + { 0x8255, 0xff }, + { 0x8256, 0xed }, + { 0x8257, 0x5b }, + { 0x8258, 0xae }, + { 0x8259, 0xe6 }, + { 0x825a, 0x3d }, + { 0x825b, 0x0f }, + { 0x825c, 0x0d }, + { 0x825d, 0xea }, + { 0x825e, 0xf2 }, + { 0x825f, 0x51 }, + { 0x8260, 0xf5 }, + { 0x8261, 0x06 }, + { 0x821a, 0x00 }, + { 0x8546, 0x40 }, + { 0x8210, 0x26 }, + { 0x8211, 0xf6 }, + { 0x8212, 0x84 }, + { 0x8213, 0x02 }, + { 0x8502, 0x01 }, + { 0x8121, 0x04 }, + { 0x8122, 0x04 }, + { 0x852e, 0x10 }, + { 0x80a4, 0xca }, + { 0x80a7, 0x40 }, + { 0x8526, 0x01 }, +}; Index: src/sys/dev/i2c/au8522mod_qam64.h diff -u /dev/null src/sys/dev/i2c/au8522mod_qam64.h:1.1 --- /dev/null Sat Jul 9 15:00:46 2011 +++ src/sys/dev/i2c/au8522mod_qam64.h Sat Jul 9 15:00:44 2011 @@ -0,0 +1,102 @@ +/* $NetBSD: au8522mod_qam64.h,v 1.1 2011/07/09 15:00:44 jmcneill Exp $ */ + +/*- + * Copyright (c) 2011 Jared D. McNeill <jmcne...@invisible.ca> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +static const struct au8522_modulation_table au8522_modulation_qam64[] = { + { 0x00a3, 0x09 }, + { 0x00a4, 0x00 }, + { 0x0081, 0xc4 }, + { 0x00a5, 0x40 }, + { 0x00aa, 0x77 }, + { 0x00ad, 0x77 }, + { 0x00a6, 0x67 }, + { 0x0262, 0x20 }, + { 0x021c, 0x30 }, + { 0x00b8, 0x3e }, + { 0x00b9, 0xf0 }, + { 0x00ba, 0x01 }, + { 0x00bb, 0x18 }, + { 0x00bc, 0x50 }, + { 0x00bd, 0x00 }, + { 0x00be, 0xea }, + { 0x00bf, 0xef }, + { 0x00c0, 0xfc }, + { 0x00c1, 0xbd }, + { 0x00c2, 0x1f }, + { 0x00c3, 0xfc }, + { 0x00c4, 0xdd }, + { 0x00c5, 0xaf }, + { 0x00c6, 0x00 }, + { 0x00c7, 0x38 }, + { 0x00c8, 0x30 }, + { 0x00c9, 0x05 }, + { 0x00ca, 0x4a }, + { 0x00cb, 0xd0 }, + { 0x00cc, 0x01 }, + { 0x00cd, 0xd9 }, + { 0x00ce, 0x6f }, + { 0x00cf, 0xf9 }, + { 0x00d0, 0x70 }, + { 0x00d1, 0xdf }, + { 0x00d2, 0xf7 }, + { 0x00d3, 0xc2 }, + { 0x00d4, 0xdf }, + { 0x00d5, 0x02 }, + { 0x00d6, 0x9a }, + { 0x00d7, 0xd0 }, + { 0x0250, 0x0d }, + { 0x0251, 0xcd }, + { 0x0252, 0xe0 }, + { 0x0253, 0x05 }, + { 0x0254, 0xa7 }, + { 0x0255, 0xff }, + { 0x0256, 0xed }, + { 0x0257, 0x5b }, + { 0x0258, 0xae }, + { 0x0259, 0xe6 }, + { 0x025a, 0x3d }, + { 0x025b, 0x0f }, + { 0x025c, 0x0d }, + { 0x025d, 0xea }, + { 0x025e, 0xf2 }, + { 0x025f, 0x51 }, + { 0x0260, 0xf5 }, + { 0x0261, 0x06 }, + { 0x021a, 0x00 }, + { 0x0546, 0x40 }, + { 0x0210, 0xc7 }, + { 0x0211, 0xaa }, + { 0x0212, 0xab }, + { 0x0213, 0x02 }, + { 0x0502, 0x00 }, + { 0x0121, 0x04 }, + { 0x0122, 0x04 }, + { 0x052e, 0x10 }, + { 0x00a4, 0xca }, + { 0x00a7, 0x40 }, + { 0x0526, 0x01 }, +}; Index: src/sys/dev/usb/auvitek_dtv.c diff -u /dev/null src/sys/dev/usb/auvitek_dtv.c:1.1 --- /dev/null Sat Jul 9 15:00:46 2011 +++ src/sys/dev/usb/auvitek_dtv.c Sat Jul 9 15:00:44 2011 @@ -0,0 +1,345 @@ +/* $NetBSD: auvitek_dtv.c,v 1.1 2011/07/09 15:00:44 jmcneill Exp $ */ + +/*- + * Copyright (c) 2011 Jared D. McNeill <jmcne...@invisible.ca> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Auvitek AU0828 USB controller (Digital TV function) + */ + +#include <sys/cdefs.h> +__KERNEL_RCSID(0, "$NetBSD: auvitek_dtv.c,v 1.1 2011/07/09 15:00:44 jmcneill Exp $"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/conf.h> +#include <sys/kmem.h> +#include <sys/bus.h> + +#include <dev/usb/usb.h> +#include <dev/usb/usbdi.h> +#include <dev/usb/usbdivar.h> +#include <dev/usb/usbdi_util.h> +#include <dev/usb/usbdevs.h> + +#include <dev/dtv/dtvif.h> + +#include <dev/usb/auvitekreg.h> +#include <dev/usb/auvitekvar.h> + +static void auvitek_dtv_get_devinfo(void *, + struct dvb_frontend_info *); +static int auvitek_dtv_open(void *, int); +static void auvitek_dtv_close(void *); +static int auvitek_dtv_set_tuner(void *, + const struct dvb_frontend_parameters *); +static fe_status_t auvitek_dtv_get_status(void *); +static uint16_t auvitek_dtv_get_signal_strength(void *); +static uint16_t auvitek_dtv_get_snr(void *); +static int auvitek_dtv_start_transfer(void *); +static int auvitek_dtv_stop_transfer(void *); + +static int auvitek_dtv_init_pipes(struct auvitek_softc *); +static int auvitek_dtv_close_pipes(struct auvitek_softc *); + +static int auvitek_dtv_bulk_start(struct auvitek_softc *); +static int auvitek_dtv_bulk_start1(struct auvitek_bulk_xfer *); +static void auvitek_dtv_bulk_cb(usbd_xfer_handle, + usbd_private_handle, + usbd_status); + +static const struct dtv_hw_if auvitek_dtv_if = { + .get_devinfo = auvitek_dtv_get_devinfo, + .open = auvitek_dtv_open, + .close = auvitek_dtv_close, + .set_tuner = auvitek_dtv_set_tuner, + .get_status = auvitek_dtv_get_status, + .get_signal_strength = auvitek_dtv_get_signal_strength, + .get_snr = auvitek_dtv_get_snr, + .start_transfer = auvitek_dtv_start_transfer, + .stop_transfer = auvitek_dtv_stop_transfer, +}; + +int +auvitek_dtv_attach(struct auvitek_softc *sc) +{ + struct dtv_attach_args daa; + + daa.hw = &auvitek_dtv_if; + daa.priv = sc; + sc->sc_dtvdev = config_found_ia(sc->sc_dev, "dtvbus", &daa, dtv_print); + + return (sc->sc_dtvdev != NULL); +} + +int +auvitek_dtv_detach(struct auvitek_softc *sc, int flags) +{ + if (sc->sc_dtvdev != NULL) { + config_detach(sc->sc_dtvdev, flags); + sc->sc_dtvdev = NULL; + } + + return 0; +} + +void +auvitek_dtv_childdet(struct auvitek_softc *sc, device_t child) +{ + if (sc->sc_dtvdev == child) + sc->sc_dtvdev = NULL; +} + +static void +auvitek_dtv_get_devinfo(void *priv, struct dvb_frontend_info *info) +{ + struct auvitek_softc *sc = priv; + + memset(info, 0, sizeof(*info)); + strlcpy(info->name, sc->sc_descr, sizeof(info->name)); + info->type = FE_ATSC; + info->frequency_min = 54000000; + info->frequency_max = 858000000; + info->frequency_stepsize = 62500; + info->caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB; +} + +static int +auvitek_dtv_open(void *priv, int flags) +{ + struct auvitek_softc *sc = priv; + + if (sc->sc_dying) + return EIO; + + mutex_enter(&sc->sc_subdev_lock); + if (sc->sc_xc5k == NULL) { + sc->sc_xc5k = xc5k_open(sc->sc_dev, &sc->sc_i2c, 0xc2 >> 1, + auvitek_board_tuner_reset, sc, + auvitek_board_get_if_frequency(sc), + FE_ATSC); + } + mutex_exit(&sc->sc_subdev_lock); + + if (sc->sc_xc5k == NULL) + return ENXIO; + + return auvitek_dtv_init_pipes(sc); +} + +static void +auvitek_dtv_close(void *priv) +{ + struct auvitek_softc *sc = priv; + + auvitek_dtv_stop_transfer(sc); + auvitek_dtv_close_pipes(sc); +} + +static int +auvitek_dtv_set_tuner(void *priv, const struct dvb_frontend_parameters *params) +{ + struct auvitek_softc *sc = priv; + int error; + + error = au8522_set_modulation(sc->sc_au8522, params->u.vsb.modulation); + if (error) + return error; + + delay(100000); + + au8522_set_gate(sc->sc_au8522, true); + error = xc5k_tune_dtv(sc->sc_xc5k, params); + au8522_set_gate(sc->sc_au8522, false); + + return error; +} + +fe_status_t +auvitek_dtv_get_status(void *priv) +{ + struct auvitek_softc *sc = priv; + + return au8522_get_dtv_status(sc->sc_au8522); +} + +uint16_t +auvitek_dtv_get_signal_strength(void *priv) +{ + return 0; /* TODO */ +} + +uint16_t +auvitek_dtv_get_snr(void *priv) +{ + return 0; /* TODO */ +} + +static int +auvitek_dtv_start_transfer(void *priv) +{ + struct auvitek_softc *sc = priv; + int s; + + if (sc->sc_ab.ab_running) { + return 0; + } + + auvitek_write_1(sc, 0x608, 0x90); + auvitek_write_1(sc, 0x609, 0x72); + auvitek_write_1(sc, 0x60a, 0x71); + auvitek_write_1(sc, 0x60b, 0x01); + + sc->sc_ab.ab_running = true; + + s = splusb(); + auvitek_dtv_bulk_start(sc); + splx(s); + + return 0; +} + +static int +auvitek_dtv_stop_transfer(void *priv) +{ + struct auvitek_softc *sc = priv; + + sc->sc_ab.ab_running = false; + + auvitek_write_1(sc, 0x608, 0x00); + auvitek_write_1(sc, 0x609, 0x00); + auvitek_write_1(sc, 0x60a, 0x00); + auvitek_write_1(sc, 0x60b, 0x00); + + return 0; +} + +static int +auvitek_dtv_init_pipes(struct auvitek_softc *sc) +{ + usbd_status err; + + err = usbd_open_pipe(sc->sc_bulk_iface, sc->sc_ab.ab_endpt, + USBD_EXCLUSIVE_USE, &sc->sc_ab.ab_pipe); + if (err) { + aprint_error_dev(sc->sc_dev, "couldn't open bulk-in pipe: %s\n", + usbd_errstr(err)); + return ENOMEM; + } + + return 0; +} + +static int +auvitek_dtv_close_pipes(struct auvitek_softc *sc) +{ + if (sc->sc_ab.ab_pipe != NULL) { + usbd_abort_pipe(sc->sc_ab.ab_pipe); + usbd_close_pipe(sc->sc_ab.ab_pipe); + sc->sc_ab.ab_pipe = NULL; + } + + return 0; +} + +static void +auvitek_dtv_bulk_cb(usbd_xfer_handle xfer, usbd_private_handle priv, + usbd_status status) +{ + struct auvitek_bulk_xfer *bx = priv; + struct auvitek_softc *sc = bx->bx_sc; + struct auvitek_bulk *ab = &sc->sc_ab; + struct dtv_payload payload; + uint32_t xferlen; + + if (ab->ab_running == false) + return; + + usbd_get_xfer_status(xfer, NULL, NULL, &xferlen, NULL); + + //printf("%s: status=%d xferlen=%u\n", __func__, status, xferlen); + + if (status != USBD_NORMAL_COMPLETION) { + printf("%s: USB error (%s)\n", __func__, usbd_errstr(status)); + if (status == USBD_STALLED) { + usbd_clear_endpoint_stall_async(ab->ab_pipe); + goto next; + } + if (status == USBD_SHORT_XFER) { + goto next; + } + return; + } + + if (xferlen == 0) { + printf("%s: 0-length xfer\n", __func__); + goto next; + } + + payload.data = bx->bx_buffer; + payload.size = xferlen; + dtv_submit_payload(sc->sc_dtvdev, &payload); + +next: + auvitek_dtv_bulk_start1(bx); +} + +static int +auvitek_dtv_bulk_start(struct auvitek_softc *sc) +{ + int i, error; + + for (i = 0; i < AUVITEK_NBULK_XFERS; i++) { + error = auvitek_dtv_bulk_start1(&sc->sc_ab.ab_bx[i]); + if (error) + return error; + } + + return 0; +} + +static int +auvitek_dtv_bulk_start1(struct auvitek_bulk_xfer *bx) +{ + struct auvitek_softc *sc = bx->bx_sc; + struct auvitek_bulk *ab = &sc->sc_ab; + int err; + + usbd_setup_xfer(bx->bx_xfer, ab->ab_pipe, bx, + bx->bx_buffer, AUVITEK_BULK_BUFLEN, + //USBD_SHORT_XFER_OK|USBD_NO_COPY, USBD_NO_TIMEOUT, + USBD_NO_COPY, 100, + auvitek_dtv_bulk_cb); + err = usbd_transfer(bx->bx_xfer); + if (err != USBD_IN_PROGRESS) { + aprint_error_dev(sc->sc_dev, "USB error: %s\n", + usbd_errstr(err)); + return ENODEV; + } + + return 0; +}