V4L/DVB (11207): pvrusb2: Add composite and s-video input support for OnAir devices
[safe/jmp/linux-2.6] / drivers / media / video / pvrusb2 / pvrusb2-hdw.c
index 2404053..e357721 100644 (file)
@@ -1,6 +1,5 @@
 /*
  *
- *  $Id$
  *
  *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
  *
 #include <linux/firmware.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-common.h>
+#include <media/tuner.h>
 #include "pvrusb2.h"
 #include "pvrusb2-std.h"
 #include "pvrusb2-util.h"
 #include "pvrusb2-hdw.h"
 #include "pvrusb2-i2c-core.h"
-#include "pvrusb2-tuner.h"
 #include "pvrusb2-eeprom.h"
 #include "pvrusb2-hdw-internal.h"
 #include "pvrusb2-encoder.h"
 #include "pvrusb2-debug.h"
 #include "pvrusb2-fx2-cmd.h"
+#include "pvrusb2-wm8775.h"
+#include "pvrusb2-video-v4l.h"
+#include "pvrusb2-cx2584x-v4l.h"
+#include "pvrusb2-cs53l32a.h"
+#include "pvrusb2-audio.h"
 
 #define TV_MIN_FREQ     55250000L
 #define TV_MAX_FREQ    850000000L
 
+/* This defines a minimum interval that the decoder must remain quiet
+   before we are allowed to start it running. */
+#define TIME_MSEC_DECODER_WAIT 50
+
+/* This defines a minimum interval that the encoder must remain quiet
+   before we are allowed to configure it.  I had this originally set to
+   50msec, but Martin Dauskardt <martin.dauskardt@gmx.de> reports that
+   things work better when it's set to 100msec. */
+#define TIME_MSEC_ENCODER_WAIT 100
+
+/* This defines the minimum interval that the encoder must successfully run
+   before we consider that the encoder has run at least once since its
+   firmware has been loaded.  This measurement is in important for cases
+   where we can't do something until we know that the encoder has been run
+   at least once. */
+#define TIME_MSEC_ENCODER_OK 250
+
 static struct pvr2_hdw *unit_pointers[PVR_NUM] = {[ 0 ... PVR_NUM-1 ] = NULL};
 static DEFINE_MUTEX(pvr2_unit_mtx);
 
-static int ctlchg = 0;
-static int initusbreset = 1;
-static int procreload = 0;
+static int ctlchg;
+static int procreload;
 static int tuner[PVR_NUM] = { [0 ... PVR_NUM-1] = -1 };
 static int tolerance[PVR_NUM] = { [0 ... PVR_NUM-1] = 0 };
 static int video_std[PVR_NUM] = { [0 ... PVR_NUM-1] = 0 };
