diff options
Diffstat (limited to 'linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c')
-rw-r--r-- | linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c | 690 |
1 files changed, 538 insertions, 152 deletions
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c index 77edc72a2..f78bc351f 100644 --- a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -1,6 +1,5 @@ /* * - * $Id$ * * Copyright (C) 2005 Mike Isely <isely@pobox.com> * @@ -25,7 +24,6 @@ #include <linux/firmware.h> #include <linux/videodev2.h> #include <media/v4l2-common.h> -#include <asm/semaphore.h> #include "pvrusb2.h" #include "pvrusb2-std.h" #include "pvrusb2-util.h" @@ -42,6 +40,23 @@ #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); @@ -69,6 +84,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 @@ -218,6 +243,40 @@ 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_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); @@ -233,6 +292,8 @@ 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, @@ -371,30 +432,12 @@ static int ctrl_get_input(struct pvr2_ctrl *cptr,int *vp) 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) @@ -991,7 +1034,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) { @@ -1213,6 +1256,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*/ @@ -1230,19 +1281,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 */ @@ -1255,7 +1301,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); @@ -1263,7 +1310,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); @@ -1294,23 +1342,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; } @@ -1382,11 +1434,13 @@ int pvr2_hdw_untrip(struct pvr2_hdw *hdw) } +#if 0 const char *pvr2_hdw_get_state_name(unsigned int id) { if (id >= ARRAY_SIZE(pvr2_state_names)) return NULL; return pvr2_state_names[id]; } +#endif /* 0 */ int pvr2_hdw_get_streaming(struct pvr2_hdw *hdw) @@ -1690,10 +1744,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. @@ -1730,6 +1782,13 @@ static void pvr2_hdw_setup_low(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(); @@ -1831,10 +1890,19 @@ int pvr2_hdw_initialize(struct pvr2_hdw *hdw, 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; } @@ -1868,6 +1936,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); @@ -1885,6 +1957,7 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, 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. */ @@ -2075,6 +2148,7 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, 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); @@ -2137,6 +2211,7 @@ void pvr2_hdw_destroy(struct pvr2_hdw *hdw) 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); @@ -2357,7 +2432,7 @@ static int pvr2_hdw_commit_setup(struct pvr2_hdw *hdw) for (idx = 0; idx < hdw->control_cnt; idx++) { cptr = hdw->controls + idx; - if (cptr->info->is_dirty == 0) continue; + if (!cptr->info->is_dirty) continue; if (!cptr->info->is_dirty(cptr)) continue; commit_flag = !0; @@ -2419,7 +2494,7 @@ static int pvr2_hdw_commit_execute(struct pvr2_hdw *hdw) } } - if (hdw->input_dirty && + if (hdw->input_dirty && hdw->state_pathway_ok && (((hdw->input_val == PVR2_CVAL_INPUT_DTV) ? PVR2_PATHWAY_DIGITAL : PVR2_PATHWAY_ANALOG) != hdw->pathway_state)) { @@ -2484,6 +2559,20 @@ static int pvr2_hdw_commit_execute(struct pvr2_hdw *hdw) 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); @@ -2706,7 +2795,7 @@ void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *hdw, u16 address; unsigned int pipe; LOCK_TAKE(hdw->big_lock); do { - if ((hdw->fw_buffer == 0) == !enable_flag) break; + if ((hdw->fw_buffer == NULL) == !enable_flag) break; if (!enable_flag) { pvr2_trace(PVR2_TRACE_FIRMWARE, @@ -2775,7 +2864,7 @@ void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *hdw, /* Return true if we're in a mode for retrieval CPU firmware */ int pvr2_hdw_cpufw_get_enabled(struct pvr2_hdw *hdw) { - return hdw->fw_buffer != 0; + return hdw->fw_buffer != NULL; } @@ -3185,6 +3274,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; @@ -3292,40 +3442,19 @@ 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); } -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); } @@ -3352,55 +3481,29 @@ int pvr2_hdw_cmd_decoder_reset(struct pvr2_hdw *hdw) 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)); } @@ -3430,9 +3533,7 @@ static void pvr2_hdw_cmd_modeswitch(struct pvr2_hdw *hdw,int digitalFl) /* 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; } @@ -3442,7 +3543,7 @@ static void pvr2_hdw_cmd_modeswitch(struct pvr2_hdw *hdw,int digitalFl) } -void pvr2_led_ctrl_hauppauge(struct pvr2_hdw *hdw, int onoff) +static void pvr2_led_ctrl_hauppauge(struct pvr2_hdw *hdw, int onoff) { /* change some GPIO data * @@ -3490,24 +3591,43 @@ static void pvr2_led_ctrl(struct pvr2_hdw *hdw,int onoff) /* 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; + } } @@ -3538,7 +3658,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_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); @@ -3598,7 +3723,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); } } @@ -3615,23 +3742,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 && - 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 * TIME_MSEC_ENCODER_OK / 1000); + add_timer(&hdw->encoder_run_timer); + } } trace_stbit("state_encoder_run",hdw->state_encoder_run); return !0; @@ -3660,6 +3880,19 @@ 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) { @@ -3691,7 +3924,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); } } @@ -3723,14 +3958,19 @@ 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; @@ -3741,6 +3981,19 @@ static int state_eval_usbstream_run(struct pvr2_hdw *hdw) 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; @@ -3836,6 +4089,24 @@ 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) { @@ -3884,22 +4155,65 @@ 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>"), (hdw->state_pathway_ok ? " <pathway:ok>" : "")); - break; 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; @@ -3963,7 +4277,9 @@ static int pvr2_hdw_state_eval(struct pvr2_hdw *hdw) 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)) { @@ -4009,6 +4325,7 @@ static void pvr2_hdw_state_sched(struct pvr2_hdw *hdw) queue_work(hdw->workqueue,&hdw->workpoll); } +#if 0 void pvr2_hdw_get_debug_info_unlocked(const struct pvr2_hdw *hdw, struct pvr2_hdw_debug_info *ptr) @@ -4050,6 +4367,7 @@ void pvr2_hdw_get_debug_info_locked(struct pvr2_hdw *hdw, } while(0); LOCK_GIVE(hdw->ctl_lock); } +#endif /* 0 */ int pvr2_hdw_gpio_get_dir(struct pvr2_hdw *hdw,u32 *dp) { @@ -4116,6 +4434,74 @@ unsigned int pvr2_hdw_get_input_available(struct pvr2_hdw *hdw) } +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) { |