提交 681c7399 编写于 作者: M Mike Isely 提交者: Mauro Carvalho Chehab

V4L/DVB (6691): pvrusb2: Rework pipeline state control

This is a new implementation for video pipeline control within the
pvrusb2 driver.  Actual start/stop of the pipeline is moved to the
driver's kernel thread.  Pipeline stages are controlled autonomously
based on surrounding pipeline or application control state.  Kernel
thread management is also cleaned up and moved into the internal
control structure of the driver, solving a set up / tear down race
along the way.  Better failure recovery is implemented with this new
control strategy.  Also with this change comes better control of the
cx23416 encoder, building on additional information learned about the
peculiarities of controlling this part (this information was the
original trigger for this rework).  With this change, overall encoder
stability should be considerably improved.  Yes, this is a large
change for this driver, but due to the nature of the feature being
worked on, the changes are fairly pervasive and would be difficult to
break into smaller pieces with any semblence of step-wise stability.
Signed-off-by: NMike Isely <isely@pobox.com>
Signed-off-by: NMauro Carvalho Chehab <mchehab@infradead.org>
上级 493977f0
......@@ -31,52 +31,32 @@
static void pvr2_context_destroy(struct pvr2_context *mp)
{
if (mp->hdw) pvr2_hdw_destroy(mp->hdw);
pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr_main id=%p",mp);
if (mp->workqueue) {
flush_workqueue(mp->workqueue);
destroy_workqueue(mp->workqueue);
}
if (mp->hdw) pvr2_hdw_destroy(mp->hdw);
kfree(mp);
}
static void pvr2_context_trigger_poll(struct pvr2_context *mp)
{
queue_work(mp->workqueue,&mp->workpoll);
}
static void pvr2_context_poll(struct work_struct *work)
{
struct pvr2_context *mp =
container_of(work, struct pvr2_context, workpoll);
pvr2_context_enter(mp); do {
pvr2_hdw_poll(mp->hdw);
} while (0); pvr2_context_exit(mp);
}
static void pvr2_context_setup(struct work_struct *work)
static void pvr2_context_state_check(struct pvr2_context *mp)
{
struct pvr2_context *mp =
container_of(work, struct pvr2_context, workinit);
if (mp->init_flag) return;
switch (pvr2_hdw_get_state(mp->hdw)) {
case PVR2_STATE_WARM: break;
case PVR2_STATE_ERROR: break;
case PVR2_STATE_READY: break;
case PVR2_STATE_RUN: break;
default: return;
}
pvr2_context_enter(mp); do {
if (!pvr2_hdw_dev_ok(mp->hdw)) break;
pvr2_hdw_setup(mp->hdw);
pvr2_hdw_setup_poll_trigger(
mp->hdw,
(void (*)(void *))pvr2_context_trigger_poll,
mp);
if (!pvr2_hdw_dev_ok(mp->hdw)) break;
if (!pvr2_hdw_init_ok(mp->hdw)) break;
mp->init_flag = !0;
mp->video_stream.stream = pvr2_hdw_get_video_stream(mp->hdw);
if (mp->setup_func) {
mp->setup_func(mp);
}
} while (0); pvr2_context_exit(mp);
}
}
struct pvr2_context *pvr2_context_create(
......@@ -96,11 +76,10 @@ struct pvr2_context *pvr2_context_create(
mp = NULL;
goto done;
}
mp->workqueue = create_singlethread_workqueue("pvrusb2");
INIT_WORK(&mp->workinit, pvr2_context_setup);
INIT_WORK(&mp->workpoll, pvr2_context_poll);
queue_work(mp->workqueue,&mp->workinit);
pvr2_hdw_set_state_callback(mp->hdw,
(void (*)(void *))pvr2_context_state_check,
mp);
pvr2_context_state_check(mp);
done:
return mp;
}
......
......@@ -45,14 +45,11 @@ struct pvr2_context {
struct pvr2_context_stream video_stream;
struct mutex mutex;
int disconnect_flag;
int init_flag;
/* Called after pvr2_context initialization is complete */
void (*setup_func)(struct pvr2_context *);
/* Work queue overhead for out-of-line processing */
struct workqueue_struct *workqueue;
struct work_struct workinit;
struct work_struct workpoll;
};
struct pvr2_channel {
......
......@@ -140,7 +140,7 @@ static const struct pvr2_v4l_cx2584x_ops decoder_ops[] = {
static void decoder_detach(struct pvr2_v4l_cx2584x *ctxt)
{
ctxt->client->handler = NULL;
ctxt->hdw->decoder_ctrl = NULL;
pvr2_hdw_set_decoder(ctxt->hdw,NULL);
kfree(ctxt);
}
......@@ -241,7 +241,7 @@ int pvr2_i2c_cx2584x_v4l_setup(struct pvr2_hdw *hdw,
ctxt->client = cp;
ctxt->hdw = hdw;
ctxt->stale_mask = (1 << ARRAY_SIZE(decoder_ops)) - 1;
hdw->decoder_ctrl = &ctxt->ctrl;
pvr2_hdw_set_decoder(hdw,&ctxt->ctrl);
cp->handler = &ctxt->handler;
{
/*
......
......@@ -34,25 +34,26 @@ extern int pvrusb2_debug;
#define PVR2_TRACE_INIT (1 << 5) /* misc initialization steps */
#define PVR2_TRACE_START_STOP (1 << 6) /* Streaming start / stop */
#define PVR2_TRACE_CTL (1 << 7) /* commit of control changes */
#define PVR2_TRACE_DEBUG (1 << 8) /* Temporary debug code */
#define PVR2_TRACE_EEPROM (1 << 9) /* eeprom parsing / report */
#define PVR2_TRACE_STRUCT (1 << 10) /* internal struct creation */
#define PVR2_TRACE_OPEN_CLOSE (1 << 11) /* application open / close */
#define PVR2_TRACE_CREG (1 << 12) /* Main critical region entry / exit */
#define PVR2_TRACE_SYSFS (1 << 13) /* Sysfs driven I/O */
#define PVR2_TRACE_FIRMWARE (1 << 14) /* firmware upload actions */
#define PVR2_TRACE_CHIPS (1 << 15) /* chip broadcast operation */
#define PVR2_TRACE_I2C (1 << 16) /* I2C related stuff */
#define PVR2_TRACE_I2C_CMD (1 << 17) /* Software commands to I2C modules */
#define PVR2_TRACE_I2C_CORE (1 << 18) /* I2C core debugging */
#define PVR2_TRACE_I2C_TRAF (1 << 19) /* I2C traffic through the adapter */
#define PVR2_TRACE_V4LIOCTL (1 << 20) /* v4l ioctl details */
#define PVR2_TRACE_ENCODER (1 << 21) /* mpeg2 encoder operation */
#define PVR2_TRACE_BUF_POOL (1 << 22) /* Track buffer pool management */
#define PVR2_TRACE_BUF_FLOW (1 << 23) /* Track buffer flow in system */
#define PVR2_TRACE_DATA_FLOW (1 << 24) /* Track data flow */
#define PVR2_TRACE_DEBUGIFC (1 << 25) /* Debug interface actions */
#define PVR2_TRACE_GPIO (1 << 26) /* GPIO state bit changes */
#define PVR2_TRACE_STATE (1 << 8) /* Device state changes */
#define PVR2_TRACE_STBITS (1 << 9) /* Individual bit state changes */
#define PVR2_TRACE_EEPROM (1 << 10) /* eeprom parsing / report */
#define PVR2_TRACE_STRUCT (1 << 11) /* internal struct creation */
#define PVR2_TRACE_OPEN_CLOSE (1 << 12) /* application open / close */
#define PVR2_TRACE_CREG (1 << 13) /* Main critical region entry / exit */
#define PVR2_TRACE_SYSFS (1 << 14) /* Sysfs driven I/O */
#define PVR2_TRACE_FIRMWARE (1 << 15) /* firmware upload actions */
#define PVR2_TRACE_CHIPS (1 << 16) /* chip broadcast operation */
#define PVR2_TRACE_I2C (1 << 17) /* I2C related stuff */
#define PVR2_TRACE_I2C_CMD (1 << 18) /* Software commands to I2C modules */
#define PVR2_TRACE_I2C_CORE (1 << 19) /* I2C core debugging */
#define PVR2_TRACE_I2C_TRAF (1 << 20) /* I2C traffic through the adapter */
#define PVR2_TRACE_V4LIOCTL (1 << 21) /* v4l ioctl details */
#define PVR2_TRACE_ENCODER (1 << 22) /* mpeg2 encoder operation */
#define PVR2_TRACE_BUF_POOL (1 << 23) /* Track buffer pool management */
#define PVR2_TRACE_BUF_FLOW (1 << 24) /* Track buffer flow in system */
#define PVR2_TRACE_DATA_FLOW (1 << 25) /* Track data flow */
#define PVR2_TRACE_DEBUGIFC (1 << 26) /* Debug interface actions */
#define PVR2_TRACE_GPIO (1 << 27) /* GPIO state bit changes */
#endif /* __PVRUSB2_HDW_INTERNAL_H */
......
......@@ -31,14 +31,6 @@ struct debugifc_mask_item {
unsigned long msk;
};
static struct debugifc_mask_item mask_items[] = {
{"ENC_FIRMWARE",(1<<PVR2_SUBSYS_B_ENC_FIRMWARE)},
{"ENC_CFG",(1<<PVR2_SUBSYS_B_ENC_CFG)},
{"DIG_RUN",(1<<PVR2_SUBSYS_B_DIGITIZER_RUN)},
{"USB_RUN",(1<<PVR2_SUBSYS_B_USBSTREAM_RUN)},
{"ENC_RUN",(1<<PVR2_SUBSYS_B_ENC_RUN)},
};
static unsigned int debugifc_count_whitespace(const char *buf,
unsigned int count)
......@@ -148,134 +140,14 @@ static int debugifc_match_keyword(const char *buf,unsigned int count,
}
static unsigned long debugifc_find_mask(const char *buf,unsigned int count)
{
struct debugifc_mask_item *mip;
unsigned int idx;
for (idx = 0; idx < ARRAY_SIZE(mask_items); idx++) {
mip = mask_items + idx;
if (debugifc_match_keyword(buf,count,mip->name)) {
return mip->msk;
}
}
return 0;
}
static int debugifc_print_mask(char *buf,unsigned int sz,
unsigned long msk,unsigned long val)
{
struct debugifc_mask_item *mip;
unsigned int idx;
int bcnt = 0;
int ccnt;
for (idx = 0; idx < ARRAY_SIZE(mask_items); idx++) {
mip = mask_items + idx;
if (!(mip->msk & msk)) continue;
ccnt = scnprintf(buf,sz,"%s%c%s",
(bcnt ? " " : ""),
((mip->msk & val) ? '+' : '-'),
mip->name);
sz -= ccnt;
buf += ccnt;
bcnt += ccnt;
}
return bcnt;
}
static unsigned int debugifc_parse_subsys_mask(const char *buf,
unsigned int count,
unsigned long *mskPtr,
unsigned long *valPtr)
{
const char *wptr;
unsigned int consume_cnt = 0;
unsigned int scnt;
unsigned int wlen;
int mode;
unsigned long m1,msk,val;
msk = 0;
val = 0;
while (count) {
scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
if (!scnt) break;
consume_cnt += scnt; count -= scnt; buf += scnt;
if (!wptr) break;
mode = 0;
if (wlen) switch (wptr[0]) {
case '+':
wptr++;
wlen--;
break;
case '-':
mode = 1;
wptr++;
wlen--;
break;
}
if (!wlen) continue;
m1 = debugifc_find_mask(wptr,wlen);
if (!m1) break;
msk |= m1;
if (!mode) val |= m1;
}
*mskPtr = msk;
*valPtr = val;
return consume_cnt;
}
int pvr2_debugifc_print_info(struct pvr2_hdw *hdw,char *buf,unsigned int acnt)
{
int bcnt = 0;
int ccnt;
struct pvr2_hdw_debug_info dbg;
pvr2_hdw_get_debug_info(hdw,&dbg);
ccnt = scnprintf(buf,acnt,"big lock %s; ctl lock %s",
(dbg.big_lock_held ? "held" : "free"),
(dbg.ctl_lock_held ? "held" : "free"));
bcnt += ccnt; acnt -= ccnt; buf += ccnt;
if (dbg.ctl_lock_held) {
ccnt = scnprintf(buf,acnt,"; cmd_state=%d cmd_code=%d"
" cmd_wlen=%d cmd_rlen=%d"
" wpend=%d rpend=%d tmout=%d rstatus=%d"
" wstatus=%d",
dbg.cmd_debug_state,dbg.cmd_code,
dbg.cmd_debug_write_len,
dbg.cmd_debug_read_len,
dbg.cmd_debug_write_pend,
dbg.cmd_debug_read_pend,
dbg.cmd_debug_timeout,
dbg.cmd_debug_rstatus,
dbg.cmd_debug_wstatus);
bcnt += ccnt; acnt -= ccnt; buf += ccnt;
}
ccnt = scnprintf(buf,acnt,"\n");
bcnt += ccnt; acnt -= ccnt; buf += ccnt;
ccnt = scnprintf(
buf,acnt,"driver flags: %s %s %s\n",
(dbg.flag_init_ok ? "initialized" : "uninitialized"),
(dbg.flag_ok ? "ok" : "fail"),
(dbg.flag_disconnected ? "disconnected" : "connected"));
bcnt += ccnt; acnt -= ccnt; buf += ccnt;
ccnt = scnprintf(buf,acnt,"Subsystems enabled / configured: ");
ccnt = scnprintf(buf,acnt,"Driver state info:\n");
bcnt += ccnt; acnt -= ccnt; buf += ccnt;
ccnt = debugifc_print_mask(buf,acnt,dbg.subsys_flags,dbg.subsys_flags);
ccnt = pvr2_hdw_state_report(hdw,buf,acnt);
bcnt += ccnt; acnt -= ccnt; buf += ccnt;
ccnt = scnprintf(buf,acnt,"\n");
bcnt += ccnt; acnt -= ccnt; buf += ccnt;
ccnt = scnprintf(buf,acnt,"Subsystems disabled / unconfigured: ");
bcnt += ccnt; acnt -= ccnt; buf += ccnt;
ccnt = debugifc_print_mask(buf,acnt,~dbg.subsys_flags,dbg.subsys_flags);
bcnt += ccnt; acnt -= ccnt; buf += ccnt;
ccnt = scnprintf(buf,acnt,"\n");
bcnt += ccnt; acnt -= ccnt; buf += ccnt;
ccnt = scnprintf(buf,acnt,"Attached I2C modules:\n");
bcnt += ccnt; acnt -= ccnt; buf += ccnt;
ccnt = pvr2_i2c_report(hdw,buf,acnt);
......@@ -290,7 +162,6 @@ int pvr2_debugifc_print_status(struct pvr2_hdw *hdw,
{
int bcnt = 0;
int ccnt;
unsigned long msk;
int ret;
u32 gpio_dir,gpio_in,gpio_out;
......@@ -311,28 +182,6 @@ int pvr2_debugifc_print_status(struct pvr2_hdw *hdw,
pvr2_hdw_get_streaming(hdw) ? "on" : "off");
bcnt += ccnt; acnt -= ccnt; buf += ccnt;
msk = pvr2_hdw_subsys_get(hdw);
ccnt = scnprintf(buf,acnt,"Subsystems enabled / configured: ");
bcnt += ccnt; acnt -= ccnt; buf += ccnt;
ccnt = debugifc_print_mask(buf,acnt,msk,msk);
bcnt += ccnt; acnt -= ccnt; buf += ccnt;
ccnt = scnprintf(buf,acnt,"\n");
bcnt += ccnt; acnt -= ccnt; buf += ccnt;
ccnt = scnprintf(buf,acnt,"Subsystems disabled / unconfigured: ");
bcnt += ccnt; acnt -= ccnt; buf += ccnt;
ccnt = debugifc_print_mask(buf,acnt,~msk,msk);
bcnt += ccnt; acnt -= ccnt; buf += ccnt;
ccnt = scnprintf(buf,acnt,"\n");
bcnt += ccnt; acnt -= ccnt; buf += ccnt;
msk = pvr2_hdw_subsys_stream_get(hdw);
ccnt = scnprintf(buf,acnt,"Subsystems stopped on stream shutdown: ");
bcnt += ccnt; acnt -= ccnt; buf += ccnt;
ccnt = debugifc_print_mask(buf,acnt,msk,msk);
bcnt += ccnt; acnt -= ccnt; buf += ccnt;
ccnt = scnprintf(buf,acnt,"\n");
bcnt += ccnt; acnt -= ccnt; buf += ccnt;
return bcnt;
}
......@@ -369,28 +218,10 @@ static int pvr2_debugifc_do1cmd(struct pvr2_hdw *hdw,const char *buf,
return pvr2_upload_firmware2(hdw);
} else if (debugifc_match_keyword(wptr,wlen,"decoder")) {
return pvr2_hdw_cmd_decoder_reset(hdw);
} else if (debugifc_match_keyword(wptr,wlen,"worker")) {
return pvr2_hdw_untrip(hdw);
}
return -EINVAL;
} else if (debugifc_match_keyword(wptr,wlen,"subsys_flags")) {
unsigned long msk = 0;
unsigned long val = 0;
if (debugifc_parse_subsys_mask(buf,count,&msk,&val) != count) {
pvr2_trace(PVR2_TRACE_DEBUGIFC,
"debugifc parse error on subsys mask");
return -EINVAL;
}
pvr2_hdw_subsys_bit_chg(hdw,msk,val);
return 0;
} else if (debugifc_match_keyword(wptr,wlen,"stream_flags")) {
unsigned long msk = 0;
unsigned long val = 0;
if (debugifc_parse_subsys_mask(buf,count,&msk,&val) != count) {
pvr2_trace(PVR2_TRACE_DEBUGIFC,
"debugifc parse error on stream mask");
return -EINVAL;
}
pvr2_hdw_subsys_stream_bit_chg(hdw,msk,val);
return 0;
} else if (debugifc_match_keyword(wptr,wlen,"cpufw")) {
scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
if (!scnt) return -EINVAL;
......
......@@ -209,7 +209,7 @@ static int pvr2_encoder_cmd(void *ctxt,
LOCK_TAKE(hdw->ctl_lock); do {
if (!hdw->flag_encoder_ok) {
if (!hdw->state_encoder_ok) {
ret = -EIO;
break;
}
......@@ -278,7 +278,11 @@ static int pvr2_encoder_cmd(void *ctxt,
ret = -EBUSY;
}
if (ret) {
hdw->flag_encoder_ok = 0;
hdw->state_encoder_ok = 0;
pvr2_trace(PVR2_TRACE_STBITS,
"State bit %s <-- %s",
"state_encoder_ok",
(hdw->state_encoder_ok ? "true" : "false"));
pvr2_trace(
PVR2_TRACE_ERROR_LEGS,
"Giving up on command."
......@@ -394,6 +398,24 @@ static int pvr2_encoder_prep_config(struct pvr2_hdw *hdw)
return ret;
}
int pvr2_encoder_adjust(struct pvr2_hdw *hdw)
{
int ret;
ret = cx2341x_update(hdw,pvr2_encoder_cmd,
(hdw->enc_cur_valid ? &hdw->enc_cur_state : NULL),
&hdw->enc_ctl_state);
if (ret) {
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
"Error from cx2341x module code=%d",ret);
} else {
memcpy(&hdw->enc_cur_state,&hdw->enc_ctl_state,
sizeof(struct cx2341x_mpeg_params));
hdw->enc_cur_valid = !0;
}
return ret;
}
int pvr2_encoder_configure(struct pvr2_hdw *hdw)
{
int ret;
......@@ -436,18 +458,10 @@ int pvr2_encoder_configure(struct pvr2_hdw *hdw)
return ret;
}
ret = cx2341x_update(hdw,pvr2_encoder_cmd,
(hdw->enc_cur_valid ? &hdw->enc_cur_state : NULL),
&hdw->enc_ctl_state);
if (ret) {
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
"Error from cx2341x module code=%d",ret);
return ret;
}
ret = 0;
ret = pvr2_encoder_adjust(hdw);
if (ret) return ret;
if (!ret) ret = pvr2_encoder_vcmd(
ret = pvr2_encoder_vcmd(
hdw, CX2341X_ENC_INITIALIZE_INPUT, 0);
if (ret) {
......@@ -456,10 +470,6 @@ int pvr2_encoder_configure(struct pvr2_hdw *hdw)
return ret;
}
hdw->subsys_enabled_mask |= (1<<PVR2_SUBSYS_B_ENC_CFG);
memcpy(&hdw->enc_cur_state,&hdw->enc_ctl_state,
sizeof(struct cx2341x_mpeg_params));
hdw->enc_cur_valid = !0;
return 0;
}
......@@ -478,7 +488,7 @@ int pvr2_encoder_start(struct pvr2_hdw *hdw)
pvr2_encoder_vcmd(hdw,CX2341X_ENC_MUTE_VIDEO,1,
hdw->input_val == PVR2_CVAL_INPUT_RADIO ? 1 : 0);
switch (hdw->config) {
switch (hdw->active_stream_type) {
case pvr2_config_vbi:
status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,
0x01,0x14);
......@@ -492,9 +502,6 @@ int pvr2_encoder_start(struct pvr2_hdw *hdw)
0,0x13);
break;
}
if (!status) {
hdw->subsys_enabled_mask |= (1<<PVR2_SUBSYS_B_ENC_RUN);
}
return status;
}
......@@ -505,7 +512,7 @@ int pvr2_encoder_stop(struct pvr2_hdw *hdw)
/* mask all interrupts */
pvr2_write_register(hdw, 0x0048, 0xffffffff);
switch (hdw->config) {
switch (hdw->active_stream_type) {
case pvr2_config_vbi:
status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,
0x01,0x01,0x14);
......@@ -526,9 +533,6 @@ int pvr2_encoder_stop(struct pvr2_hdw *hdw)
pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000401);
pvr2_hdw_gpio_chg_out(hdw,0xffffffff,0x00000000);
if (!status) {
hdw->subsys_enabled_mask &= ~(1<<PVR2_SUBSYS_B_ENC_RUN);
}
return status;
}
......
......@@ -25,6 +25,7 @@
struct pvr2_hdw;
int pvr2_encoder_adjust(struct pvr2_hdw *);
int pvr2_encoder_configure(struct pvr2_hdw *);
int pvr2_encoder_start(struct pvr2_hdw *);
int pvr2_encoder_stop(struct pvr2_hdw *);
......
......@@ -35,6 +35,7 @@
#include <linux/videodev2.h>
#include <linux/i2c.h>
#include <linux/workqueue.h>
#include <linux/mutex.h>
#include "pvrusb2-hdw.h"
#include "pvrusb2-io.h"
......@@ -179,6 +180,12 @@ struct pvr2_hdw {
/* Device type, one of PVR2_HDW_TYPE_xxxxx */
unsigned int hdw_type;
/* Kernel worker thread handling */
struct workqueue_struct *workqueue;
struct work_struct workpoll; /* Update driver state */
struct work_struct worki2csync; /* Update i2c clients */
struct work_struct workinit; /* Driver initialization sequence */
/* Video spigot */
struct pvr2_stream *vid_stream;
......@@ -186,9 +193,6 @@ struct pvr2_hdw {
struct mutex big_lock_mutex;
int big_lock_held; /* For debugging */
void (*poll_trigger_func)(void *);
void *poll_trigger_data;
char name[32];
/* I2C stuff */
......@@ -225,14 +229,48 @@ struct pvr2_hdw {
unsigned int cmd_debug_write_len; //
unsigned int cmd_debug_read_len; //
/* Bits of state that describe what is going on with various parts
of the driver. */
volatile int state_encoder_ok; /* Encoder is operational */
volatile int state_encoder_run; /* Encoder is running */
volatile int state_encoder_config; /* Encoder is configured */
volatile int state_encoder_waitok; /* Encoder pre-wait done */
volatile int state_decoder_run; /* Decoder is running */
volatile int state_usbstream_run; /* FX2 is streaming */
volatile int state_decoder_quiescent; /* Decoder idle for > 50msec */
volatile int state_pipeline_config; /* Pipeline is configured */
int state_pipeline_req; /* Somebody wants to stream */
int state_pipeline_pause; /* Pipeline must be paused */
int state_pipeline_idle; /* Pipeline not running */
/* This is the master state of the driver. It is the combined
result of other bits of state. Examining this will indicate the
overall state of the driver. Values here are one of
PVR2_STATE_xxxx */
unsigned int master_state;
/* True if states must be re-evaluated */
int state_stale;
void (*state_func)(void *);
void *state_data;
/* Timer for measuring decoder settling time */
struct timer_list quiescent_timer;
/* Timer for measuring encoder pre-wait time */
struct timer_list encoder_wait_timer;
/* Place to block while waiting for state changes */
wait_queue_head_t state_wait_data;
int flag_ok; /* device in known good state */
int flag_disconnected; /* flag_ok == 0 due to disconnect */
int flag_init_ok; /* true if structure is fully initialized */
int flag_streaming_enabled; /* true if streaming should be on */
int fw1_state; /* current situation with fw1 */
int flag_encoder_ok; /* True if encoder is healthy */
int flag_decoder_is_tuned;
int flag_decoder_missed;/* We've noticed missing decoder */
int flag_tripped; /* Indicates overall failure to start */
struct pvr2_decoder_ctrl *decoder_ctrl;
......@@ -241,12 +279,6 @@ struct pvr2_hdw {
unsigned int fw_size;
int fw_cpu_flag; /* True if we are dealing with the CPU */
// Which subsystem pieces have been enabled / configured
unsigned long subsys_enabled_mask;
// Which subsystems are manipulated to enable streaming
unsigned long subsys_stream_mask;
// True if there is a request to trigger logging of state in each
// module.
int log_requested;
......@@ -296,13 +328,16 @@ struct pvr2_hdw {
/* Location of eeprom or a negative number if none */
int eeprom_addr;
enum pvr2_config config;
enum pvr2_config active_stream_type;
enum pvr2_config desired_stream_type;
/* Control state needed for cx2341x module */
struct cx2341x_mpeg_params enc_cur_state;
struct cx2341x_mpeg_params enc_ctl_state;
/* True if an encoder attribute has changed */
int enc_stale;
/* True if an unsafe encoder attribute has changed */
int enc_unsafe_stale;
/* True if enc_cur_state is valid */
int enc_cur_valid;
......@@ -332,6 +367,7 @@ struct pvr2_hdw {
/* This function gets the current frequency */
unsigned long pvr2_hdw_get_cur_freq(struct pvr2_hdw *);
void pvr2_hdw_set_decoder(struct pvr2_hdw *,struct pvr2_decoder_ctrl *);
#endif /* __PVRUSB2_HDW_INTERNAL_H */
......
......@@ -44,27 +44,6 @@
#define PVR2_CVAL_INPUT_COMPOSITE 2
#define PVR2_CVAL_INPUT_RADIO 3
/* Subsystem definitions - these are various pieces that can be
independently stopped / started. Usually you don't want to mess with
this directly (let the driver handle things itself), but it is useful
for debugging. */
#define PVR2_SUBSYS_B_ENC_FIRMWARE 0
#define PVR2_SUBSYS_B_ENC_CFG 1
#define PVR2_SUBSYS_B_DIGITIZER_RUN 2
#define PVR2_SUBSYS_B_USBSTREAM_RUN 3
#define PVR2_SUBSYS_B_ENC_RUN 4
#define PVR2_SUBSYS_CFG_ALL ( \
(1 << PVR2_SUBSYS_B_ENC_FIRMWARE) | \
(1 << PVR2_SUBSYS_B_ENC_CFG) )
#define PVR2_SUBSYS_RUN_ALL ( \
(1 << PVR2_SUBSYS_B_DIGITIZER_RUN) | \
(1 << PVR2_SUBSYS_B_USBSTREAM_RUN) | \
(1 << PVR2_SUBSYS_B_ENC_RUN) )
#define PVR2_SUBSYS_ALL ( \
PVR2_SUBSYS_CFG_ALL | \
PVR2_SUBSYS_RUN_ALL )
enum pvr2_config {
pvr2_config_empty, /* No configuration */
pvr2_config_mpeg, /* Encoded / compressed video */
......@@ -79,8 +58,41 @@ enum pvr2_v4l_type {
pvr2_v4l_type_radio,
};
/* Major states that we can be in:
*
* DEAD - Device is in an unusable state and cannot be recovered. This
* can happen if we completely lose the ability to communicate with it
* (but it might still on the bus). In this state there's nothing we can
* do; it must be replugged in order to recover.
*
* COLD - Device is in an unusuable state, needs microcontroller firmware.
*
* WARM - We can communicate with the device and the proper
* microcontroller firmware is running, but other device initialization is
* still needed (e.g. encoder firmware).
*
* ERROR - A problem prevents capture operation (e.g. encoder firmware
* missing).
*
* READY - Device is operational, but not streaming.
*
* RUN - Device is streaming.
*
*/
#define PVR2_STATE_NONE 0
#define PVR2_STATE_DEAD 1
#define PVR2_STATE_COLD 2
#define PVR2_STATE_WARM 3
#define PVR2_STATE_ERROR 4
#define PVR2_STATE_READY 5
#define PVR2_STATE_RUN 6
/* Translate configuration enum to a string label */
const char *pvr2_config_get_name(enum pvr2_config);
/* Translate a master state enum to a string label */
const char *pvr2_hdw_get_state_name(unsigned int);
struct pvr2_hdw;
/* Create and return a structure for interacting with the underlying
......@@ -88,28 +100,13 @@ struct pvr2_hdw;
struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
const struct usb_device_id *devid);
/* Poll for background activity (if any) */
void pvr2_hdw_poll(struct pvr2_hdw *);
/* Trigger a poll to take place later at a convenient time */
void pvr2_hdw_poll_trigger_unlocked(struct pvr2_hdw *);
/* Register a callback used to trigger a future poll */
void pvr2_hdw_setup_poll_trigger(struct pvr2_hdw *,
void (*func)(void *),
void *data);
/* Destroy hardware interaction structure */
void pvr2_hdw_destroy(struct pvr2_hdw *);
/* Set up the structure and attempt to put the device into a usable state.
This can be a time-consuming operation, which is why it is not done
internally as part of the create() step. Return value is exactly the
same as pvr2_hdw_init_ok(). */
int pvr2_hdw_setup(struct pvr2_hdw *);
/* Initialization succeeded */
int pvr2_hdw_init_ok(struct pvr2_hdw *);
/* Register a function to be called whenever the master state changes. */
void pvr2_hdw_set_state_callback(struct pvr2_hdw *,
void (*callback_func)(void *),
void *callback_data);
/* Return true if in the ready (normal) state */
int pvr2_hdw_dev_ok(struct pvr2_hdw *);
......@@ -167,6 +164,9 @@ int pvr2_hdw_set_streaming(struct pvr2_hdw *,int);
/* Find out if streaming is on */
int pvr2_hdw_get_streaming(struct pvr2_hdw *);
/* Retrieve driver overall state */
int pvr2_hdw_get_state(struct pvr2_hdw *);
/* Configure the type of stream to generate */
int pvr2_hdw_set_stream_type(struct pvr2_hdw *, enum pvr2_config);
......@@ -177,26 +177,6 @@ struct pvr2_stream *pvr2_hdw_get_video_stream(struct pvr2_hdw *);
int pvr2_hdw_get_stdenum_value(struct pvr2_hdw *hdw,struct v4l2_standard *std,
unsigned int idx);
/* Enable / disable various pieces of hardware. Items to change are
identified by bit positions within msk, and new state for each item is
identified by corresponding bit positions within val. */
void pvr2_hdw_subsys_bit_chg(struct pvr2_hdw *hdw,
unsigned long msk,unsigned long val);
/* Retrieve mask indicating which pieces of hardware are currently enabled
/ configured. */
unsigned long pvr2_hdw_subsys_get(struct pvr2_hdw *);
/* Adjust mask of what get shut down when streaming is stopped. This is a
debugging aid. */
void pvr2_hdw_subsys_stream_bit_chg(struct pvr2_hdw *hdw,
unsigned long msk,unsigned long val);
/* Retrieve mask indicating which pieces of hardware are disabled when
streaming is turned off. */
unsigned long pvr2_hdw_subsys_stream_get(struct pvr2_hdw *);
/* Enable / disable retrieval of CPU firmware or prom contents. This must
be enabled before pvr2_hdw_cpufw_get() will function. Note that doing
this may prevent the device from running (and leaving this mode may
......@@ -253,6 +233,9 @@ void pvr2_hdw_cpureset_assert(struct pvr2_hdw *,int);
/* Execute a USB-commanded device reset */
void pvr2_hdw_device_reset(struct pvr2_hdw *);
/* Reset worker's error trapping circuit breaker */
int pvr2_hdw_untrip(struct pvr2_hdw *);
/* Execute hard reset command (after this point it's likely that the
encoder will have to be reconfigured). This also clears the "useless"
state. */
......@@ -275,11 +258,21 @@ int pvr2_hdw_gpio_chg_out(struct pvr2_hdw *hdw,u32 msk,u32 val);
struct pvr2_hdw_debug_info {
int big_lock_held;
int ctl_lock_held;
int flag_ok;
int flag_disconnected;
int flag_init_ok;
int flag_streaming_enabled;
unsigned long subsys_flags;
int flag_ok;
int fw1_state;
int flag_decoder_missed;
int flag_tripped;
int state_encoder_ok;
int state_encoder_run;
int state_decoder_run;
int state_usbstream_run;
int state_decoder_quiescent;
int state_pipeline_config;
int state_pipeline_req;
int state_pipeline_pause;
int state_pipeline_idle;
int cmd_debug_state;
int cmd_debug_write_len;
int cmd_debug_read_len;
......@@ -295,8 +288,20 @@ struct pvr2_hdw_debug_info {
diagnosing lockups. Note that this operation is completed without any
kind of locking and so it is not atomic and may yield inconsistent
results. This is *purely* a debugging aid. */
void pvr2_hdw_get_debug_info(const struct pvr2_hdw *hdw,
struct pvr2_hdw_debug_info *);
void pvr2_hdw_get_debug_info_unlocked(const struct pvr2_hdw *hdw,
struct pvr2_hdw_debug_info *);
/* Intrusively retrieve internal state info - this is useful for
diagnosing overall driver state. This operation synchronizes against
the overall driver mutex - so if there are locking problems this will
likely hang! This is *purely* a debugging aid. */
void pvr2_hdw_get_debug_info_locked(struct pvr2_hdw *hdw,
struct pvr2_hdw_debug_info *);
/* Report out several lines of text that describes driver internal state.
Results are written into the passed-in buffer. */
unsigned int pvr2_hdw_state_report(struct pvr2_hdw *hdw,
char *buf_ptr,unsigned int buf_size);
/* Cause modules to log their state once */
void pvr2_hdw_trigger_module_log(struct pvr2_hdw *hdw);
......
......@@ -895,7 +895,7 @@ static int pvr2_i2c_attach_inform(struct i2c_client *client)
list_add_tail(&cp->list,&hdw->i2c_clients);
hdw->i2c_pend_types |= PVR2_I2C_PEND_DETECT;
} while (0); mutex_unlock(&hdw->i2c_list_lock);
if (fl) pvr2_hdw_poll_trigger_unlocked(hdw);
if (fl) queue_work(hdw->workqueue,&hdw->worki2csync);
return 0;
}
......
......@@ -1015,10 +1015,8 @@ static int pvr2_v4l2_iosetup(struct pvr2_v4l2_fh *fh)
sp = fh->dev_info->stream->stream;
pvr2_stream_set_callback(sp,(pvr2_stream_callback)pvr2_v4l2_notify,fh);
pvr2_hdw_set_stream_type(hdw,fh->dev_info->config);
pvr2_hdw_set_streaming(hdw,!0);
ret = pvr2_ioread_set_enabled(fh->rhp,!0);
return ret;
if ((ret = pvr2_hdw_set_streaming(hdw,!0)) < 0) return ret;
return pvr2_ioread_set_enabled(fh->rhp,!0);
}
......
......@@ -129,7 +129,7 @@ static const struct pvr2_v4l_decoder_ops decoder_ops[] = {
static void decoder_detach(struct pvr2_v4l_decoder *ctxt)
{
ctxt->client->handler = NULL;
ctxt->hdw->decoder_ctrl = NULL;
pvr2_hdw_set_decoder(ctxt->hdw,NULL);
kfree(ctxt);
}
......@@ -217,7 +217,7 @@ int pvr2_i2c_decoder_v4l_setup(struct pvr2_hdw *hdw,
ctxt->client = cp;
ctxt->hdw = hdw;
ctxt->stale_mask = (1 << ARRAY_SIZE(decoder_ops)) - 1;
hdw->decoder_ctrl = &ctxt->ctrl;
pvr2_hdw_set_decoder(hdw,&ctxt->ctrl);
cp->handler = &ctxt->handler;
pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x saa711x V4L2 handler set up",
cp->client->addr);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册