-static int init_pause_msec = 0;
+static int init_pause_msec;
 
 module_param(ctlchg, int, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(ctlchg, "0=optimize ctl change 1=always accept new ctl value");
 module_param(init_pause_msec, int, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(init_pause_msec, "hardware initialization settling delay");
-module_param(initusbreset, int, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(initusbreset, "Do USB reset device on probe");
 module_param(procreload, int, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(procreload,
                 "Attempt init failure recovery with firmware reload");
@@ -67,6 +85,16 @@ MODULE_PARM_DESC(video_std,"specify initial video standard");
 module_param_array(tolerance,    int, NULL, 0444);
 MODULE_PARM_DESC(tolerance,"specify stream error tolerance");
 
+/* US Broadcast channel 7 (175.25 MHz) */
+static int default_tv_freq    = 175250000L;
+/* 104.3 MHz, a usable FM station for my area */
+static int default_radio_freq = 104300000L;
+
+module_param_named(tv_freq, default_tv_freq, int, 0444);
+MODULE_PARM_DESC(tv_freq, "specify initial television frequency");
+module_param_named(radio_freq, default_radio_freq, int, 0444);
+MODULE_PARM_DESC(radio_freq, "specify initial radio frequency");
+
 #define PVR2_CTL_WRITE_ENDPOINT  0x01
 #define PVR2_CTL_READ_ENDPOINT   0x81
 
@@ -81,6 +109,39 @@ MODULE_PARM_DESC(tolerance,"specify stream error tolerance");
 /* size of a firmware chunk */
 #define FIRMWARE_CHUNK_SIZE 0x2000
 
+typedef void (*pvr2_subdev_update_func)(struct pvr2_hdw *,
+                                       struct v4l2_subdev *);
+
+static const pvr2_subdev_update_func pvr2_module_update_functions[] = {
+       [PVR2_CLIENT_ID_WM8775] = pvr2_wm8775_subdev_update,
+       [PVR2_CLIENT_ID_SAA7115] = pvr2_saa7115_subdev_update,
+       [PVR2_CLIENT_ID_MSP3400] = pvr2_msp3400_subdev_update,
+       [PVR2_CLIENT_ID_CX25840] = pvr2_cx25840_subdev_update,
+       [PVR2_CLIENT_ID_CS53L32A] = pvr2_cs53l32a_subdev_update,
+};
+
+static const char *module_names[] = {
+       [PVR2_CLIENT_ID_MSP3400] = "msp3400",
+       [PVR2_CLIENT_ID_CX25840] = "cx25840",
+       [PVR2_CLIENT_ID_SAA7115] = "saa7115",
+       [PVR2_CLIENT_ID_TUNER] = "tuner",
+       [PVR2_CLIENT_ID_DEMOD] = "tuner",
+       [PVR2_CLIENT_ID_CS53L32A] = "cs53l32a",
+       [PVR2_CLIENT_ID_WM8775] = "wm8775",
+};
+
+
+static const unsigned char *module_i2c_addresses[] = {
+       [PVR2_CLIENT_ID_TUNER] = "\x60\x61\x62\x63",
+       [PVR2_CLIENT_ID_DEMOD] = "\x43",
+       [PVR2_CLIENT_ID_MSP3400] = "\x40",
+       [PVR2_CLIENT_ID_SAA7115] = "\x21",
+       [PVR2_CLIENT_ID_WM8775] = "\x1b",
+       [PVR2_CLIENT_ID_CX25840] = "\x44",
+       [PVR2_CLIENT_ID_CS53L32A] = "\x11",
+};
+
+
 /* Define the list of additional controls we'll dynamically construct based
    on query of the cx2341x module. */
 struct pvr2_mpeg_ids {
@@ -182,6 +243,7 @@ static const char *control_values_srate[] = {
 
 static const char *control_values_input[] = {
        [PVR2_CVAL_INPUT_TV]        = "television",  /*xawtv needs this name*/
+       [PVR2_CVAL_INPUT_DTV]       = "dtv",
        [PVR2_CVAL_INPUT_RADIO]     = "radio",
        [PVR2_CVAL_INPUT_SVIDEO]    = "s-video",
        [PVR2_CVAL_INPUT_COMPOSITE] = "composite",
@@ -215,12 +277,45 @@ static const char *pvr2_state_names[] = {
 };
 
 
+struct pvr2_fx2cmd_descdef {
+       unsigned char id;
+       unsigned char *desc;
+};
+
+static const struct pvr2_fx2cmd_descdef pvr2_fx2cmd_desc[] = {
+       {FX2CMD_MEM_WRITE_DWORD, "write encoder dword"},
+       {FX2CMD_MEM_READ_DWORD, "read encoder dword"},
+       {FX2CMD_HCW_ZILOG_RESET, "zilog IR reset control"},
+       {FX2CMD_MEM_READ_64BYTES, "read encoder 64bytes"},
+       {FX2CMD_REG_WRITE, "write encoder register"},
+       {FX2CMD_REG_READ, "read encoder register"},
+       {FX2CMD_MEMSEL, "encoder memsel"},
+       {FX2CMD_I2C_WRITE, "i2c write"},
+       {FX2CMD_I2C_READ, "i2c read"},
+       {FX2CMD_GET_USB_SPEED, "get USB speed"},
+       {FX2CMD_STREAMING_ON, "stream on"},
+       {FX2CMD_STREAMING_OFF, "stream off"},
+       {FX2CMD_FWPOST1, "fwpost1"},
+       {FX2CMD_POWER_OFF, "power off"},
+       {FX2CMD_POWER_ON, "power on"},
+       {FX2CMD_DEEP_RESET, "deep reset"},
+       {FX2CMD_GET_EEPROM_ADDR, "get rom addr"},
+       {FX2CMD_GET_IR_CODE, "get IR code"},
+       {FX2CMD_HCW_DEMOD_RESETIN, "hcw demod resetin"},
+       {FX2CMD_HCW_DTV_STREAMING_ON, "hcw dtv stream on"},
+       {FX2CMD_HCW_DTV_STREAMING_OFF, "hcw dtv stream off"},
+       {FX2CMD_ONAIR_DTV_STREAMING_ON, "onair dtv stream on"},
+       {FX2CMD_ONAIR_DTV_STREAMING_OFF, "onair dtv stream off"},
+       {FX2CMD_ONAIR_DTV_POWER_ON, "onair dtv power on"},
+       {FX2CMD_ONAIR_DTV_POWER_OFF, "onair dtv power off"},
+};
+
+
+static int pvr2_hdw_set_input(struct pvr2_hdw *hdw,int v);
 static void pvr2_hdw_state_sched(struct pvr2_hdw *);
 static int pvr2_hdw_state_eval(struct pvr2_hdw *);
 static void pvr2_hdw_set_cur_freq(struct pvr2_hdw *,unsigned long);
-static void pvr2_hdw_worker_i2c(struct work_struct *work);
 static void pvr2_hdw_worker_poll(struct work_struct *work);
-static void pvr2_hdw_worker_init(struct work_struct *work);
 static int pvr2_hdw_wait(struct pvr2_hdw *,int state);
 static int pvr2_hdw_untrip_unlocked(struct pvr2_hdw *);
 static void pvr2_hdw_state_log_state(struct pvr2_hdw *);
@@ -231,10 +326,13 @@ static void pvr2_hdw_internal_find_stdenum(struct pvr2_hdw *hdw);
 static void pvr2_hdw_internal_set_std_avail(struct pvr2_hdw *hdw);
 static void pvr2_hdw_quiescent_timeout(unsigned long);
 static void pvr2_hdw_encoder_wait_timeout(unsigned long);
+static void pvr2_hdw_encoder_run_timeout(unsigned long);
+static int pvr2_issue_simple_cmd(struct pvr2_hdw *,u32);
 static int pvr2_send_request_ex(struct pvr2_hdw *hdw,
                                unsigned int timeout,int probe_fl,
                                void *write_data,unsigned int write_len,
                                void *read_data,unsigned int read_len);
+static int pvr2_hdw_check_cropcap(struct pvr2_hdw *hdw);
 
 
 static void trace_stbit(const char *name,int val)
@@ -339,6 +437,194 @@ static int ctrl_freq_set(struct pvr2_ctrl *cptr,int m,int v)
        return 0;
 }
 
+static int ctrl_cropl_min_get(struct pvr2_ctrl *cptr, int *left)
+{
+       struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+       int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+       if (stat != 0) {
+               return stat;
+       }
+       *left = cap->bounds.left;
+       return 0;
+}
+
+static int ctrl_cropl_max_get(struct pvr2_ctrl *cptr, int *left)
+{
+       struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+       int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+       if (stat != 0) {
+               return stat;
+       }
+       *left = cap->bounds.left;
+       if (cap->bounds.width > cptr->hdw->cropw_val) {
+               *left += cap->bounds.width - cptr->hdw->cropw_val;
+       }
+       return 0;
+}
+
+static int ctrl_cropt_min_get(struct pvr2_ctrl *cptr, int *top)
+{
+       struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+       int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+       if (stat != 0) {
+               return stat;
+       }
+       *top = cap->bounds.top;
+       return 0;
+}
+
+static int ctrl_cropt_max_get(struct pvr2_ctrl *cptr, int *top)
+{
+       struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+       int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+       if (stat != 0) {
+               return stat;
+       }
+       *top = cap->bounds.top;
+       if (cap->bounds.height > cptr->hdw->croph_val) {
+               *top += cap->bounds.height - cptr->hdw->croph_val;
+       }
+       return 0;
+}
+
+static int ctrl_cropw_max_get(struct pvr2_ctrl *cptr, int *val)
+{
+       struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+       int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+       if (stat != 0) {
+               return stat;
+       }
+       *val = 0;
+       if (cap->bounds.width > cptr->hdw->cropl_val) {
+               *val = cap->bounds.width - cptr->hdw->cropl_val;
+       }
+       return 0;
+}
+
+static int ctrl_croph_max_get(struct pvr2_ctrl *cptr, int *val)
+{
+       struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+       int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+       if (stat != 0) {
+               return stat;
+       }
+       *val = 0;
+       if (cap->bounds.height > cptr->hdw->cropt_val) {
+               *val = cap->bounds.height - cptr->hdw->cropt_val;
+       }
+       return 0;
+}
+
+static int ctrl_get_cropcapbl(struct pvr2_ctrl *cptr, int *val)
+{
+       struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+       int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+       if (stat != 0) {
+               return stat;
+       }
+       *val = cap->bounds.left;
+       return 0;
+}
+
+static int ctrl_get_cropcapbt(struct pvr2_ctrl *cptr, int *val)
+{
+       struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+       int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+       if (stat != 0) {
+               return stat;
+       }
+       *val = cap->bounds.top;
+       return 0;
+}
+
+static int ctrl_get_cropcapbw(struct pvr2_ctrl *cptr, int *val)
+{
+       struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+       int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+       if (stat != 0) {
+               return stat;
+       }
+       *val = cap->bounds.width;
+       return 0;
+}
+
+static int ctrl_get_cropcapbh(struct pvr2_ctrl *cptr, int *val)
+{
+       struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+       int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+       if (stat != 0) {
+               return stat;
+       }
+       *val = cap->bounds.height;
+       return 0;
+}
+
+static int ctrl_get_cropcapdl(struct pvr2_ctrl *cptr, int *val)
+{
+       struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+       int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+       if (stat != 0) {
+               return stat;
+       }
+       *val = cap->defrect.left;
+       return 0;
+}
+
+static int ctrl_get_cropcapdt(struct pvr2_ctrl *cptr, int *val)
+{
+       struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+       int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+       if (stat != 0) {
+               return stat;
+       }
+       *val = cap->defrect.top;
+       return 0;
+}
+
+static int ctrl_get_cropcapdw(struct pvr2_ctrl *cptr, int *val)
+{
+       struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+       int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+       if (stat != 0) {
+               return stat;
+       }
+       *val = cap->defrect.width;
+       return 0;
+}
+
+static int ctrl_get_cropcapdh(struct pvr2_ctrl *cptr, int *val)
+{
+       struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+       int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+       if (stat != 0) {
+               return stat;
+       }
+       *val = cap->defrect.height;
+       return 0;
+}
+
+static int ctrl_get_cropcappan(struct pvr2_ctrl *cptr, int *val)
+{
+       struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+       int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+       if (stat != 0) {
+               return stat;
+       }
+       *val = cap->pixelaspect.numerator;
+       return 0;
+}
+
+static int ctrl_get_cropcappad(struct pvr2_ctrl *cptr, int *val)
+{
+       struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info;
+       int stat = pvr2_hdw_check_cropcap(cptr->hdw);
+       if (stat != 0) {
+               return stat;
+       }
+       *val = cap->pixelaspect.denominator;
+       return 0;
+}
+
 static int ctrl_vres_max_get(struct pvr2_ctrl *cptr,int *vp)
 {
        /* Actual maximum depends on the video standard in effect. */
@@ -367,26 +653,14 @@ static int ctrl_get_input(struct pvr2_ctrl *cptr,int *vp)
        return 0;
 }
 
-static int ctrl_set_input(struct pvr2_ctrl *cptr,int m,int v)
+static int ctrl_check_input(struct pvr2_ctrl *cptr,int v)
 {
-       struct pvr2_hdw *hdw = cptr->hdw;
-
-       if (hdw->input_val != v) {
-               hdw->input_val = v;
-               hdw->input_dirty = !0;
-       }
+       return ((1 << v) & cptr->hdw->input_allowed_mask) != 0;
+}
 
-       /* Handle side effects - if we switch to a mode that needs the RF
-          tuner, then select the right frequency choice as well and mark
-          it dirty. */
-       if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
-               hdw->freqSelector = 0;
-               hdw->freqDirty = !0;
-       } else if (hdw->input_val == PVR2_CVAL_INPUT_TV) {
-               hdw->freqSelector = 1;
-               hdw->freqDirty = !0;
-       }
-       return 0;
+static int ctrl_set_input(struct pvr2_ctrl *cptr,int m,int v)
+{
+       return pvr2_hdw_set_input(cptr->hdw,v);
 }
 
 static int ctrl_isdirty_input(struct pvr2_ctrl *cptr)
@@ -405,7 +679,7 @@ static int ctrl_freq_max_get(struct pvr2_ctrl *cptr, int *vp)
        unsigned long fv;
        struct pvr2_hdw *hdw = cptr->hdw;
        if (hdw->tuner_signal_stale) {
-               pvr2_i2c_core_status_poll(hdw);
+               pvr2_hdw_status_poll(hdw);
        }
        fv = hdw->tuner_signal_info.rangehigh;
        if (!fv) {
@@ -427,7 +701,7 @@ static int ctrl_freq_min_get(struct pvr2_ctrl *cptr, int *vp)
        unsigned long fv;
        struct pvr2_hdw *hdw = cptr->hdw;
        if (hdw->tuner_signal_stale) {
-               pvr2_i2c_core_status_poll(hdw);
+               pvr2_hdw_status_poll(hdw);
        }
        fv = hdw->tuner_signal_info.rangelow;
        if (!fv) {
@@ -621,7 +895,7 @@ static void ctrl_stdcur_clear_dirty(struct pvr2_ctrl *cptr)
 static int ctrl_signal_get(struct pvr2_ctrl *cptr,int *vp)
 {
        struct pvr2_hdw *hdw = cptr->hdw;
-       pvr2_i2c_core_status_poll(hdw);
+       pvr2_hdw_status_poll(hdw);
        *vp = hdw->tuner_signal_info.signal;
        return 0;
 }
@@ -631,7 +905,7 @@ static int ctrl_audio_modes_present_get(struct pvr2_ctrl *cptr,int *vp)
        int val = 0;
        unsigned int subchan;
        struct pvr2_hdw *hdw = cptr->hdw;
-       pvr2_i2c_core_status_poll(hdw);
+       pvr2_hdw_status_poll(hdw);
        subchan = hdw->tuner_signal_info.rxsubchans;
        if (subchan & V4L2_TUNER_SUB_MONO) {
                val |= (1 << V4L2_TUNER_MODE_MONO);
@@ -728,6 +1002,10 @@ VCREATE_FUNCS(balance)
 VCREATE_FUNCS(bass)
 VCREATE_FUNCS(treble)
 VCREATE_FUNCS(mute)
+VCREATE_FUNCS(cropl)
+VCREATE_FUNCS(cropt)
+VCREATE_FUNCS(cropw)
+VCREATE_FUNCS(croph)
 VCREATE_FUNCS(audiomode)
 VCREATE_FUNCS(res_hor)
 VCREATE_FUNCS(res_ver)
@@ -798,11 +1076,78 @@ static const struct pvr2_ctl_info control_defs[] = {
                .default_value = 0,
                DEFREF(mute),
                DEFBOOL,
+       }, {
+               .desc = "Capture crop left margin",
+               .name = "crop_left",
+               .internal_id = PVR2_CID_CROPL,
+               .default_value = 0,
+               DEFREF(cropl),
+               DEFINT(-129, 340),
+               .get_min_value = ctrl_cropl_min_get,
+               .get_max_value = ctrl_cropl_max_get,
+               .get_def_value = ctrl_get_cropcapdl,
+       }, {
+               .desc = "Capture crop top margin",
+               .name = "crop_top",
+               .internal_id = PVR2_CID_CROPT,
+               .default_value = 0,
+               DEFREF(cropt),
+               DEFINT(-35, 544),
+               .get_min_value = ctrl_cropt_min_get,
+               .get_max_value = ctrl_cropt_max_get,
+               .get_def_value = ctrl_get_cropcapdt,
+       }, {
+               .desc = "Capture crop width",
+               .name = "crop_width",
+               .internal_id = PVR2_CID_CROPW,
+               .default_value = 720,
+               DEFREF(cropw),
+               .get_max_value = ctrl_cropw_max_get,
+               .get_def_value = ctrl_get_cropcapdw,
+       }, {
+               .desc = "Capture crop height",
+               .name = "crop_height",
+               .internal_id = PVR2_CID_CROPH,
+               .default_value = 480,
+               DEFREF(croph),
+               .get_max_value = ctrl_croph_max_get,
+               .get_def_value = ctrl_get_cropcapdh,
+       }, {
+               .desc = "Capture capability pixel aspect numerator",
+               .name = "cropcap_pixel_numerator",
+               .internal_id = PVR2_CID_CROPCAPPAN,
+               .get_value = ctrl_get_cropcappan,
+       }, {
+               .desc = "Capture capability pixel aspect denominator",
+               .name = "cropcap_pixel_denominator",
+               .internal_id = PVR2_CID_CROPCAPPAD,
+               .get_value = ctrl_get_cropcappad,
+       }, {
+               .desc = "Capture capability bounds top",
+               .name = "cropcap_bounds_top",
+               .internal_id = PVR2_CID_CROPCAPBT,
+               .get_value = ctrl_get_cropcapbt,
+       }, {
+               .desc = "Capture capability bounds left",
+               .name = "cropcap_bounds_left",
+               .internal_id = PVR2_CID_CROPCAPBL,
+               .get_value = ctrl_get_cropcapbl,
+       }, {
+               .desc = "Capture capability bounds width",
+               .name = "cropcap_bounds_width",
+               .internal_id = PVR2_CID_CROPCAPBW,
+               .get_value = ctrl_get_cropcapbw,
+       }, {
+               .desc = "Capture capability bounds height",
+               .name = "cropcap_bounds_height",
+               .internal_id = PVR2_CID_CROPCAPBH,
+               .get_value = ctrl_get_cropcapbh,
        },{
                .desc = "Video Source",
                .name = "input",
                .internal_id = PVR2_CID_INPUT,
                .default_value = PVR2_CVAL_INPUT_TV,
+               .check_value = ctrl_check_input,
                DEFREF(input),
                DEFENUM(control_values_input),
        },{
@@ -975,6 +1320,12 @@ const char *pvr2_hdw_get_bus_info(struct pvr2_hdw *hdw)
 }
 
 
+const char *pvr2_hdw_get_device_identifier(struct pvr2_hdw *hdw)
+{
+       return hdw->identifier;
+}
+
+
 unsigned long pvr2_hdw_get_cur_freq(struct pvr2_hdw *hdw)
 {
        return hdw->freqSelector ? hdw->freqValTelevision : hdw->freqValRadio;
@@ -982,7 +1333,7 @@ unsigned long pvr2_hdw_get_cur_freq(struct pvr2_hdw *hdw)
 
 /* Set the currently tuned frequency and account for all possible
    driver-core side effects of this action. */
-void pvr2_hdw_set_cur_freq(struct pvr2_hdw *hdw,unsigned long val)
+static void pvr2_hdw_set_cur_freq(struct pvr2_hdw *hdw,unsigned long val)
 {
        if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
                if (hdw->freqSelector) {
@@ -1195,6 +1546,14 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
           time we configure the encoder, then we'll fully configure it. */
        hdw->enc_cur_valid = 0;
 
+       /* Encoder is about to be reset so note that as far as we're
+          concerned now, the encoder has never been run. */
+       del_timer_sync(&hdw->encoder_run_timer);
+       if (hdw->state_encoder_runok) {
+               hdw->state_encoder_runok = 0;
+               trace_stbit("state_encoder_runok",hdw->state_encoder_runok);
+       }
+
        /* First prepare firmware loading */
        ret |= pvr2_write_register(hdw, 0x0048, 0xffffffff); /*interrupt mask*/
        ret |= pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000088); /*gpio dir*/
@@ -1212,19 +1571,14 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
        ret |= pvr2_write_register(hdw, 0xaa04, 0x00057810); /*unknown*/
        ret |= pvr2_write_register(hdw, 0xaa10, 0x00148500); /*unknown*/
        ret |= pvr2_write_register(hdw, 0xaa18, 0x00840000); /*unknown*/
-       LOCK_TAKE(hdw->ctl_lock); do {
-               hdw->cmd_buffer[0] = FX2CMD_FWPOST1;
-               ret |= pvr2_send_request(hdw,hdw->cmd_buffer,1,NULL,0);
-               hdw->cmd_buffer[0] = FX2CMD_MEMSEL;
-               hdw->cmd_buffer[1] = 0;
-               ret |= pvr2_send_request(hdw,hdw->cmd_buffer,2,NULL,0);
-       } while (0); LOCK_GIVE(hdw->ctl_lock);
+       ret |= pvr2_issue_simple_cmd(hdw,FX2CMD_FWPOST1);
+       ret |= pvr2_issue_simple_cmd(hdw,FX2CMD_MEMSEL | (1 << 8) | (0 << 16));
 
        if (ret) {
                pvr2_trace(PVR2_TRACE_ERROR_LEGS,
                           "firmware2 upload prep failed, ret=%d",ret);
                release_firmware(fw_entry);
-               return ret;
+               goto done;
        }
 
        /* Now send firmware */
@@ -1237,7 +1591,8 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
                           " must be a multiple of %zu bytes",
                           fw_files[fwidx],sizeof(u32));
                release_firmware(fw_entry);
-               return -1;
+               ret = -EINVAL;
+               goto done;
        }
 
        fw_ptr = kmalloc(FIRMWARE_CHUNK_SIZE, GFP_KERNEL);
@@ -1245,7 +1600,8 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
                release_firmware(fw_entry);
                pvr2_trace(PVR2_TRACE_ERROR_LEGS,
                           "failed to allocate memory for firmware2 upload");
-               return -ENOMEM;
+               ret = -ENOMEM;
+               goto done;
        }
 
        pipe = usb_sndbulkpipe(hdw->usb_dev, PVR2_FIRMWARE_ENDPOINT);
@@ -1256,9 +1612,19 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
                if (bcnt > FIRMWARE_CHUNK_SIZE) bcnt = FIRMWARE_CHUNK_SIZE;
                memcpy(fw_ptr, fw_entry->data + fw_done, bcnt);
                /* Usbsnoop log shows that we must swap bytes... */
+               /* Some background info: The data being swapped here is a
+                  firmware image destined for the mpeg encoder chip that
+                  lives at the other end of a USB endpoint.  The encoder
+                  chip always talks in 32 bit chunks and its storage is
+                  organized into 32 bit words.  However from the file
+                  system to the encoder chip everything is purely a byte
+                  stream.  The firmware file's contents are always 32 bit
+                  swapped from what the encoder expects.  Thus the need
+                  always exists to swap the bytes regardless of the endian
+                  type of the host processor and therefore swab32() makes
+                  the most sense. */
                for (icnt = 0; icnt < bcnt/4 ; icnt++)
-                       ((u32 *)fw_ptr)[icnt] =
-                               ___swab32(((u32 *)fw_ptr)[icnt]);
+                       ((u32 *)fw_ptr)[icnt] = swab32(((u32 *)fw_ptr)[icnt]);
 
                ret |= usb_bulk_msg(hdw->usb_dev, pipe, fw_ptr,bcnt,
                                    &actual_length, HZ);
@@ -1276,23 +1642,27 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
        if (ret) {
                pvr2_trace(PVR2_TRACE_ERROR_LEGS,
                           "firmware2 upload transfer failure");
-               return ret;
+               goto done;
        }
 
        /* Finish upload */
 
        ret |= pvr2_write_register(hdw, 0x9054, 0xffffffff); /*reset hw blocks*/
        ret |= pvr2_write_register(hdw, 0x9058, 0xffffffe8); /*VPU ctrl*/
-       LOCK_TAKE(hdw->ctl_lock); do {
-               hdw->cmd_buffer[0] = FX2CMD_MEMSEL;
-               hdw->cmd_buffer[1] = 0;
-               ret |= pvr2_send_request(hdw,hdw->cmd_buffer,2,NULL,0);
-       } while (0); LOCK_GIVE(hdw->ctl_lock);
+       ret |= pvr2_issue_simple_cmd(hdw,FX2CMD_MEMSEL | (1 << 8) | (0 << 16));
 
        if (ret) {
                pvr2_trace(PVR2_TRACE_ERROR_LEGS,
                           "firmware2 upload post-proc failure");
        }
+
+ done:
+       if (hdw->hdw_desc->signal_routing_scheme ==
+           PVR2_ROUTING_SCHEME_GOTVIEW) {
+               /* Ensure that GPIO 11 is set to output for GOTVIEW
+                  hardware. */
+               pvr2_hdw_gpio_chg_dir(hdw,(1 << 11),~0);
+       }
        return ret;
 }
 
@@ -1307,33 +1677,27 @@ static const char *pvr2_get_state_name(unsigned int st)
 
 static int pvr2_decoder_enable(struct pvr2_hdw *hdw,int enablefl)
 {
-       if (!hdw->decoder_ctrl) {
-               if (!hdw->flag_decoder_missed) {
-                       pvr2_trace(PVR2_TRACE_ERROR_LEGS,
-                                  "WARNING: No decoder present");
-                       hdw->flag_decoder_missed = !0;
-                       trace_stbit("flag_decoder_missed",
-                                   hdw->flag_decoder_missed);
-               }
-               return -EIO;
+       /* Even though we really only care about the video decoder chip at
+          this point, we'll broadcast stream on/off to all sub-devices
+          anyway, just in case somebody else wants to hear the
+          command... */
+       pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 stream=%s",
+                  (enablefl ? "on" : "off"));
+       v4l2_device_call_all(&hdw->v4l2_dev, 0, video, s_stream, enablefl);
+       if (hdw->decoder_client_id) {
+               /* We get here if the encoder has been noticed.  Otherwise
+                  we'll issue a warning to the user (which should
+                  normally never happen). */
+               return 0;
        }
-       hdw->decoder_ctrl->enable(hdw->decoder_ctrl->ctxt,enablefl);
-       return 0;
-}
-
-
-void pvr2_hdw_set_decoder(struct pvr2_hdw *hdw,struct pvr2_decoder_ctrl *ptr)
-{
-       if (hdw->decoder_ctrl == ptr) return;
-       hdw->decoder_ctrl = ptr;
-       if (hdw->decoder_ctrl && hdw->flag_decoder_missed) {
-               hdw->flag_decoder_missed = 0;
+       if (!hdw->flag_decoder_missed) {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "WARNING: No decoder present");
+               hdw->flag_decoder_missed = !0;
                trace_stbit("flag_decoder_missed",
                            hdw->flag_decoder_missed);
-               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
-                          "Decoder has appeared");
-               pvr2_hdw_state_sched(hdw);
        }
+       return -EIO;
 }
 
 
@@ -1364,11 +1728,6 @@ int pvr2_hdw_untrip(struct pvr2_hdw *hdw)
 }
 
 
-const char *pvr2_hdw_get_state_name(unsigned int id)
-{
-       if (id >= ARRAY_SIZE(pvr2_state_names)) return NULL;
-       return pvr2_state_names[id];
-}
 
 
 int pvr2_hdw_get_streaming(struct pvr2_hdw *hdw)
@@ -1495,7 +1854,7 @@ struct pvr2_std_hack {
    default - which can always be overridden explicitly - and if the user
    has otherwise named a default then that default will always be used in
    place of this table. */
-const static struct pvr2_std_hack std_eeprom_maps[] = {
+static const struct pvr2_std_hack std_eeprom_maps[] = {
        {       /* PAL(B/G) */
                .pat = V4L2_STD_B|V4L2_STD_GH,
                .std = V4L2_STD_PAL_B|V4L2_STD_PAL_B1|V4L2_STD_PAL_G,
@@ -1605,6 +1964,166 @@ static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw)
 }
 
 
+static unsigned int pvr2_copy_i2c_addr_list(
+       unsigned short *dst, const unsigned char *src,
+       unsigned int dst_max)
+{
+       unsigned int cnt = 0;
+       if (!src) return 0;
+       while (src[cnt] && (cnt + 1) < dst_max) {
+               dst[cnt] = src[cnt];
+               cnt++;
+       }
+       dst[cnt] = I2C_CLIENT_END;
+       return cnt;
+}
+
+
+static int pvr2_hdw_load_subdev(struct pvr2_hdw *hdw,
+                               const struct pvr2_device_client_desc *cd)
+{
+       const char *fname;
+       unsigned char mid;
+       struct v4l2_subdev *sd;
+       unsigned int i2ccnt;
+       const unsigned char *p;
+       /* Arbitrary count - max # i2c addresses we will probe */
+       unsigned short i2caddr[25];
+
+       mid = cd->module_id;
+       fname = (mid < ARRAY_SIZE(module_names)) ? module_names[mid] : NULL;
+       if (!fname) {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "Module ID %u for device %s has no name",
+                          mid,
+                          hdw->hdw_desc->description);
+               return -EINVAL;
+       }
+       pvr2_trace(PVR2_TRACE_INIT,
+                  "Module ID %u (%s) for device %s being loaded...",
+                  mid, fname,
+                  hdw->hdw_desc->description);
+
+       i2ccnt = pvr2_copy_i2c_addr_list(i2caddr, cd->i2c_address_list,
+                                        ARRAY_SIZE(i2caddr));
+       if (!i2ccnt && ((p = (mid < ARRAY_SIZE(module_i2c_addresses)) ?
+                        module_i2c_addresses[mid] : NULL) != NULL)) {
+               /* Second chance: Try default i2c address list */
+               i2ccnt = pvr2_copy_i2c_addr_list(i2caddr, p,
+                                                ARRAY_SIZE(i2caddr));
+               if (i2ccnt) {
+                       pvr2_trace(PVR2_TRACE_INIT,
+                                  "Module ID %u:"
+                                  " Using default i2c address list",
+                                  mid);
+               }
+       }
+
+       if (!i2ccnt) {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "Module ID %u (%s) for device %s:"
+                          " No i2c addresses",
+                          mid, fname, hdw->hdw_desc->description);
+               return -EINVAL;
+       }
+
+       /* Note how the 2nd and 3rd arguments are the same for both
+        * v4l2_i2c_new_subdev() and v4l2_i2c_new_probed_subdev().  Why?
+        * Well the 2nd argument is the module name to load, while the 3rd
+        * argument is documented in the framework as being the "chipid" -
+        * and every other place where I can find examples of this, the
+        * "chipid" appears to just be the module name again.  So here we
+        * just do the same thing. */
+       if (i2ccnt == 1) {
+               pvr2_trace(PVR2_TRACE_INIT,
+                          "Module ID %u:"
+                          " Setting up with specified i2c address 0x%x",
+                          mid, i2caddr[0]);
+               sd = v4l2_i2c_new_subdev(&hdw->i2c_adap,
+                                        fname, fname,
+                                        i2caddr[0]);
+       } else {
+               pvr2_trace(PVR2_TRACE_INIT,
+                          "Module ID %u:"
+                          " Setting up with address probe list",
+                          mid);
+               sd = v4l2_i2c_new_probed_subdev(&hdw->i2c_adap,
+                                               fname, fname,
+                                               i2caddr);
+       }
+
+       if (!sd) {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "Module ID %u (%s) for device %s failed to load",
+                          mid, fname, hdw->hdw_desc->description);
+               return -EIO;
+       }
+
+       /* Tag this sub-device instance with the module ID we know about.
+          In other places we'll use that tag to determine if the instance
+          requires special handling. */
+       sd->grp_id = mid;
+
+       pvr2_trace(PVR2_TRACE_INFO, "Attached sub-driver %s", fname);
+
+
+       /* client-specific setup... */
+       switch (mid) {
+       case PVR2_CLIENT_ID_CX25840:
+               hdw->decoder_client_id = mid;
+               {
+                       /*
+                         Mike Isely <isely@pobox.com> 19-Nov-2006 - This
+                         bit of nuttiness for cx25840 causes that module
+                         to correctly set up its video scaling.  This is
+                         really a problem in the cx25840 module itself,
+                         but we work around it here.  The problem has not
+                         been seen in ivtv because there VBI is supported
+                         and set up.  We don't do VBI here (at least not
+                         yet) and thus we never attempted to even set it
+                         up.
+                       */
+                       struct v4l2_format fmt;
+                       pvr2_trace(PVR2_TRACE_INIT,
+                                  "Module ID %u:"
+                                  " Executing cx25840 VBI hack",
+                                  mid);
+                       memset(&fmt, 0, sizeof(fmt));
+                       fmt.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
+                       v4l2_device_call_all(&hdw->v4l2_dev, mid,
+                                            video, s_fmt, &fmt);
+               }
+               break;
+       case PVR2_CLIENT_ID_SAA7115:
+               hdw->decoder_client_id = mid;
+               break;
+       default: break;
+       }
+
+       return 0;
+}
+
+
+static void pvr2_hdw_load_modules(struct pvr2_hdw *hdw)
+{
+       unsigned int idx;
+       const struct pvr2_string_table *cm;
+       const struct pvr2_device_client_table *ct;
+       int okFl = !0;
+
+       cm = &hdw->hdw_desc->client_modules;
+       for (idx = 0; idx < cm->cnt; idx++) {
+               request_module(cm->lst[idx]);
+       }
+
+       ct = &hdw->hdw_desc->client_table;
+       for (idx = 0; idx < ct->cnt; idx++) {
+               if (pvr2_hdw_load_subdev(hdw, &ct->lst[idx]) < 0) okFl = 0;
+       }
+       if (!okFl) pvr2_hdw_render_useless(hdw);
+}
+
+
 static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
 {
        int ret;
@@ -1642,24 +2161,32 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
        }
        hdw->fw1_state = FW1_STATE_OK;
 
-       if (initusbreset) {
-               pvr2_hdw_device_reset(hdw);
-       }
        if (!pvr2_hdw_dev_ok(hdw)) return;
 
-       for (idx = 0; idx < hdw->hdw_desc->client_modules.cnt; idx++) {
-               request_module(hdw->hdw_desc->client_modules.lst[idx]);
-       }
+       hdw->force_dirty = !0;
 
        if (!hdw->hdw_desc->flag_no_powerup) {
                pvr2_hdw_cmd_powerup(hdw);
                if (!pvr2_hdw_dev_ok(hdw)) return;
        }
 
+       /* Take the IR chip out of reset, if appropriate */
+       if (hdw->hdw_desc->ir_scheme == PVR2_IR_SCHEME_ZILOG) {
+               pvr2_issue_simple_cmd(hdw,
+                                     FX2CMD_HCW_ZILOG_RESET |
+                                     (1 << 8) |
+                                     ((0) << 16));
+       }
+
        // This step MUST happen after the earlier powerup step.
        pvr2_i2c_core_init(hdw);
        if (!pvr2_hdw_dev_ok(hdw)) return;
 
+       pvr2_hdw_load_modules(hdw);
+       if (!pvr2_hdw_dev_ok(hdw)) return;
+
+       v4l2_device_call_all(&hdw->v4l2_dev, 0, core, init, 0);
+
        for (idx = 0; idx < CTRLDEF_COUNT; idx++) {
                cptr = hdw->controls + idx;
                if (cptr->info->skip_init) continue;
@@ -1672,10 +2199,8 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
           are, but I set them to something usable in the Chicago area just
           to make driver testing a little easier. */
 
-       /* US Broadcast channel 7 (175.25 MHz) */
-       hdw->freqValTelevision = 175250000L;
-       /* 104.3 MHz, a usable FM station for my area */
-       hdw->freqValRadio = 104300000L;
+       hdw->freqValTelevision = default_tv_freq;
+       hdw->freqValRadio = default_radio_freq;
 
        // Do not use pvr2_reset_ctl_endpoints() here.  It is not
        // thread-safe against the normal pvr2_send_request() mechanism.
@@ -1699,6 +2224,19 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
                hdw->std_mask_eeprom = V4L2_STD_ALL;
        }
 
+       if (hdw->serial_number) {
+               idx = scnprintf(hdw->identifier, sizeof(hdw->identifier) - 1,
+                               "sn-%lu", hdw->serial_number);
+       } else if (hdw->unit_number >= 0) {
+               idx = scnprintf(hdw->identifier, sizeof(hdw->identifier) - 1,
+                               "unit-%c",
+                               hdw->unit_number + 'a');
+       } else {
+               idx = scnprintf(hdw->identifier, sizeof(hdw->identifier) - 1,
+                               "unit-??");
+       }
+       hdw->identifier[idx] = 0;
+
        pvr2_hdw_setup_std(hdw);
 
        if (!get_default_tuner_type(hdw)) {
@@ -1707,11 +2245,16 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
                           hdw->tuner_type);
        }
 
-       pvr2_i2c_core_check_stale(hdw);
-       hdw->tuner_updated = 0;
 
        if (!pvr2_hdw_dev_ok(hdw)) return;
 
+       if (hdw->hdw_desc->signal_routing_scheme ==
+           PVR2_ROUTING_SCHEME_GOTVIEW) {
+               /* Ensure that GPIO 11 is set to output for GOTVIEW
+                  hardware. */
+               pvr2_hdw_gpio_chg_dir(hdw,(1 << 11),~0);
+       }
+
        pvr2_hdw_commit_setup(hdw);
 
        hdw->vid_stream = pvr2_stream_create();
@@ -1805,22 +2348,60 @@ static void pvr2_hdw_setup(struct pvr2_hdw *hdw)
 }
 
 
-/* Create and return a structure for interacting with the underlying
-   hardware */
+/* Perform second stage initialization.  Set callback pointer first so that
+   we can avoid a possible initialization race (if the kernel thread runs
+   before the callback has been set). */
+int pvr2_hdw_initialize(struct pvr2_hdw *hdw,
+                       void (*callback_func)(void *),
+                       void *callback_data)
+{
+       LOCK_TAKE(hdw->big_lock); do {
+               if (hdw->flag_disconnected) {
+                       /* Handle a race here: If we're already
+                          disconnected by this point, then give up.  If we
+                          get past this then we'll remain connected for
+                          the duration of initialization since the entire
+                          initialization sequence is now protected by the
+                          big_lock. */
+                       break;
+               }
+               hdw->state_data = callback_data;
+               hdw->state_func = callback_func;
+               pvr2_hdw_setup(hdw);
+       } while (0); LOCK_GIVE(hdw->big_lock);
+       return hdw->flag_init_ok;
+}
+
+
+/* Create, set up, and return a structure for interacting with the
+   underlying hardware.  */
 struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
                                 const struct usb_device_id *devid)
 {
-       unsigned int idx,cnt1,cnt2;
-       struct pvr2_hdw *hdw;
+       unsigned int idx,cnt1,cnt2,m;
+       struct pvr2_hdw *hdw = NULL;
        int valid_std_mask;
        struct pvr2_ctrl *cptr;
+       struct usb_device *usb_dev;
        const struct pvr2_device_desc *hdw_desc;
        __u8 ifnum;
        struct v4l2_queryctrl qctrl;
        struct pvr2_ctl_info *ciptr;
 
+       usb_dev = interface_to_usbdev(intf);
+
        hdw_desc = (const struct pvr2_device_desc *)(devid->driver_info);
 
+       if (hdw_desc == NULL) {
+               pvr2_trace(PVR2_TRACE_INIT, "pvr2_hdw_create:"
+                          " No device description pointer,"
+                          " unable to continue.");
+               pvr2_trace(PVR2_TRACE_INIT, "If you have a new device type,"
+                          " please contact Mike Isely <isely@pobox.com>"
+                          " to get it included in the driver\n");
+               goto fail;
+       }
+
        hdw = kzalloc(sizeof(*hdw),GFP_KERNEL);
        pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_create: hdw=%p, type \"%s\"",
                   hdw,hdw_desc->description);
