summaryrefslogtreecommitdiff
path: root/linux/drivers
diff options
context:
space:
mode:
authorMike Isely <isely@pobox.com>2008-02-03 15:40:46 -0600
committerMike Isely <isely@pobox.com>2008-02-03 15:40:46 -0600
commitec2bc3423e5768eb58b32bc15ebbba3d31f42c85 (patch)
treef52a059257e9f2882ad63066953cd01c77edfcc9 /linux/drivers
parentba1027b988b2df2c233e524b09f07d9584177721 (diff)
downloadmediapointer-dvb-s2-ec2bc3423e5768eb58b32bc15ebbba3d31f42c85.tar.gz
mediapointer-dvb-s2-ec2bc3423e5768eb58b32bc15ebbba3d31f42c85.tar.bz2
pvrusb2: Enhance core logic to also control digital streaming
From: Mike Isely <isely@pobox.com> This is a major pvrusb2 change. The driver core has an algorithm that is used to cleanly sequence the changes needed to enable / disable video streaming. The algorithm had originally been written for analog streaming, but when in digital mode the pipeline is considerably different - for example the mpeg encoder is not used. These changes to the core logic implement correct pipeline control when in digital mode. Knowing which pipeline to handle and how to handle it is completely driven by the current input selection. So, in theory, to perform digital stream now all one has to do is switch input to dtv and start streaming as usual. Well, in theory. The reality is that digital tuner and demod control are still not in the driver core yet so until that is present there's nothing to actually stream. Signed-off-by: Mike Isely <isely@pobox.com>
Diffstat (limited to 'linux/drivers')
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h7
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c196
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-hdw.h8
3 files changed, 164 insertions, 47 deletions
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
index 493b78ebf..ae0b13d4e 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
@@ -167,6 +167,11 @@ struct pvr2_decoder_ctrl {
#define FW1_STATE_RELOAD 3
#define FW1_STATE_OK 4
+/* What state the device is in if it is a hybrid */
+#define PVR2_PATHWAY_UNKNOWN 0
+#define PVR2_PATHWAY_ANALOG 1
+#define PVR2_PATHWAY_DIGITAL 2
+
typedef int (*pvr2_i2c_func)(struct pvr2_hdw *,u8,u8 *,u16,u8 *, u16);
#define PVR2_I2C_FUNC_CNT 128
@@ -245,6 +250,7 @@ struct pvr2_hdw {
/* Bits of state that describe what is going on with various parts
of the driver. */
+ int state_pathway_ok; /* Pathway config is ok */
int state_encoder_ok; /* Encoder is operational */
int state_encoder_run; /* Encoder is running */
int state_encoder_config; /* Encoder is configured */
@@ -283,6 +289,7 @@ struct pvr2_hdw {
int flag_disconnected; /* flag_ok == 0 due to disconnect */
int flag_init_ok; /* true if structure is fully initialized */
int fw1_state; /* current situation with fw1 */
+ int pathway_state; /* one of PVR2_PATHWAY_xxx */
int flag_decoder_missed;/* We've noticed missing decoder */
int flag_tripped; /* Indicates overall failure to start */
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c
index 133c874c2..5dffbe4a7 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c
@@ -1871,6 +1871,14 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
if (hdw_desc->flag_has_fmradio) m |= 1 << PVR2_CVAL_INPUT_RADIO;
hdw->input_avail_mask = m;
+ /* 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,
@@ -2400,6 +2408,17 @@ static int pvr2_hdw_commit_execute(struct pvr2_hdw *hdw)
}
}
+ if (hdw->input_dirty &&
+ (((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;
+ }
+ if (!hdw->state_pathway_ok) {
+ /* Can't commit anything until pathway is ok. */
+ return 0;
+ }
/* If any of the below has changed, then we can't do the update
while the pipeline is running. Pipeline must be paused first
and decoder -> encoder connection be made quiescent before we
@@ -2456,9 +2475,11 @@ static int pvr2_hdw_commit_execute(struct pvr2_hdw *hdw)
/* 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;
}
@@ -3337,12 +3358,14 @@ int pvr2_hdw_cmd_decoder_reset(struct pvr2_hdw *hdw)
}
-int pvr2_hdw_cmd_hcw_demod_reset(struct pvr2_hdw *hdw, int onoff)
+static int pvr2_hdw_cmd_hcw_demod_reset(struct pvr2_hdw *hdw, int onoff)
{
int status;
LOCK_TAKE(hdw->ctl_lock); do {
- pvr2_trace(PVR2_TRACE_INIT, "Issuing fe demod wake command");
+ pvr2_trace(PVR2_TRACE_INIT,
+ "Issuing fe demod wake command (%s)",
+ (onoff ? "on" : "off"));
hdw->flag_ok = !0;
hdw->cmd_buffer[0] = FX2CMD_HCW_DEMOD_RESETIN;
hdw->cmd_buffer[1] = onoff;
@@ -3352,24 +3375,15 @@ int pvr2_hdw_cmd_hcw_demod_reset(struct pvr2_hdw *hdw, int onoff)
return status;
}
-int pvr2_hdw_cmd_hcw_usbstream_dvb(struct pvr2_hdw *hdw, int onoff)
-{
- int status;
- LOCK_TAKE(hdw->ctl_lock); do {
- hdw->cmd_buffer[0] =
- (onoff ? FX2CMD_HCW_DTV_STREAMING_ON :
- FX2CMD_HCW_DTV_STREAMING_OFF);
- status = pvr2_send_request(hdw, hdw->cmd_buffer, 1, NULL, 0);
- } while (0); LOCK_GIVE(hdw->ctl_lock);
- return status;
-}
-int pvr2_hdw_cmd_onair_fe_power_ctrl(struct pvr2_hdw *hdw, int onoff)
+static int pvr2_hdw_cmd_onair_fe_power_ctrl(struct pvr2_hdw *hdw, int onoff)
{
int status;
LOCK_TAKE(hdw->ctl_lock); do {
- pvr2_trace(PVR2_TRACE_INIT, "Issuing fe power command to CPLD");
+ pvr2_trace(PVR2_TRACE_INIT,
+ "Issuing fe power command to CPLD (%s)",
+ (onoff ? "on" : "off"));
hdw->flag_ok = !0;
hdw->cmd_buffer[0] =
(onoff ? FX2CMD_ONAIR_DTV_POWER_ON :
@@ -3380,10 +3394,15 @@ int pvr2_hdw_cmd_onair_fe_power_ctrl(struct pvr2_hdw *hdw, int onoff)
return status;
}
-int pvr2_hdw_cmd_onair_digital_path_ctrl(struct pvr2_hdw *hdw, int onoff)
+
+static int pvr2_hdw_cmd_onair_digital_path_ctrl(struct pvr2_hdw *hdw,
+ int onoff)
{
int status;
LOCK_TAKE(hdw->ctl_lock); do {
+ pvr2_trace(PVR2_TRACE_INIT,
+ "Issuing onair digital setup command (%s)",
+ (onoff ? "on" : "off"));
hdw->cmd_buffer[0] =
(onoff ? FX2CMD_ONAIR_DTV_STREAMING_ON :
FX2CMD_ONAIR_DTV_STREAMING_OFF);
@@ -3392,19 +3411,85 @@ int pvr2_hdw_cmd_onair_digital_path_ctrl(struct pvr2_hdw *hdw, int onoff)
return status;
}
+
+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;
+ }
+
+ 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... */
+ if (digitalFl) pvr2_hdw_cmd_onair_fe_power_ctrl(hdw,!0);
+ pvr2_hdw_cmd_onair_digital_path_ctrl(hdw,digitalFl);
+ if (!digitalFl) pvr2_hdw_cmd_onair_fe_power_ctrl(hdw,0);
+ break;
+ default: break;
+ }
+
+ hdw->pathway_state = cmode;
+}
+
+
/* Stop / start video stream transport */
static int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl)
{
- int status;
+ int status,cc;
+ if ((hdw->pathway_state == PVR2_PATHWAY_DIGITAL) &&
+ hdw->hdw_desc->digital_control_scheme ==
+ PVR2_DIGITAL_SCHEME_HAUPPAUGE) {
+ cc = (runFl ?
+ FX2CMD_HCW_DTV_STREAMING_ON :
+ FX2CMD_HCW_DTV_STREAMING_OFF);
+ } else {
+ cc = (runFl ?
+ FX2CMD_STREAMING_ON :
+ FX2CMD_STREAMING_OFF);
+ }
+
LOCK_TAKE(hdw->ctl_lock); do {
- hdw->cmd_buffer[0] =
- (runFl ? FX2CMD_STREAMING_ON : FX2CMD_STREAMING_OFF);
+ hdw->cmd_buffer[0] = cc;
status = pvr2_send_request(hdw,hdw->cmd_buffer,1,NULL,0);
} while (0); LOCK_GIVE(hdw->ctl_lock);
return status;
}
+/* 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;
+ return !0;
+}
+
+
/* Evaluate whether or not state_encoder_ok can change */
static int state_eval_encoder_ok(struct pvr2_hdw *hdw)
{
@@ -3414,6 +3499,7 @@ 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_ANALOG) return 0;
if (pvr2_upload_firmware2(hdw) < 0) {
hdw->flag_tripped = !0;
trace_stbit("flag_tripped",hdw->flag_tripped);
@@ -3439,7 +3525,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 ||
@@ -3493,13 +3581,16 @@ static int state_eval_encoder_run(struct pvr2_hdw *hdw)
{
if (hdw->state_encoder_run) {
if (hdw->state_encoder_ok) {
- if (hdw->state_decoder_run) return 0;
+ if (hdw->state_decoder_run &&
+ hdw->state_pathway_ok) return 0;
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 (!hdw->state_pathway_ok) return 0;
+ if (hdw->pathway_state != PVR2_PATHWAY_ANALOG) return 0;
if (pvr2_encoder_start(hdw) < 0) return !0;
hdw->state_encoder_run = !0;
}
@@ -3536,7 +3627,8 @@ 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);
@@ -3569,7 +3661,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 ||
@@ -3590,16 +3684,25 @@ 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;
+ if (hdw->pathway_state == PVR2_PATHWAY_ANALOG) {
+ if (hdw->state_encoder_ok &&
+ hdw->state_encoder_run &&
+ hdw->state_pathway_ok) return 0;
+ } else {
+ if (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;
+ }
if (pvr2_hdw_cmd_usbstream(hdw,!0) < 0) return 0;
hdw->state_usbstream_run = !0;
}
@@ -3646,6 +3749,7 @@ 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[] = {
+ state_eval_pathway_ok,
state_eval_pipeline_config,
state_eval_encoder_ok,
state_eval_encoder_config,
@@ -3693,6 +3797,16 @@ static int pvr2_hdw_state_update(struct pvr2_hdw *hdw)
}
+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)
{
@@ -3700,13 +3814,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,
@@ -3719,7 +3835,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 ?
@@ -3735,7 +3851,9 @@ static unsigned int pvr2_hdw_report_unlocked(struct pvr2_hdw *hdw,int which,
(hdw->state_encoder_waitok ?
"" : " <encode:wait>")),
(hdw->state_usbstream_run ?
- " <usb:run>" : " <usb:stop>"));
+ " <usb:run>" : " <usb:stop>"),
+ (hdw->state_pathway_ok ?
+ "<pathway:ok>" : ""));
break;
case 3:
return scnprintf(
@@ -3807,9 +3925,9 @@ static int pvr2_hdw_state_eval(struct pvr2_hdw *hdw)
st = PVR2_STATE_WARM;
} else if (hdw->flag_tripped || 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 &&
+ ((hdw->pathway_state != PVR2_PATHWAY_ANALOG) ||
+ (hdw->state_encoder_run && hdw->state_decoder_run))) {
st = PVR2_STATE_RUN;
} else {
st = PVR2_STATE_READY;
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.h
index fd98027ee..8c0abb4e4 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.h
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.h
@@ -264,14 +264,6 @@ int pvr2_hdw_cmd_powerup(struct pvr2_hdw *);
/* suspend */
int pvr2_hdw_cmd_powerdown(struct pvr2_hdw *);
-/* Hauppauge - specific */
-int pvr2_hdw_cmd_hcw_demod_reset(struct pvr2_hdw *hdw, int onoff);
-int pvr2_hdw_cmd_hcw_usbstream_dvb(struct pvr2_hdw *hdw, int onoff);
-
-/* onair - specific */
-int pvr2_hdw_cmd_onair_fe_power_ctrl(struct pvr2_hdw *hdw, int onoff);
-int pvr2_hdw_cmd_onair_digital_path_ctrl(struct pvr2_hdw *hdw, int onoff);
-
/* Order decoder to reset */
int pvr2_hdw_cmd_decoder_reset(struct pvr2_hdw *);