};
+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_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_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,
static int ctrl_check_input(struct pvr2_ctrl *cptr,int v)
{
- return ((1 << v) & cptr->hdw->input_avail_mask) != 0;
+ return ((1 << v) & cptr->hdw->input_allowed_mask) != 0;
}
static int ctrl_set_input(struct pvr2_ctrl *cptr,int m,int v)
{
- struct pvr2_hdw *hdw = cptr->hdw;
-
- 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;
+ return pvr2_hdw_set_input(cptr->hdw,v);
}
static int ctrl_isdirty_input(struct pvr2_ctrl *cptr)
/* 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) {
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*/
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 */
" 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);
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);
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;
}
}
-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)
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();
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);
- pvr2_hdw_setup(hdw);
return hdw->flag_init_ok;
}
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);
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. */
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);
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->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);
+ }
+ }
+
/* Now execute i2c core update */
pvr2_i2c_core_sync(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;
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);
}
-static int pvr2_hdw_cmd_power_ctrl(struct pvr2_hdw *hdw, int onoff)
-{
- int status;
- LOCK_TAKE(hdw->ctl_lock); do {
- if (onoff) {
- pvr2_trace(PVR2_TRACE_INIT, "Requesting powerup");
- hdw->cmd_buffer[0] = FX2CMD_POWER_ON;
- } else {
- pvr2_trace(PVR2_TRACE_INIT, "Requesting powerdown");
- hdw->cmd_buffer[0] = FX2CMD_POWER_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_powerup(struct pvr2_hdw *hdw)
{
- return pvr2_hdw_cmd_power_ctrl(hdw, 1);
+ return pvr2_issue_simple_cmd(hdw,FX2CMD_POWER_ON);
}
+
int pvr2_hdw_cmd_powerdown(struct pvr2_hdw *hdw)
{
- return pvr2_hdw_cmd_power_ctrl(hdw, 0);
+ return pvr2_issue_simple_cmd(hdw,FX2CMD_POWER_OFF);
}
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 (%s)",
- (onoff ? "on" : "off"));
- hdw->flag_ok = !0;
- hdw->cmd_buffer[0] = FX2CMD_HCW_DEMOD_RESETIN;
- hdw->cmd_buffer[1] = onoff;
- status = pvr2_send_request(hdw, hdw->cmd_buffer, 2, NULL, 0);
- } while (0); LOCK_GIVE(hdw->ctl_lock);
-
- return status;
+ 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)
{
- int status;
-
- LOCK_TAKE(hdw->ctl_lock); do {
- 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 :
- FX2CMD_ONAIR_DTV_POWER_OFF);
- status = pvr2_send_request(hdw, hdw->cmd_buffer, 1, NULL, 0);
- } while (0); LOCK_GIVE(hdw->ctl_lock);
-
- return status;
+ 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)
{
- 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);
- 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,(onoff ?
+ FX2CMD_ONAIR_DTV_STREAMING_ON :
+ FX2CMD_ONAIR_DTV_STREAMING_OFF));
}
/* 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);
+ pvr2_hdw_cmd_onair_fe_power_ctrl(hdw,digitalFl);
break;
default: break;
}
/* Stop / start video stream transport */
static int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl)
{
- 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);
+ 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 */
}
- LOCK_TAKE(hdw->ctl_lock); do {
- 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;
+ 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;
+ }
}
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 (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);
}
+/* 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 &&
- hdw->state_pathway_ok) 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 (!hdw->state_pathway_ok) return 0;
- if (hdw->pathway_state != PVR2_PATHWAY_ANALOG) 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*250/1000);
+ add_timer(&hdw->encoder_run_timer);
+ }
}
trace_stbit("state_encoder_run",hdw->state_encoder_run);
return !0;
}
+/* 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)
{
static int state_eval_usbstream_run(struct pvr2_hdw *hdw)
{
if (hdw->state_usbstream_run) {
+ int fl = !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;
+ 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;
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;
}
+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) {
(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 ?
buf,acnt,
"state: %s",
pvr2_get_state_name(hdw->master_state));
+ 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;
st = PVR2_STATE_DEAD;
} else if (hdw->fw1_state != FW1_STATE_OK) {
st = PVR2_STATE_COLD;
- } else if (analog_mode && !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 ||
(analog_mode && hdw->flag_decoder_missed)) {
}
-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);
}
+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)
{