@@ -1834,6 +2415,10 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
        hdw->encoder_wait_timer.data = (unsigned long)hdw;
        hdw->encoder_wait_timer.function = pvr2_hdw_encoder_wait_timeout;
 
+       init_timer(&hdw->encoder_run_timer);
+       hdw->encoder_run_timer.data = (unsigned long)hdw;
+       hdw->encoder_run_timer.function = pvr2_hdw_encoder_run_timeout;
+
        hdw->master_state = PVR2_STATE_DEAD;
 
        init_waitqueue_head(&hdw->state_wait_data);
@@ -1841,9 +2426,29 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
        hdw->tuner_signal_stale = !0;
        cx2341x_fill_defaults(&hdw->enc_ctl_state);
 
-       hdw->control_cnt = CTRLDEF_COUNT;
-       hdw->control_cnt += MPEGDEF_COUNT;
-       hdw->controls = kzalloc(sizeof(struct pvr2_ctrl) * hdw->control_cnt,
+       /* Calculate which inputs are OK */
+       m = 0;
+       if (hdw_desc->flag_has_analogtuner) m |= 1 << PVR2_CVAL_INPUT_TV;
+       if (hdw_desc->digital_control_scheme != PVR2_DIGITAL_SCHEME_NONE) {
+               m |= 1 << PVR2_CVAL_INPUT_DTV;
+       }
+       if (hdw_desc->flag_has_svideo) m |= 1 << PVR2_CVAL_INPUT_SVIDEO;
+       if (hdw_desc->flag_has_composite) m |= 1 << PVR2_CVAL_INPUT_COMPOSITE;
+       if (hdw_desc->flag_has_fmradio) m |= 1 << PVR2_CVAL_INPUT_RADIO;
+       hdw->input_avail_mask = m;
+       hdw->input_allowed_mask = hdw->input_avail_mask;
+
+       /* If not a hybrid device, pathway_state never changes.  So
+          initialize it here to what it should forever be. */
+       if (!(hdw->input_avail_mask & (1 << PVR2_CVAL_INPUT_DTV))) {
+               hdw->pathway_state = PVR2_PATHWAY_ANALOG;
+       } else if (!(hdw->input_avail_mask & (1 << PVR2_CVAL_INPUT_TV))) {
+               hdw->pathway_state = PVR2_PATHWAY_DIGITAL;
+       }
+
+       hdw->control_cnt = CTRLDEF_COUNT;
+       hdw->control_cnt += MPEGDEF_COUNT;
+       hdw->controls = kzalloc(sizeof(struct pvr2_ctrl) * hdw->control_cnt,
                                GFP_KERNEL);
        if (!hdw->controls) goto fail;
        hdw->hdw_desc = hdw_desc;
@@ -1858,6 +2463,15 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
                cptr = hdw->controls + idx;
                cptr->info = control_defs+idx;
        }
+
+       /* Ensure that default input choice is a valid one. */
+       m = hdw->input_avail_mask;
+       if (m) for (idx = 0; idx < (sizeof(m) << 3); idx++) {
+               if (!((1 << idx) & m)) continue;
+               hdw->input_val = idx;
+               break;
+       }
+
        /* Define and configure additional controls from cx2341x module. */
        hdw->mpeg_ctrl_info = kzalloc(
                sizeof(*(hdw->mpeg_ctrl_info)) * MPEGDEF_COUNT, GFP_KERNEL);
@@ -1895,7 +2509,8 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
                case V4L2_CTRL_TYPE_MENU:
                        ciptr->type = pvr2_ctl_enum;
                        ciptr->def.type_enum.value_names =
-                               cx2341x_ctrl_get_menu(ciptr->v4l_id);
+                               cx2341x_ctrl_get_menu(&hdw->enc_ctl_state,
+                                                               ciptr->v4l_id);
                        for (cnt1 = 0;
                             ciptr->def.type_enum.value_names[cnt1] != NULL;
                             cnt1++) { }
@@ -1944,6 +2559,7 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
                        valid_std_mask;
        }
 
+       hdw->cropcap_stale = !0;
        hdw->eeprom_addr = -1;
        hdw->unit_number = -1;
        hdw->v4l_minor_number_video = -1;
@@ -1958,6 +2574,11 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
        hdw->ctl_read_urb = usb_alloc_urb(0,GFP_KERNEL);
        if (!hdw->ctl_read_urb) goto fail;
 
+       if (v4l2_device_register(&usb_dev->dev, &hdw->v4l2_dev) != 0) {
+               pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+                          "Error registering with v4l core, giving up");
+               goto fail;
+       }
        mutex_lock(&pvr2_unit_mtx); do {
                for (idx = 0; idx < PVR_NUM; idx++) {
                        if (unit_pointers[idx]) continue;
@@ -1980,8 +2601,6 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
 
        hdw->workqueue = create_singlethread_workqueue(hdw->name);
        INIT_WORK(&hdw->workpoll,pvr2_hdw_worker_poll);
-       INIT_WORK(&hdw->worki2csync,pvr2_hdw_worker_i2c);
-       INIT_WORK(&hdw->workinit,pvr2_hdw_worker_init);
 
        pvr2_trace(PVR2_TRACE_INIT,"Driver unit number is %d, name is %s",
                   hdw->unit_number,hdw->name);
@@ -1990,12 +2609,9 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
        hdw->flag_ok = !0;
 
        hdw->usb_intf = intf;
-       hdw->usb_dev = interface_to_usbdev(intf);
+       hdw->usb_dev = usb_dev;
 
-       scnprintf(hdw->bus_info,sizeof(hdw->bus_info),
-                 "usb %s address %d",
-                 hdw->usb_dev->dev.bus_id,
-                 hdw->usb_dev->devnum);
+       usb_make_path(hdw->usb_dev, hdw->bus_info, sizeof(hdw->bus_info));
 
        ifnum = hdw->usb_intf->cur_altsetting->desc.bInterfaceNumber;
        usb_set_interface(hdw->usb_dev,ifnum,0);
@@ -2003,11 +2619,11 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
        mutex_init(&hdw->ctl_lock_mutex);
        mutex_init(&hdw->big_lock_mutex);
 
-       queue_work(hdw->workqueue,&hdw->workinit);
        return hdw;
  fail:
        if (hdw) {
                del_timer_sync(&hdw->quiescent_timer);
+               del_timer_sync(&hdw->encoder_run_timer);
                del_timer_sync(&hdw->encoder_wait_timer);
                if (hdw->workqueue) {
                        flush_workqueue(hdw->workqueue);
@@ -2053,6 +2669,13 @@ static void pvr2_hdw_remove_usb_stuff(struct pvr2_hdw *hdw)
                hdw->ctl_write_buffer = NULL;
        }
        hdw->flag_disconnected = !0;
+       /* If we don't do this, then there will be a dangling struct device
+          reference to our disappearing device persisting inside the V4L
+          core... */
+       if (hdw->v4l2_dev.dev) {
+               dev_set_drvdata(hdw->v4l2_dev.dev, NULL);
+               hdw->v4l2_dev.dev = NULL;
+       }
        hdw->usb_dev = NULL;
        hdw->usb_intf = NULL;
        pvr2_hdw_render_useless(hdw);
@@ -2064,13 +2687,14 @@ void pvr2_hdw_destroy(struct pvr2_hdw *hdw)
 {
        if (!hdw) return;
        pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_destroy: hdw=%p",hdw);
-       del_timer_sync(&hdw->quiescent_timer);
-       del_timer_sync(&hdw->encoder_wait_timer);
        if (hdw->workqueue) {
                flush_workqueue(hdw->workqueue);
                destroy_workqueue(hdw->workqueue);
                hdw->workqueue = NULL;
        }
+       del_timer_sync(&hdw->quiescent_timer);
+       del_timer_sync(&hdw->encoder_run_timer);
+       del_timer_sync(&hdw->encoder_wait_timer);
        if (hdw->fw_buffer) {
                kfree(hdw->fw_buffer);
                hdw->fw_buffer = NULL;
@@ -2079,10 +2703,8 @@ void pvr2_hdw_destroy(struct pvr2_hdw *hdw)
                pvr2_stream_destroy(hdw->vid_stream);
                hdw->vid_stream = NULL;
        }
-       if (hdw->decoder_ctrl) {
-               hdw->decoder_ctrl->detach(hdw->decoder_ctrl->ctxt);
-       }
        pvr2_i2c_core_done(hdw);
+       v4l2_device_unregister(&hdw->v4l2_dev);
        pvr2_hdw_remove_usb_stuff(hdw);
        mutex_lock(&pvr2_unit_mtx); do {
                if ((hdw->unit_number >= 0) &&
@@ -2276,6 +2898,150 @@ static const char *get_ctrl_typename(enum pvr2_ctl_type tp)
 }
 
 
+static void pvr2_subdev_set_control(struct pvr2_hdw *hdw, int id,
+                                   const char *name, int val)
+{
+       struct v4l2_control ctrl;
+       pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 %s=%d", name, val);
+       memset(&ctrl, 0, sizeof(ctrl));
+       ctrl.id = id;
+       ctrl.value = val;
+       v4l2_device_call_all(&hdw->v4l2_dev, 0, core, s_ctrl, &ctrl);
+}
+
+#define PVR2_SUBDEV_SET_CONTROL(hdw, id, lab) \
+       if ((hdw)->lab##_dirty || (hdw)->force_dirty) {         \
+               pvr2_subdev_set_control(hdw, id, #lab, (hdw)->lab##_val); \
+       }
+
+/* Execute whatever commands are required to update the state of all the
+   sub-devices so that they match our current control values. */
+static void pvr2_subdev_update(struct pvr2_hdw *hdw)
+{
+       struct v4l2_subdev *sd;
+       unsigned int id;
+       pvr2_subdev_update_func fp;
+
+       pvr2_trace(PVR2_TRACE_CHIPS, "subdev update...");
+
+       if (hdw->tuner_updated || hdw->force_dirty) {
+               struct tuner_setup setup;
+               pvr2_trace(PVR2_TRACE_CHIPS, "subdev tuner set_type(%d)",
+                          hdw->tuner_type);
+               if (((int)(hdw->tuner_type)) >= 0) {
+                       setup.addr = ADDR_UNSET;
+                       setup.type = hdw->tuner_type;
+                       setup.mode_mask = T_RADIO | T_ANALOG_TV;
+                       v4l2_device_call_all(&hdw->v4l2_dev, 0,
+                                            tuner, s_type_addr, &setup);
+               }
+       }
+
+       if (hdw->input_dirty || hdw->std_dirty || hdw->force_dirty) {
+               pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 set_standard");
+               if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
+                       v4l2_device_call_all(&hdw->v4l2_dev, 0,
+                                            tuner, s_radio);
+               } else {
+                       v4l2_std_id vs;
+                       vs = hdw->std_mask_cur;
+                       v4l2_device_call_all(&hdw->v4l2_dev, 0,
+                                            tuner, s_std, vs);
+               }
+               hdw->tuner_signal_stale = !0;
+               hdw->cropcap_stale = !0;
+       }
+
+       PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_BRIGHTNESS, brightness);
+       PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_CONTRAST, contrast);
+       PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_SATURATION, saturation);
+       PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_HUE, hue);
+       PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_AUDIO_MUTE, mute);
+       PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_AUDIO_VOLUME, volume);
+       PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_AUDIO_BALANCE, balance);
+       PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_AUDIO_BASS, bass);
+       PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_AUDIO_TREBLE, treble);
+
+       if (hdw->input_dirty || hdw->audiomode_dirty || hdw->force_dirty) {
+               struct v4l2_tuner vt;
+               memset(&vt, 0, sizeof(vt));
+               vt.audmode = hdw->audiomode_val;
+               v4l2_device_call_all(&hdw->v4l2_dev, 0, tuner, s_tuner, &vt);
+       }
+
+       if (hdw->freqDirty || hdw->force_dirty) {
+               unsigned long fv;
+               struct v4l2_frequency freq;
+               fv = pvr2_hdw_get_cur_freq(hdw);
+               pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 set_freq(%lu)", fv);
+               if (hdw->tuner_signal_stale) pvr2_hdw_status_poll(hdw);
+               memset(&freq, 0, sizeof(freq));
+               if (hdw->tuner_signal_info.capability & V4L2_TUNER_CAP_LOW) {
+                       /* ((fv * 1000) / 62500) */
+                       freq.frequency = (fv * 2) / 125;
+               } else {
+                       freq.frequency = fv / 62500;
+               }
+               /* tuner-core currently doesn't seem to care about this, but
+                  let's set it anyway for completeness. */
+               if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
+                       freq.type = V4L2_TUNER_RADIO;
+               } else {
+                       freq.type = V4L2_TUNER_ANALOG_TV;
+               }
+               freq.tuner = 0;
+               v4l2_device_call_all(&hdw->v4l2_dev, 0, tuner,
+                                    s_frequency, &freq);
+       }
+
+       if (hdw->res_hor_dirty || hdw->res_ver_dirty || hdw->force_dirty) {
+               struct v4l2_format fmt;
+               memset(&fmt, 0, sizeof(fmt));
+               fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               fmt.fmt.pix.width = hdw->res_hor_val;
+               fmt.fmt.pix.height = hdw->res_ver_val;
+               pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 set_size(%dx%d)",
+                          fmt.fmt.pix.width, fmt.fmt.pix.height);
+               v4l2_device_call_all(&hdw->v4l2_dev, 0, video, s_fmt, &fmt);
+       }
+
+       if (hdw->srate_dirty || hdw->force_dirty) {
+               u32 val;
+               pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 set_audio %d",
+                          hdw->srate_val);
+               switch (hdw->srate_val) {
+               default:
+               case V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000:
+                       val = 48000;
+                       break;
+               case V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100:
+                       val = 44100;
+                       break;
+               case V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000:
+                       val = 32000;
+                       break;
+               }
+               v4l2_device_call_all(&hdw->v4l2_dev, 0,
+                                    audio, s_clock_freq, val);
+       }
+
+       /* Unable to set crop parameters; there is apparently no equivalent
+          for VIDIOC_S_CROP */
+
+       v4l2_device_for_each_subdev(sd, &hdw->v4l2_dev) {
+               id = sd->grp_id;
+               if (id >= ARRAY_SIZE(pvr2_module_update_functions)) continue;
+               fp = pvr2_module_update_functions[id];
+               if (!fp) continue;
+               (*fp)(hdw, sd);
+       }
+
+       if (hdw->tuner_signal_stale || hdw->cropcap_stale) {
+               pvr2_hdw_status_poll(hdw);
+       }
+}
+
+
 /* Figure out if we need to commit control changes.  If so, mark internal
    state flags to indicate this fact and return true.  Otherwise do nothing
    else and return false. */
@@ -2284,7 +3050,7 @@ static int pvr2_hdw_commit_setup(struct pvr2_hdw *hdw)
        unsigned int idx;
        struct pvr2_ctrl *cptr;
        int value;
-       int commit_flag = 0;
+       int commit_flag = hdw->force_dirty;
        char buf[100];
        unsigned int bcnt,ccnt;
 
@@ -2334,22 +3100,72 @@ static int pvr2_hdw_commit_execute(struct pvr2_hdw *hdw)
        struct pvr2_ctrl *cptr;
        int disruptive_change;
 
-       /* When video standard changes, reset the hres and vres values -
-          but if the user has pending changes there, then let the changes
-          take priority. */
+       /* Handle some required side effects when the video standard is
+          changed.... */
        if (hdw->std_dirty) {
-               /* Rewrite the vertical resolution to be appropriate to the
-                  video standard that has been selected. */
                int nvres;
+               int gop_size;
                if (hdw->std_mask_cur & V4L2_STD_525_60) {
                        nvres = 480;
+                       gop_size = 15;
                } else {
                        nvres = 576;
+                       gop_size = 12;
                }
+               /* Rewrite the vertical resolution to be appropriate to the
+                  video standard that has been selected. */
                if (nvres != hdw->res_ver_val) {
                        hdw->res_ver_val = nvres;
                        hdw->res_ver_dirty = !0;
                }
+               /* Rewrite the GOP size to be appropriate to the video
+                  standard that has been selected. */
+               if (gop_size != hdw->enc_ctl_state.video_gop_size) {
+                       struct v4l2_ext_controls cs;
+                       struct v4l2_ext_control c1;
+                       memset(&cs, 0, sizeof(cs));
+                       memset(&c1, 0, sizeof(c1));
+                       cs.controls = &c1;
+                       cs.count = 1;
+                       c1.id = V4L2_CID_MPEG_VIDEO_GOP_SIZE;
+                       c1.value = gop_size;
+                       cx2341x_ext_ctrls(&hdw->enc_ctl_state, 0, &cs,
+                                         VIDIOC_S_EXT_CTRLS);
+               }
+       }
+
+       if (hdw->input_dirty && hdw->state_pathway_ok &&
+           (((hdw->input_val == PVR2_CVAL_INPUT_DTV) ?
+             PVR2_PATHWAY_DIGITAL : PVR2_PATHWAY_ANALOG) !=
+            hdw->pathway_state)) {
+               /* Change of mode being asked for... */
+               hdw->state_pathway_ok = 0;
+               trace_stbit("state_pathway_ok",hdw->state_pathway_ok);
+       }
+       if (!hdw->state_pathway_ok) {
+               /* Can't commit anything until pathway is ok. */
+               return 0;
+       }
+       /* The broadcast decoder can only scale down, so if
+        * res_*_dirty && crop window < output format ==> enlarge crop.
+        *
+        * The mpeg encoder receives fields of res_hor_val dots and
+        * res_ver_val halflines.  Limits: hor<=720, ver<=576.
+        */
+       if (hdw->res_hor_dirty && hdw->cropw_val < hdw->res_hor_val) {
+               hdw->cropw_val = hdw->res_hor_val;
+               hdw->cropw_dirty = !0;
+       } else if (hdw->cropw_dirty) {
+               hdw->res_hor_dirty = !0;           /* must rescale */
+               hdw->res_hor_val = min(720, hdw->cropw_val);
+       }
+       if (hdw->res_ver_dirty && hdw->croph_val < hdw->res_ver_val) {
+               hdw->croph_val = hdw->res_ver_val;
+               hdw->croph_dirty = !0;
+       } else if (hdw->croph_dirty) {
+               int nvres = hdw->std_mask_cur & V4L2_STD_525_60 ? 480 : 576;
+               hdw->res_ver_dirty = !0;
+               hdw->res_ver_val = min(nvres, hdw->croph_val);
        }
 
        /* If any of the below has changed, then we can't do the update
@@ -2362,6 +3178,8 @@ static int pvr2_hdw_commit_execute(struct pvr2_hdw *hdw)
                 hdw->srate_dirty ||
                 hdw->res_ver_dirty ||
                 hdw->res_hor_dirty ||
+                hdw->cropw_dirty ||
+                hdw->croph_dirty ||
                 hdw->input_dirty ||
                 (hdw->active_stream_type != hdw->desired_stream_type));
        if (disruptive_change && !hdw->state_pipeline_idle) {
@@ -2388,33 +3206,48 @@ static int pvr2_hdw_commit_execute(struct pvr2_hdw *hdw)
                cx2341x_ext_ctrls(&hdw->enc_ctl_state, 0, &cs,VIDIOC_S_EXT_CTRLS);
        }
 
-       /* Scan i2c core at this point - before we clear all the dirty
-          bits.  Various parts of the i2c core will notice dirty bits as
-          appropriate and arrange to broadcast or directly send updates to
-          the client drivers in order to keep everything in sync */
-       pvr2_i2c_core_check_stale(hdw);
+       if (hdw->active_stream_type != hdw->desired_stream_type) {
+               /* Handle any side effects of stream config here */
+               hdw->active_stream_type = hdw->desired_stream_type;
+       }
+
+       if (hdw->hdw_desc->signal_routing_scheme ==
+           PVR2_ROUTING_SCHEME_GOTVIEW) {
+               u32 b;
+               /* Handle GOTVIEW audio switching */
+               pvr2_hdw_gpio_get_out(hdw,&b);
+               if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
+                       /* Set GPIO 11 */
+                       pvr2_hdw_gpio_chg_out(hdw,(1 << 11),~0);
+               } else {
+                       /* Clear GPIO 11 */
+                       pvr2_hdw_gpio_chg_out(hdw,(1 << 11),0);
+               }
+       }
+
+       /* Check and update state for all sub-devices. */
+       pvr2_subdev_update(hdw);
 
+       hdw->tuner_updated = 0;
+       hdw->force_dirty = 0;
        for (idx = 0; idx < hdw->control_cnt; idx++) {
                cptr = hdw->controls + idx;
                if (!cptr->info->clear_dirty) continue;
                cptr->info->clear_dirty(cptr);
        }
 
-       if (hdw->active_stream_type != hdw->desired_stream_type) {
-               /* Handle any side effects of stream config here */
-               hdw->active_stream_type = hdw->desired_stream_type;
-       }
-
-       /* Now execute i2c core update */
-       pvr2_i2c_core_sync(hdw);
-
-       if (hdw->state_encoder_run) {
-               /* If encoder isn't running, then this will get worked out
-                  later when we start the encoder. */
+       if ((hdw->pathway_state == PVR2_PATHWAY_ANALOG) &&
+           hdw->state_encoder_run) {
+               /* If encoder isn't running or it can't be touched, then
+                  this will get worked out later when we start the
+                  encoder. */
                if (pvr2_encoder_adjust(hdw) < 0) return !0;
        }
 
        hdw->state_pipeline_config = !0;
+       /* Hardware state may have changed in a way to cause the cropping
+          capabilities to have changed.  So mark it stale, which will
+          cause a later re-fetch. */
        trace_stbit("state_pipeline_config",hdw->state_pipeline_config);
        return !0;
 }
@@ -2431,15 +3264,6 @@ int pvr2_hdw_commit_ctl(struct pvr2_hdw *hdw)
 }
 
 
-static void pvr2_hdw_worker_i2c(struct work_struct *work)
-{
-       struct pvr2_hdw *hdw = container_of(work,struct pvr2_hdw,worki2csync);
-       LOCK_TAKE(hdw->big_lock); do {
-               pvr2_i2c_core_sync(hdw);
-       } while (0); LOCK_GIVE(hdw->big_lock);
-}
-
-
 static void pvr2_hdw_worker_poll(struct work_struct *work)
 {
        int fl = 0;
@@ -2453,15 +3277,6 @@ static void pvr2_hdw_worker_poll(struct work_struct *work)
 }
 
 
-static void pvr2_hdw_worker_init(struct work_struct *work)
-{
-       struct pvr2_hdw *hdw = container_of(work,struct pvr2_hdw,workinit);
-       LOCK_TAKE(hdw->big_lock); do {
-               pvr2_hdw_setup(hdw);
-       } while (0); LOCK_GIVE(hdw->big_lock);
-}
-
-
 static int pvr2_hdw_wait(struct pvr2_hdw *hdw,int state)
 {
        return wait_event_interruptible(
@@ -2471,17 +3286,6 @@ static int pvr2_hdw_wait(struct pvr2_hdw *hdw,int state)
 }
 
 
-void pvr2_hdw_set_state_callback(struct pvr2_hdw *hdw,
-                                void (*callback_func)(void *),
-                                void *callback_data)
-{
-       LOCK_TAKE(hdw->big_lock); do {
-               hdw->state_data = callback_data;
-               hdw->state_func = callback_func;
-       } while (0); LOCK_GIVE(hdw->big_lock);
-}
-
-
 /* Return name for this driver instance */
 const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *hdw)
 {
@@ -2520,17 +3324,44 @@ int pvr2_hdw_is_hsm(struct pvr2_hdw *hdw)
 void pvr2_hdw_execute_tuner_poll(struct pvr2_hdw *hdw)
 {
        LOCK_TAKE(hdw->big_lock); do {
-               pvr2_i2c_core_status_poll(hdw);
+               pvr2_hdw_status_poll(hdw);
        } while (0); LOCK_GIVE(hdw->big_lock);
 }
 
 
+static int pvr2_hdw_check_cropcap(struct pvr2_hdw *hdw)
+{
+       if (!hdw->cropcap_stale) {
+               return 0;
+       }
+       pvr2_hdw_status_poll(hdw);
+       if (hdw->cropcap_stale) {
+               return -EIO;
+       }
+       return 0;
+}
+
+
+/* Return information about cropping capabilities */
+int pvr2_hdw_get_cropcap(struct pvr2_hdw *hdw, struct v4l2_cropcap *pp)
+{
+       int stat = 0;
+       LOCK_TAKE(hdw->big_lock);
+       stat = pvr2_hdw_check_cropcap(hdw);
+       if (!stat) {
+               memcpy(pp, &hdw->cropcap_info, sizeof(hdw->cropcap_info));
+       }
+       LOCK_GIVE(hdw->big_lock);
+       return stat;
+}
+
+
 /* Return information about the tuner */
 int pvr2_hdw_get_tuner_status(struct pvr2_hdw *hdw,struct v4l2_tuner *vtp)
 {
        LOCK_TAKE(hdw->big_lock); do {
                if (hdw->tuner_signal_stale) {
-                       pvr2_i2c_core_status_poll(hdw);
+                       pvr2_hdw_status_poll(hdw);
                }
                memcpy(vtp,&hdw->tuner_signal_info,sizeof(struct v4l2_tuner));
        } while (0); LOCK_GIVE(hdw->big_lock);
@@ -2549,11 +3380,8 @@ void pvr2_hdw_trigger_module_log(struct pvr2_hdw *hdw)
 {
        int nr = pvr2_hdw_get_unit_number(hdw);
        LOCK_TAKE(hdw->big_lock); do {
-               hdw->log_requested = !0;
                printk(KERN_INFO "pvrusb2: =================  START STATUS CARD #%d  =================\n", nr);
-               pvr2_i2c_core_check_stale(hdw);
-               hdw->log_requested = 0;
-               pvr2_i2c_core_sync(hdw);
+               v4l2_device_call_all(&hdw->v4l2_dev, 0, core, log_status);
                pvr2_trace(PVR2_TRACE_INFO,"cx2341x config:");
                cx2341x_log_status(&hdw->enc_ctl_state, "pvrusb2");
                pvr2_hdw_state_log_state(hdw);
@@ -3050,6 +3878,67 @@ int pvr2_send_request(struct pvr2_hdw *hdw,
                                    read_data,read_len);
 }
 
+
+static int pvr2_issue_simple_cmd(struct pvr2_hdw *hdw,u32 cmdcode)
+{
+       int ret;
+       unsigned int cnt = 1;
+       unsigned int args = 0;
+       LOCK_TAKE(hdw->ctl_lock);
+       hdw->cmd_buffer[0] = cmdcode & 0xffu;
+       args = (cmdcode >> 8) & 0xffu;
+       args = (args > 2) ? 2 : args;
+       if (args) {
+               cnt += args;
+               hdw->cmd_buffer[1] = (cmdcode >> 16) & 0xffu;
+               if (args > 1) {
+                       hdw->cmd_buffer[2] = (cmdcode >> 24) & 0xffu;
+               }
+       }
+       if (pvrusb2_debug & PVR2_TRACE_INIT) {
+               unsigned int idx;
+               unsigned int ccnt,bcnt;
+               char tbuf[50];
+               cmdcode &= 0xffu;
+               bcnt = 0;
+               ccnt = scnprintf(tbuf+bcnt,
+                                sizeof(tbuf)-bcnt,
+                                "Sending FX2 command 0x%x",cmdcode);
+               bcnt += ccnt;
+               for (idx = 0; idx < ARRAY_SIZE(pvr2_fx2cmd_desc); idx++) {
+                       if (pvr2_fx2cmd_desc[idx].id == cmdcode) {
+                               ccnt = scnprintf(tbuf+bcnt,
+                                                sizeof(tbuf)-bcnt,
+                                                " \"%s\"",
+                                                pvr2_fx2cmd_desc[idx].desc);
+                               bcnt += ccnt;
+                               break;
+                       }
+               }
+               if (args) {
+                       ccnt = scnprintf(tbuf+bcnt,
+                                        sizeof(tbuf)-bcnt,
+                                        " (%u",hdw->cmd_buffer[1]);
+                       bcnt += ccnt;
+                       if (args > 1) {
+                               ccnt = scnprintf(tbuf+bcnt,
+                                                sizeof(tbuf)-bcnt,
+                                                ",%u",hdw->cmd_buffer[2]);
+                               bcnt += ccnt;
+                       }
+                       ccnt = scnprintf(tbuf+bcnt,
+                                        sizeof(tbuf)-bcnt,
+                                        ")");
+                       bcnt += ccnt;
+               }
+               pvr2_trace(PVR2_TRACE_INIT,"%.*s",bcnt,tbuf);
+       }
+       ret = pvr2_send_request(hdw,hdw->cmd_buffer,cnt,NULL,0);
+       LOCK_GIVE(hdw->ctl_lock);
+       return ret;
+}
+
+
 int pvr2_write_register(struct pvr2_hdw *hdw, u16 reg, u32 data)
 {
        int ret;
@@ -3114,7 +4003,7 @@ void pvr2_hdw_device_reset(struct pvr2_hdw *hdw)
        int ret;
        pvr2_trace(PVR2_TRACE_INIT,"Performing a device reset...");
        ret = usb_lock_device_for_reset(hdw->usb_dev,NULL);
-       if (ret == 1) {
+       if (ret == 0) {
                ret = usb_reset_device(hdw->usb_dev);
                usb_unlock_device(hdw->usb_dev);
        } else {
@@ -3157,59 +4046,204 @@ void pvr2_hdw_cpureset_assert(struct pvr2_hdw *hdw,int val)
 
 int pvr2_hdw_cmd_deep_reset(struct pvr2_hdw *hdw)
 {
-       int status;
-       LOCK_TAKE(hdw->ctl_lock); do {
-               pvr2_trace(PVR2_TRACE_INIT,"Requesting uproc hard reset");
-               hdw->cmd_buffer[0] = FX2CMD_DEEP_RESET;
-               status = pvr2_send_request(hdw,hdw->cmd_buffer,1,NULL,0);
-       } while (0); LOCK_GIVE(hdw->ctl_lock);
-       return status;
+       return pvr2_issue_simple_cmd(hdw,FX2CMD_DEEP_RESET);
 }
 
 
 int pvr2_hdw_cmd_powerup(struct pvr2_hdw *hdw)
 {
-       int status;
-       LOCK_TAKE(hdw->ctl_lock); do {
-               pvr2_trace(PVR2_TRACE_INIT,"Requesting powerup");
-               hdw->cmd_buffer[0] = FX2CMD_POWER_ON;
-               status = pvr2_send_request(hdw,hdw->cmd_buffer,1,NULL,0);
-       } while (0); LOCK_GIVE(hdw->ctl_lock);
-       return status;
+       return pvr2_issue_simple_cmd(hdw,FX2CMD_POWER_ON);
+}
+
+
+int pvr2_hdw_cmd_powerdown(struct pvr2_hdw *hdw)
+{
+       return pvr2_issue_simple_cmd(hdw,FX2CMD_POWER_OFF);
 }
 
 
 int pvr2_hdw_cmd_decoder_reset(struct pvr2_hdw *hdw)
 {
-       if (!hdw->decoder_ctrl) {
-               pvr2_trace(PVR2_TRACE_INIT,
-                          "Unable to reset decoder: nothing attached");
-               return -ENOTTY;
+       pvr2_trace(PVR2_TRACE_INIT,
+                  "Requesting decoder reset");
+       if (hdw->decoder_client_id) {
+               v4l2_device_call_all(&hdw->v4l2_dev, hdw->decoder_client_id,
+                                    core, reset, 0);
+               return 0;
        }
+       pvr2_trace(PVR2_TRACE_INIT,
+                  "Unable to reset decoder: nothing attached");
+       return -ENOTTY;
+}
 
-       if (!hdw->decoder_ctrl->force_reset) {
-               pvr2_trace(PVR2_TRACE_INIT,
-                          "Unable to reset decoder: not implemented");
-               return -ENOTTY;
+
+static int pvr2_hdw_cmd_hcw_demod_reset(struct pvr2_hdw *hdw, int onoff)
+{
+       hdw->flag_ok = !0;
+       return pvr2_issue_simple_cmd(hdw,
+                                    FX2CMD_HCW_DEMOD_RESETIN |
+                                    (1 << 8) |
+                                    ((onoff ? 1 : 0) << 16));
+}
+
+
+static int pvr2_hdw_cmd_onair_fe_power_ctrl(struct pvr2_hdw *hdw, int onoff)
+{
+       hdw->flag_ok = !0;
+       return pvr2_issue_simple_cmd(hdw,(onoff ?
+                                         FX2CMD_ONAIR_DTV_POWER_ON :
+                                         FX2CMD_ONAIR_DTV_POWER_OFF));
+}
+
+
+static int pvr2_hdw_cmd_onair_digital_path_ctrl(struct pvr2_hdw *hdw,
+                                               int onoff)
+{
+       return pvr2_issue_simple_cmd(hdw,(onoff ?
+                                         FX2CMD_ONAIR_DTV_STREAMING_ON :
+                                         FX2CMD_ONAIR_DTV_STREAMING_OFF));
+}
+
+
+static void pvr2_hdw_cmd_modeswitch(struct pvr2_hdw *hdw,int digitalFl)
+{
+       int cmode;
+       /* Compare digital/analog desired setting with current setting.  If
+          they don't match, fix it... */
+       cmode = (digitalFl ? PVR2_PATHWAY_DIGITAL : PVR2_PATHWAY_ANALOG);
+       if (cmode == hdw->pathway_state) {
+               /* They match; nothing to do */
+               return;
        }
 
-       pvr2_trace(PVR2_TRACE_INIT,
-                  "Requesting decoder reset");
-       hdw->decoder_ctrl->force_reset(hdw->decoder_ctrl->ctxt);
-       return 0;
+       switch (hdw->hdw_desc->digital_control_scheme) {
+       case PVR2_DIGITAL_SCHEME_HAUPPAUGE:
+               pvr2_hdw_cmd_hcw_demod_reset(hdw,digitalFl);
+               if (cmode == PVR2_PATHWAY_ANALOG) {
+                       /* If moving to analog mode, also force the decoder
+                          to reset.  If no decoder is attached, then it's
+                          ok to ignore this because if/when the decoder
+                          attaches, it will reset itself at that time. */
+                       pvr2_hdw_cmd_decoder_reset(hdw);
+               }
+               break;
+       case PVR2_DIGITAL_SCHEME_ONAIR:
+               /* Supposedly we should always have the power on whether in
+                  digital or analog mode.  But for now do what appears to
+                  work... */
+               pvr2_hdw_cmd_onair_fe_power_ctrl(hdw,digitalFl);
+               break;
+       default: break;
+       }
+
+       pvr2_hdw_untrip_unlocked(hdw);
+       hdw->pathway_state = cmode;
+}
+
+
+static void pvr2_led_ctrl_hauppauge(struct pvr2_hdw *hdw, int onoff)
+{
+       /* change some GPIO data
+        *
+        * note: bit d7 of dir appears to control the LED,
+        * so we shut it off here.
+        *
+        */
+       if (onoff) {
+               pvr2_hdw_gpio_chg_dir(hdw, 0xffffffff, 0x00000481);
+       } else {
+               pvr2_hdw_gpio_chg_dir(hdw, 0xffffffff, 0x00000401);
+       }
+       pvr2_hdw_gpio_chg_out(hdw, 0xffffffff, 0x00000000);
+}
+
+
+typedef void (*led_method_func)(struct pvr2_hdw *,int);
+
+static led_method_func led_methods[] = {
+       [PVR2_LED_SCHEME_HAUPPAUGE] = pvr2_led_ctrl_hauppauge,
+};
+
+
+/* Toggle LED */
+static void pvr2_led_ctrl(struct pvr2_hdw *hdw,int onoff)
+{
+       unsigned int scheme_id;
+       led_method_func fp;
+
+       if ((!onoff) == (!hdw->led_on)) return;
+
+       hdw->led_on = onoff != 0;
+
+       scheme_id = hdw->hdw_desc->led_scheme;
+       if (scheme_id < ARRAY_SIZE(led_methods)) {
+               fp = led_methods[scheme_id];
+       } else {
+               fp = NULL;
+       }
+
+       if (fp) (*fp)(hdw,onoff);
 }
 
 
 /* Stop / start video stream transport */
 static int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl)
 {
-       int status;
-       LOCK_TAKE(hdw->ctl_lock); do {
-               hdw->cmd_buffer[0] =
-                       (runFl ? FX2CMD_STREAMING_ON : FX2CMD_STREAMING_OFF);
-               status = pvr2_send_request(hdw,hdw->cmd_buffer,1,NULL,0);
-       } while (0); LOCK_GIVE(hdw->ctl_lock);
-       return status;
+       int ret;
+
+       /* If we're in analog mode, then just issue the usual analog
+          command. */
+       if (hdw->pathway_state == PVR2_PATHWAY_ANALOG) {
+               return pvr2_issue_simple_cmd(hdw,
+                                            (runFl ?
+                                             FX2CMD_STREAMING_ON :
+                                             FX2CMD_STREAMING_OFF));
+               /*Note: Not reached */
+       }
+
+       if (hdw->pathway_state != PVR2_PATHWAY_DIGITAL) {
+               /* Whoops, we don't know what mode we're in... */
+               return -EINVAL;
+       }
+
+       /* To get here we have to be in digital mode.  The mechanism here
+          is unfortunately different for different vendors.  So we switch
+          on the device's digital scheme attribute in order to figure out
+          what to do. */
+       switch (hdw->hdw_desc->digital_control_scheme) {
+       case PVR2_DIGITAL_SCHEME_HAUPPAUGE:
+               return pvr2_issue_simple_cmd(hdw,
+                                            (runFl ?
+                                             FX2CMD_HCW_DTV_STREAMING_ON :
+                                             FX2CMD_HCW_DTV_STREAMING_OFF));
+       case PVR2_DIGITAL_SCHEME_ONAIR:
+               ret = pvr2_issue_simple_cmd(hdw,
+                                           (runFl ?
+                                            FX2CMD_STREAMING_ON :
+                                            FX2CMD_STREAMING_OFF));
+               if (ret) return ret;
+               return pvr2_hdw_cmd_onair_digital_path_ctrl(hdw,runFl);
+       default:
+               return -EINVAL;
+       }
+}
+
+
+/* Evaluate whether or not state_pathway_ok can change */
+static int state_eval_pathway_ok(struct pvr2_hdw *hdw)
+{
+       if (hdw->state_pathway_ok) {
+               /* Nothing to do if pathway is already ok */
+               return 0;
+       }
+       if (!hdw->state_pipeline_idle) {
+               /* Not allowed to change anything if pipeline is not idle */
+               return 0;
+       }
+       pvr2_hdw_cmd_modeswitch(hdw,hdw->input_val == PVR2_CVAL_INPUT_DTV);
+       hdw->state_pathway_ok = !0;
+       trace_stbit("state_pathway_ok",hdw->state_pathway_ok);
+       return !0;
 }
 
 
@@ -3222,6 +4256,12 @@ static int state_eval_encoder_ok(struct pvr2_hdw *hdw)
        if (hdw->state_encoder_config) return 0;
        if (hdw->state_decoder_run) return 0;
        if (hdw->state_usbstream_run) return 0;
+       if (hdw->pathway_state == PVR2_PATHWAY_DIGITAL) {
+               if (!hdw->hdw_desc->flag_digital_requires_cx23416) return 0;
+       } else if (hdw->pathway_state != PVR2_PATHWAY_ANALOG) {
+               return 0;
+       }
+
        if (pvr2_upload_firmware2(hdw) < 0) {
                hdw->flag_tripped = !0;
                trace_stbit("flag_tripped",hdw->flag_tripped);
@@ -3247,7 +4287,9 @@ static int state_eval_encoder_config(struct pvr2_hdw *hdw)
                /* paranoia - solve race if timer just completed */
                del_timer_sync(&hdw->encoder_wait_timer);
        } else {
-               if (!hdw->state_encoder_ok ||
+               if (!hdw->state_pathway_ok ||
+                   (hdw->pathway_state != PVR2_PATHWAY_ANALOG) ||
+                   !hdw->state_encoder_ok ||
                    !hdw->state_pipeline_idle ||
                    hdw->state_pipeline_pause ||
                    !hdw->state_pipeline_req ||
@@ -3279,7 +4321,9 @@ static int state_eval_encoder_config(struct pvr2_hdw *hdw)
                                   the encoder. */
                                if (!hdw->state_encoder_waitok) {
                                        hdw->encoder_wait_timer.expires =
-                                               jiffies + (HZ*50/1000);
+                                               jiffies +
+                                               (HZ * TIME_MSEC_ENCODER_WAIT
+                                                / 1000);
                                        add_timer(&hdw->encoder_wait_timer);
                                }
                        }
@@ -3296,20 +4340,116 @@ static int state_eval_encoder_config(struct pvr2_hdw *hdw)
 }
 
 
+/* Return true if the encoder should not be running. */
+static int state_check_disable_encoder_run(struct pvr2_hdw *hdw)
+{
+       if (!hdw->state_encoder_ok) {
+               /* Encoder isn't healthy at the moment, so stop it. */
+               return !0;
+       }
+       if (!hdw->state_pathway_ok) {
+               /* Mode is not understood at the moment (i.e. it wants to
+                  change), so encoder must be stopped. */
+               return !0;
+       }
+
+       switch (hdw->pathway_state) {
+       case PVR2_PATHWAY_ANALOG:
+               if (!hdw->state_decoder_run) {
+                       /* We're in analog mode and the decoder is not
+                          running; thus the encoder should be stopped as
+                          well. */
+                       return !0;
+               }
+               break;
+       case PVR2_PATHWAY_DIGITAL:
+               if (hdw->state_encoder_runok) {
+                       /* This is a funny case.  We're in digital mode so
+                          really the encoder should be stopped.  However
+                          if it really is running, only kill it after
+                          runok has been set.  This gives a chance for the
+                          onair quirk to function (encoder must run
+                          briefly first, at least once, before onair
+                          digital streaming can work). */
+                       return !0;
+               }
+               break;
+       default:
+               /* Unknown mode; so encoder should be stopped. */
+               return !0;
+       }
+
+       /* If we get here, we haven't found a reason to stop the
+          encoder. */
+       return 0;
+}
+
+
+/* Return true if the encoder should be running. */
+static int state_check_enable_encoder_run(struct pvr2_hdw *hdw)
+{
+       if (!hdw->state_encoder_ok) {
+               /* Don't run the encoder if it isn't healthy... */
+               return 0;
+       }
+       if (!hdw->state_pathway_ok) {
+               /* Don't run the encoder if we don't (yet) know what mode
+                  we need to be in... */
+               return 0;
+       }
+
+       switch (hdw->pathway_state) {
+       case PVR2_PATHWAY_ANALOG:
+               if (hdw->state_decoder_run) {
+                       /* In analog mode, if the decoder is running, then
+                          run the encoder. */
+                       return !0;
+               }
+               break;
+       case PVR2_PATHWAY_DIGITAL:
+               if ((hdw->hdw_desc->digital_control_scheme ==
+                    PVR2_DIGITAL_SCHEME_ONAIR) &&
+                   !hdw->state_encoder_runok) {
+                       /* This is a quirk.  OnAir hardware won't stream
+                          digital until the encoder has been run at least
+                          once, for a minimal period of time (empiricially
+                          measured to be 1/4 second).  So if we're on
+                          OnAir hardware and the encoder has never been
+                          run at all, then start the encoder.  Normal
+                          state machine logic in the driver will
+                          automatically handle the remaining bits. */
+                       return !0;
+               }
+               break;
+       default:
+               /* For completeness (unknown mode; encoder won't run ever) */
+               break;
+       }
+       /* If we get here, then we haven't found any reason to run the
+          encoder, so don't run it. */
+       return 0;
+}
+
+
 /* Evaluate whether or not state_encoder_run can change */
 static int state_eval_encoder_run(struct pvr2_hdw *hdw)
 {
        if (hdw->state_encoder_run) {
+               if (!state_check_disable_encoder_run(hdw)) return 0;
                if (hdw->state_encoder_ok) {
-                       if (hdw->state_decoder_run) return 0;
+                       del_timer_sync(&hdw->encoder_run_timer);
                        if (pvr2_encoder_stop(hdw) < 0) return !0;
                }
                hdw->state_encoder_run = 0;
        } else {
-               if (!hdw->state_encoder_ok) return 0;
-               if (!hdw->state_decoder_run) return 0;
+               if (!state_check_enable_encoder_run(hdw)) return 0;
                if (pvr2_encoder_start(hdw) < 0) return !0;
                hdw->state_encoder_run = !0;
+               if (!hdw->state_encoder_runok) {
+                       hdw->encoder_run_timer.expires =
+                               jiffies + (HZ * TIME_MSEC_ENCODER_OK / 1000);
+                       add_timer(&hdw->encoder_run_timer);
+               }
        }
        trace_stbit("state_encoder_run",hdw->state_encoder_run);
        return !0;
@@ -3338,13 +4478,27 @@ static void pvr2_hdw_encoder_wait_timeout(unsigned long data)
 }
 
 
+/* Timeout function for encoder run timer. */
+static void pvr2_hdw_encoder_run_timeout(unsigned long data)
+{
+       struct pvr2_hdw *hdw = (struct pvr2_hdw *)data;
+       if (!hdw->state_encoder_runok) {
+               hdw->state_encoder_runok = !0;
+               trace_stbit("state_encoder_runok",hdw->state_encoder_runok);
+               hdw->state_stale = !0;
+               queue_work(hdw->workqueue,&hdw->workpoll);
+       }
+}
+
+
 /* Evaluate whether or not state_decoder_run can change */
 static int state_eval_decoder_run(struct pvr2_hdw *hdw)
 {
        if (hdw->state_decoder_run) {
                if (hdw->state_encoder_ok) {
                        if (hdw->state_pipeline_req &&
-                           !hdw->state_pipeline_pause) return 0;
+                           !hdw->state_pipeline_pause &&
+                           hdw->state_pathway_ok) return 0;
                }
                if (!hdw->flag_decoder_missed) {
                        pvr2_decoder_enable(hdw,0);
@@ -3368,7 +4522,9 @@ static int state_eval_decoder_run(struct pvr2_hdw *hdw)
                                   but before we did the pending check. */
                                if (!hdw->state_decoder_quiescent) {
                                        hdw->quiescent_timer.expires =
-                                               jiffies + (HZ*50/1000);
+                                               jiffies +
+                                               (HZ * TIME_MSEC_DECODER_WAIT
+                                                / 1000);
                                        add_timer(&hdw->quiescent_timer);
                                }
                        }
@@ -3377,7 +4533,9 @@ static int state_eval_decoder_run(struct pvr2_hdw *hdw)
                           hopefully further stabilize the encoder. */
                        return 0;
                }
-               if (!hdw->state_pipeline_req ||
+               if (!hdw->state_pathway_ok ||
+                   (hdw->pathway_state != PVR2_PATHWAY_ANALOG) ||
+                   !hdw->state_pipeline_req ||
                    hdw->state_pipeline_pause ||
                    !hdw->state_pipeline_config ||
                    !hdw->state_encoder_config ||
@@ -3398,16 +4556,43 @@ static int state_eval_decoder_run(struct pvr2_hdw *hdw)
 static int state_eval_usbstream_run(struct pvr2_hdw *hdw)
 {
        if (hdw->state_usbstream_run) {
-               if (hdw->state_encoder_ok) {
-                       if (hdw->state_encoder_run) return 0;
+               int fl = !0;
+               if (hdw->pathway_state == PVR2_PATHWAY_ANALOG) {
+                       fl = (hdw->state_encoder_ok &&
+                             hdw->state_encoder_run);
+               } else if ((hdw->pathway_state == PVR2_PATHWAY_DIGITAL) &&
+                          (hdw->hdw_desc->flag_digital_requires_cx23416)) {
+                       fl = hdw->state_encoder_ok;
+               }
+               if (fl &&
+                   hdw->state_pipeline_req &&
+                   !hdw->state_pipeline_pause &&
+                   hdw->state_pathway_ok) {
+                       return 0;
                }
                pvr2_hdw_cmd_usbstream(hdw,0);
                hdw->state_usbstream_run = 0;
        } else {
-               if (!hdw->state_encoder_ok ||
-                   !hdw->state_encoder_run ||
-                   !hdw->state_pipeline_req ||
-                   hdw->state_pipeline_pause) return 0;
+               if (!hdw->state_pipeline_req ||
+                   hdw->state_pipeline_pause ||
+                   !hdw->state_pathway_ok) return 0;
+               if (hdw->pathway_state == PVR2_PATHWAY_ANALOG) {
+                       if (!hdw->state_encoder_ok ||
+                           !hdw->state_encoder_run) return 0;
+               } else if ((hdw->pathway_state == PVR2_PATHWAY_DIGITAL) &&
+                          (hdw->hdw_desc->flag_digital_requires_cx23416)) {
+                       if (!hdw->state_encoder_ok) return 0;
+                       if (hdw->state_encoder_run) return 0;
+                       if (hdw->hdw_desc->digital_control_scheme ==
+                           PVR2_DIGITAL_SCHEME_ONAIR) {
+                               /* OnAir digital receivers won't stream
+                                  unless the analog encoder has run first.
+                                  Why?  I have no idea.  But don't even
+                                  try until we know the analog side is
+                                  known to have run. */
+                               if (!hdw->state_encoder_runok) return 0;
+                       }
+               }
                if (pvr2_hdw_cmd_usbstream(hdw,!0) < 0) return 0;
                hdw->state_usbstream_run = !0;
        }
@@ -3453,7 +4638,8 @@ static int state_update_pipeline_state(struct pvr2_hdw *hdw)
 typedef int (*state_eval_func)(struct pvr2_hdw *);
 
 /* Set of functions to be run to evaluate various states in the driver. */
-const static state_eval_func eval_funcs[] = {
+static const state_eval_func eval_funcs[] = {
+       state_eval_pathway_ok,
        state_eval_pipeline_config,
        state_eval_encoder_ok,
        state_eval_encoder_config,
@@ -3501,6 +4687,34 @@ static int pvr2_hdw_state_update(struct pvr2_hdw *hdw)
 }
 
 
+static unsigned int print_input_mask(unsigned int msk,
+                                    char *buf,unsigned int acnt)
+{
+       unsigned int idx,ccnt;
+       unsigned int tcnt = 0;
+       for (idx = 0; idx < ARRAY_SIZE(control_values_input); idx++) {
+               if (!((1 << idx) & msk)) continue;
+               ccnt = scnprintf(buf+tcnt,
+                                acnt-tcnt,
+                                "%s%s",
+                                (tcnt ? ", " : ""),
+                                control_values_input[idx]);
+               tcnt += ccnt;
+       }
+       return tcnt;
+}
+
+
+static const char *pvr2_pathway_state_name(int id)
+{
+       switch (id) {
+       case PVR2_PATHWAY_ANALOG: return "analog";
+       case PVR2_PATHWAY_DIGITAL: return "digital";
+       default: return "unknown";
+       }
+}
+
+
 static unsigned int pvr2_hdw_report_unlocked(struct pvr2_hdw *hdw,int which,
                                             char *buf,unsigned int acnt)
 {
@@ -3508,13 +4722,15 @@ static unsigned int pvr2_hdw_report_unlocked(struct pvr2_hdw *hdw,int which,
        case 0:
                return scnprintf(
                        buf,acnt,
-                       "driver:%s%s%s%s%s",
+                       "driver:%s%s%s%s%s <mode=%s>",
                        (hdw->flag_ok ? " <ok>" : " <fail>"),
                        (hdw->flag_init_ok ? " <init>" : " <uninitialized>"),
                        (hdw->flag_disconnected ? " <disconnected>" :
                         " <connected>"),
                        (hdw->flag_tripped ? " <tripped>" : ""),
-                       (hdw->flag_decoder_missed ? " <no decoder>" : ""));
+                       (hdw->flag_decoder_missed ? " <no decoder>" : ""),
+                       pvr2_pathway_state_name(hdw->pathway_state));
+
        case 1:
                return scnprintf(
                        buf,acnt,
@@ -3527,7 +4743,7 @@ static unsigned int pvr2_hdw_report_unlocked(struct pvr2_hdw *hdw,int which,
        case 2:
                return scnprintf(
                        buf,acnt,
-                       "worker:%s%s%s%s%s%s",
+                       "worker:%s%s%s%s%s%s%s",
                        (hdw->state_decoder_run ?
                         " <decode:run>" :
                         (hdw->state_decoder_quiescent ?
@@ -3537,26 +4753,144 @@ static unsigned int pvr2_hdw_report_unlocked(struct pvr2_hdw *hdw,int which,
                        (hdw->state_encoder_ok ?
                         "" : " <encode:init>"),
                        (hdw->state_encoder_run ?
-                        " <encode:run>" : " <encode:stop>"),
+                        (hdw->state_encoder_runok ?
+                         " <encode:run>" :
+                         " <encode:firstrun>") :
+                        (hdw->state_encoder_runok ?
+                         " <encode:stop>" :
+                         " <encode:virgin>")),
                        (hdw->state_encoder_config ?
                         " <encode:configok>" :
                         (hdw->state_encoder_waitok ?
-                         "" : " <encode:wait>")),
+                         "" : " <encode:waitok>")),
                        (hdw->state_usbstream_run ?
-                        " <usb:run>" : " <usb:stop>"));
-               break;
+                        " <usb:run>" : " <usb:stop>"),
+                       (hdw->state_pathway_ok ?
+                        " <pathway:ok>" : ""));
        case 3:
                return scnprintf(
                        buf,acnt,
                        "state: %s",
                        pvr2_get_state_name(hdw->master_state));
-               break;
+       case 4: {
+               unsigned int tcnt = 0;
+               unsigned int ccnt;
+
+               ccnt = scnprintf(buf,
+                                acnt,
+                                "Hardware supported inputs: ");
+               tcnt += ccnt;
+               tcnt += print_input_mask(hdw->input_avail_mask,
+                                        buf+tcnt,
+                                        acnt-tcnt);
+               if (hdw->input_avail_mask != hdw->input_allowed_mask) {
+                       ccnt = scnprintf(buf+tcnt,
+                                        acnt-tcnt,
+                                        "; allowed inputs: ");
+                       tcnt += ccnt;
+                       tcnt += print_input_mask(hdw->input_allowed_mask,
+                                                buf+tcnt,
+                                                acnt-tcnt);
+               }
+               return tcnt;
+       }
+       case 5: {
+               struct pvr2_stream_stats stats;
+               if (!hdw->vid_stream) break;
+               pvr2_stream_get_stats(hdw->vid_stream,
+                                     &stats,
+                                     0);
+               return scnprintf(
+                       buf,acnt,
+                       "Bytes streamed=%u"
+                       " URBs: queued=%u idle=%u ready=%u"
+                       " processed=%u failed=%u",
+                       stats.bytes_processed,
+                       stats.buffers_in_queue,
+                       stats.buffers_in_idle,
+                       stats.buffers_in_ready,
+                       stats.buffers_processed,
+                       stats.buffers_failed);
+       }
        default: break;
        }
        return 0;
 }
 
 
+/* Generate report containing info about attached sub-devices and attached
+   i2c clients, including an indication of which attached i2c clients are
+   actually sub-devices. */
+static unsigned int pvr2_hdw_report_clients(struct pvr2_hdw *hdw,
+                                           char *buf, unsigned int acnt)
+{
+       struct v4l2_subdev *sd;
+       unsigned int tcnt = 0;
+       unsigned int ccnt;
+       struct i2c_client *client;
+       struct list_head *item;
+       void *cd;
+       const char *p;
+       unsigned int id;
+
+       ccnt = scnprintf(buf, acnt, "Associated v4l2-subdev drivers:");
+       tcnt += ccnt;
+       v4l2_device_for_each_subdev(sd, &hdw->v4l2_dev) {
+               id = sd->grp_id;
+               p = NULL;
+               if (id < ARRAY_SIZE(module_names)) p = module_names[id];
+               if (p) {
+                       ccnt = scnprintf(buf + tcnt, acnt - tcnt, " %s", p);
+                       tcnt += ccnt;
+               } else {
+                       ccnt = scnprintf(buf + tcnt, acnt - tcnt,
+                                        " (unknown id=%u)", id);
+                       tcnt += ccnt;
+               }
+       }
+       ccnt = scnprintf(buf + tcnt, acnt - tcnt, "\n");
+       tcnt += ccnt;
+
+       ccnt = scnprintf(buf + tcnt, acnt - tcnt, "I2C clients:\n");
+       tcnt += ccnt;
+
+       mutex_lock(&hdw->i2c_adap.clist_lock);
+       list_for_each(item, &hdw->i2c_adap.clients) {
+               client = list_entry(item, struct i2c_client, list);
+               ccnt = scnprintf(buf + tcnt, acnt - tcnt,
+                                "  %s: i2c=%02x", client->name, client->addr);
+               tcnt += ccnt;
+               cd = i2c_get_clientdata(client);
+               v4l2_device_for_each_subdev(sd, &hdw->v4l2_dev) {
+                       if (cd == sd) {
+                               id = sd->grp_id;
+                               p = NULL;
+                               if (id < ARRAY_SIZE(module_names)) {
+                                       p = module_names[id];
+                               }
+                               if (p) {
+                                       ccnt = scnprintf(buf + tcnt,
+                                                        acnt - tcnt,
+                                                        " subdev=%s", p);
+                                       tcnt += ccnt;
+                               } else {
+                                       ccnt = scnprintf(buf + tcnt,
+                                                        acnt - tcnt,
+                                                        " subdev= id %u)",
+                                                        id);
+                                       tcnt += ccnt;
+                               }
+                               break;
+                       }
+               }
+               ccnt = scnprintf(buf + tcnt, acnt - tcnt, "\n");
+               tcnt += ccnt;
+       }
+       mutex_unlock(&hdw->i2c_adap.clist_lock);
+       return tcnt;
+}
+
+
 unsigned int pvr2_hdw_state_report(struct pvr2_hdw *hdw,
                                   char *buf,unsigned int acnt)
 {
@@ -3571,6 +4905,8 @@ unsigned int pvr2_hdw_state_report(struct pvr2_hdw *hdw,
                buf[0] = '\n'; ccnt = 1;
                bcnt += ccnt; acnt -= ccnt; buf += ccnt;
        }
+       ccnt = pvr2_hdw_report_clients(hdw, buf, acnt);
+       bcnt += ccnt; acnt -= ccnt; buf += ccnt;
        LOCK_GIVE(hdw->big_lock);
        return bcnt;
 }
@@ -3578,14 +4914,25 @@ unsigned int pvr2_hdw_state_report(struct pvr2_hdw *hdw,
 
 static void pvr2_hdw_state_log_state(struct pvr2_hdw *hdw)
 {
-       char buf[128];
-       unsigned int idx,ccnt;
+       char buf[256];
+       unsigned int idx, ccnt;
+       unsigned int lcnt, ucnt;
 
        for (idx = 0; ; idx++) {
                ccnt = pvr2_hdw_report_unlocked(hdw,idx,buf,sizeof(buf));
                if (!ccnt) break;
                printk(KERN_INFO "%s %.*s\n",hdw->name,ccnt,buf);
        }
+       ccnt = pvr2_hdw_report_clients(hdw, buf, sizeof(buf));
+       ucnt = 0;
+       while (ucnt < ccnt) {
+               lcnt = 0;
+               while ((lcnt + ucnt < ccnt) && (buf[lcnt + ucnt] != '\n')) {
+                       lcnt++;
+               }
+               printk(KERN_INFO "%s %.*s\n", hdw->name, lcnt, buf + ucnt);
+               ucnt += lcnt + 1;
+       }
 }
 
 
@@ -3596,6 +4943,7 @@ static int pvr2_hdw_state_eval(struct pvr2_hdw *hdw)
        unsigned int st;
        int state_updated = 0;
        int callback_flag = 0;
+       int analog_mode;
 
        pvr2_trace(PVR2_TRACE_STBITS,
                   "Drive state check START");
@@ -3606,18 +4954,23 @@ static int pvr2_hdw_state_eval(struct pvr2_hdw *hdw)
        /* Process all state and get back over disposition */
        state_updated = pvr2_hdw_state_update(hdw);
 
+       analog_mode = (hdw->pathway_state != PVR2_PATHWAY_DIGITAL);
+
        /* Update master state based upon all other states. */
        if (!hdw->flag_ok) {
                st = PVR2_STATE_DEAD;
        } else if (hdw->fw1_state != FW1_STATE_OK) {
                st = PVR2_STATE_COLD;
-       } else if (!hdw->state_encoder_ok) {
+       } else if ((analog_mode ||
+                   hdw->hdw_desc->flag_digital_requires_cx23416) &&
+                  !hdw->state_encoder_ok) {
                st = PVR2_STATE_WARM;
-       } else if (hdw->flag_tripped || hdw->flag_decoder_missed) {
+       } else if (hdw->flag_tripped ||
+                  (analog_mode && hdw->flag_decoder_missed)) {
                st = PVR2_STATE_ERROR;
-       } else if (hdw->state_encoder_run &&
-                  hdw->state_decoder_run &&
-                  hdw->state_usbstream_run) {
+       } else if (hdw->state_usbstream_run &&
+                  (!analog_mode ||
+                   (hdw->state_encoder_run && hdw->state_decoder_run))) {
                st = PVR2_STATE_RUN;
        } else {
                st = PVR2_STATE_READY;
@@ -3627,6 +4980,7 @@ static int pvr2_hdw_state_eval(struct pvr2_hdw *hdw)
                           "Device state change from %s to %s",
                           pvr2_get_state_name(hdw->master_state),
                           pvr2_get_state_name(st));
+               pvr2_led_ctrl(hdw,st == PVR2_STATE_RUN);
                hdw->master_state = st;
                state_updated = !0;
                callback_flag = !0;
@@ -3656,47 +5010,6 @@ static void pvr2_hdw_state_sched(struct pvr2_hdw *hdw)
 }
 
 
-void pvr2_hdw_get_debug_info_unlocked(const struct pvr2_hdw *hdw,
-                                     struct pvr2_hdw_debug_info *ptr)
-{
-       ptr->big_lock_held = hdw->big_lock_held;
-       ptr->ctl_lock_held = hdw->ctl_lock_held;
-       ptr->flag_disconnected = hdw->flag_disconnected;
-       ptr->flag_init_ok = hdw->flag_init_ok;
-       ptr->flag_ok = hdw->flag_ok;
-       ptr->fw1_state = hdw->fw1_state;
-       ptr->flag_decoder_missed = hdw->flag_decoder_missed;
-       ptr->flag_tripped = hdw->flag_tripped;
-       ptr->state_encoder_ok = hdw->state_encoder_ok;
-       ptr->state_encoder_run = hdw->state_encoder_run;
-       ptr->state_decoder_run = hdw->state_decoder_run;
-       ptr->state_usbstream_run = hdw->state_usbstream_run;
-       ptr->state_decoder_quiescent = hdw->state_decoder_quiescent;
-       ptr->state_pipeline_config = hdw->state_pipeline_config;
-       ptr->state_pipeline_req = hdw->state_pipeline_req;
-       ptr->state_pipeline_pause = hdw->state_pipeline_pause;
-       ptr->state_pipeline_idle = hdw->state_pipeline_idle;
-       ptr->cmd_debug_state = hdw->cmd_debug_state;
-       ptr->cmd_code = hdw->cmd_debug_code;
-       ptr->cmd_debug_write_len = hdw->cmd_debug_write_len;
-       ptr->cmd_debug_read_len = hdw->cmd_debug_read_len;
-       ptr->cmd_debug_timeout = hdw->ctl_timeout_flag;
-       ptr->cmd_debug_write_pend = hdw->ctl_write_pend_flag;
-       ptr->cmd_debug_read_pend = hdw->ctl_read_pend_flag;
-       ptr->cmd_debug_rstatus = hdw->ctl_read_urb->status;
-       ptr->cmd_debug_wstatus = hdw->ctl_read_urb->status;
-}
-
-
-void pvr2_hdw_get_debug_info_locked(struct pvr2_hdw *hdw,
-                                   struct pvr2_hdw_debug_info *ptr)
-{
-       LOCK_TAKE(hdw->ctl_lock); do {
-               pvr2_hdw_get_debug_info_unlocked(hdw,ptr);
-       } while(0); LOCK_GIVE(hdw->ctl_lock);
-}
-
-
 int pvr2_hdw_gpio_get_dir(struct pvr2_hdw *hdw,u32 *dp)
 {
        return pvr2_read_register(hdw,PVR2_GPIO_DIR,dp);
@@ -3756,6 +5069,104 @@ int pvr2_hdw_gpio_chg_out(struct pvr2_hdw *hdw,u32 msk,u32 val)
 }
 
 
+void pvr2_hdw_status_poll(struct pvr2_hdw *hdw)
+{
+       struct v4l2_tuner *vtp = &hdw->tuner_signal_info;
+       memset(vtp, 0, sizeof(*vtp));
+       hdw->tuner_signal_stale = 0;
+       /* Note: There apparently is no replacement for VIDIOC_CROPCAP
+          using v4l2-subdev - therefore we can't support that AT ALL right
+          now.  (Of course, no sub-drivers seem to implement it either.
+          But now it's a a chicken and egg problem...) */
+       v4l2_device_call_all(&hdw->v4l2_dev, 0, tuner, g_tuner,
+                            &hdw->tuner_signal_info);
+       pvr2_trace(PVR2_TRACE_CHIPS, "subdev status poll"
+                  " type=%u strength=%u audio=0x%x cap=0x%x"
+                  " low=%u hi=%u",
+                  vtp->type,
+                  vtp->signal, vtp->rxsubchans, vtp->capability,
+                  vtp->rangelow, vtp->rangehigh);
+
+       /* We have to do this to avoid getting into constant polling if
+          there's nobody to answer a poll of cropcap info. */
+       hdw->cropcap_stale = 0;
+}
+
+
+unsigned int pvr2_hdw_get_input_available(struct pvr2_hdw *hdw)
+{
+       return hdw->input_avail_mask;
+}
+
+
+unsigned int pvr2_hdw_get_input_allowed(struct pvr2_hdw *hdw)
+{
+       return hdw->input_allowed_mask;
+}
+
+
+static int pvr2_hdw_set_input(struct pvr2_hdw *hdw,int v)
+{
+       if (hdw->input_val != v) {
+               hdw->input_val = v;
+               hdw->input_dirty = !0;
+       }
+
+       /* Handle side effects - if we switch to a mode that needs the RF
+          tuner, then select the right frequency choice as well and mark
+          it dirty. */
+       if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
+               hdw->freqSelector = 0;
+               hdw->freqDirty = !0;
+       } else if ((hdw->input_val == PVR2_CVAL_INPUT_TV) ||
+                  (hdw->input_val == PVR2_CVAL_INPUT_DTV)) {
+               hdw->freqSelector = 1;
+               hdw->freqDirty = !0;
+       }
+       return 0;
+}
+
+
+int pvr2_hdw_set_input_allowed(struct pvr2_hdw *hdw,
+                              unsigned int change_mask,
+                              unsigned int change_val)
+{
+       int ret = 0;
+       unsigned int nv,m,idx;
+       LOCK_TAKE(hdw->big_lock);
+       do {
+               nv = hdw->input_allowed_mask & ~change_mask;
+               nv |= (change_val & change_mask);
+               nv &= hdw->input_avail_mask;
+               if (!nv) {
+                       /* No legal modes left; return error instead. */
+                       ret = -EPERM;
+                       break;
+               }
+               hdw->input_allowed_mask = nv;
+               if ((1 << hdw->input_val) & hdw->input_allowed_mask) {
+                       /* Current mode is still in the allowed mask, so
+                          we're done. */
+                       break;
+               }
+               /* Select and switch to a mode that is still in the allowed
+                  mask */
+               if (!hdw->input_allowed_mask) {
+                       /* Nothing legal; give up */
+                       break;
+               }
+               m = hdw->input_allowed_mask;
+               for (idx = 0; idx < (sizeof(m) << 3); idx++) {
+                       if (!((1 << idx) & m)) continue;
+                       pvr2_hdw_set_input(hdw,idx);
+                       break;
+               }
+       } while (0);
+       LOCK_GIVE(hdw->big_lock);
+       return ret;
+}
+
+
 /* Find I2C address of eeprom */
 static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw)
 {
@@ -3773,36 +5184,22 @@ static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw)
 
 
 int pvr2_hdw_register_access(struct pvr2_hdw *hdw,
-                            u32 match_type, u32 match_chip, u64 reg_id,
-                            int setFl,u64 *val_ptr)
+                            struct v4l2_dbg_match *match, u64 reg_id,
+                            int setFl, u64 *val_ptr)
 {
 #ifdef CONFIG_VIDEO_ADV_DEBUG
-       struct pvr2_i2c_client *cp;
-       struct v4l2_register req;
+       struct v4l2_dbg_register req;
        int stat = 0;
        int okFl = 0;
 
        if (!capable(CAP_SYS_ADMIN)) return -EPERM;
 
-       req.match_type = match_type;
-       req.match_chip = match_chip;
+       req.match = *match;
        req.reg = reg_id;
        if (setFl) req.val = *val_ptr;
-       mutex_lock(&hdw->i2c_list_lock); do {
-               list_for_each_entry(cp, &hdw->i2c_clients, list) {
-                       if (!v4l2_chip_match_i2c_client(
-                                   cp->client,
-                                   req.match_type, req.match_chip)) {
-                               continue;
-                       }
-                       stat = pvr2_i2c_client_cmd(
-                               cp,(setFl ? VIDIOC_DBG_S_REGISTER :
-                                   VIDIOC_DBG_G_REGISTER),&req);
-                       if (!setFl) *val_ptr = req.val;
-                       okFl = !0;
-                       break;
-               }
-       } while (0); mutex_unlock(&hdw->i2c_list_lock);
+       /* It would be nice to know if a sub-device answered the request */
+       v4l2_device_call_all(&hdw->v4l2_dev, 0, core, g_register, &req);
+       if (!setFl) *val_ptr = req.val;
        if (okFl) {
                return stat;
        }