#include "pvrusb2-util.h"
#include "pvrusb2-hdw.h"
#include "pvrusb2-i2c-core.h"
-#include "pvrusb2-i2c-track.h"
-#include "pvrusb2-tuner.h"
#include "pvrusb2-eeprom.h"
#include "pvrusb2-hdw-internal.h"
#include "pvrusb2-encoder.h"
#include "pvrusb2-wm8775.h"
#include "pvrusb2-video-v4l.h"
#include "pvrusb2-cx2584x-v4l.h"
+#include "pvrusb2-cs53l32a.h"
#include "pvrusb2-audio.h"
#define TV_MIN_FREQ 55250000L
[PVR2_CLIENT_ID_SAA7115] = pvr2_saa7115_subdev_update,
[PVR2_CLIENT_ID_MSP3400] = pvr2_msp3400_subdev_update,
[PVR2_CLIENT_ID_CX25840] = pvr2_cx25840_subdev_update,
+ [PVR2_CLIENT_ID_CS53L32A] = pvr2_cs53l32a_subdev_update,
};
static const char *module_names[] = {
[PVR2_CLIENT_ID_CX25840] = "cx25840",
[PVR2_CLIENT_ID_SAA7115] = "saa7115",
[PVR2_CLIENT_ID_TUNER] = "tuner",
- [PVR2_CLIENT_ID_CS53132A] = "cs53132a",
+ [PVR2_CLIENT_ID_DEMOD] = "tuner",
+ [PVR2_CLIENT_ID_CS53L32A] = "cs53l32a",
[PVR2_CLIENT_ID_WM8775] = "wm8775",
};
static const unsigned char *module_i2c_addresses[] = {
[PVR2_CLIENT_ID_TUNER] = "\x60\x61\x62\x63",
+ [PVR2_CLIENT_ID_DEMOD] = "\x43",
+ [PVR2_CLIENT_ID_MSP3400] = "\x40",
+ [PVR2_CLIENT_ID_SAA7115] = "\x21",
[PVR2_CLIENT_ID_WM8775] = "\x1b",
[PVR2_CLIENT_ID_CX25840] = "\x44",
+ [PVR2_CLIENT_ID_CS53L32A] = "\x11",
};
static void pvr2_hdw_state_sched(struct pvr2_hdw *);
static int pvr2_hdw_state_eval(struct pvr2_hdw *);
static void pvr2_hdw_set_cur_freq(struct pvr2_hdw *,unsigned long);
-static void pvr2_hdw_worker_i2c(struct work_struct *work);
static void pvr2_hdw_worker_poll(struct work_struct *work);
static int pvr2_hdw_wait(struct pvr2_hdw *,int state);
static int pvr2_hdw_untrip_unlocked(struct pvr2_hdw *);
static int pvr2_decoder_enable(struct pvr2_hdw *hdw,int enablefl)
{
- if (hdw->decoder_ctrl) {
- hdw->decoder_ctrl->enable(hdw->decoder_ctrl->ctxt, enablefl);
- return 0;
- }
/* Even though we really only care about the video decoder chip at
this point, we'll broadcast stream on/off to all sub-devices
anyway, just in case somebody else wants to hear the
command... */
+ pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 stream=%s",
+ (enablefl ? "on" : "off"));
v4l2_device_call_all(&hdw->v4l2_dev, 0, video, s_stream, enablefl);
if (hdw->decoder_client_id) {
/* We get here if the encoder has been noticed. Otherwise
}
-void pvr2_hdw_set_decoder(struct pvr2_hdw *hdw,struct pvr2_decoder_ctrl *ptr)
-{
- if (hdw->decoder_ctrl == ptr) return;
- hdw->decoder_ctrl = ptr;
- if (hdw->decoder_ctrl && hdw->flag_decoder_missed) {
- hdw->flag_decoder_missed = 0;
- trace_stbit("flag_decoder_missed",
- hdw->flag_decoder_missed);
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "Decoder has appeared");
- pvr2_hdw_state_sched(hdw);
- }
-}
-
-
int pvr2_hdw_get_state(struct pvr2_hdw *hdw)
{
return hdw->master_state;
* and every other place where I can find examples of this, the
* "chipid" appears to just be the module name again. So here we
* just do the same thing. */
- hdw->i2c_adap.class = 0;
if (i2ccnt == 1) {
pvr2_trace(PVR2_TRACE_INIT,
"Module ID %u:"
" Setting up with specified i2c address 0x%x",
mid, i2caddr[0]);
- sd = v4l2_i2c_new_subdev(&hdw->i2c_adap,
+ sd = v4l2_i2c_new_subdev(&hdw->v4l2_dev, &hdw->i2c_adap,
fname, fname,
i2caddr[0]);
} else {
"Module ID %u:"
" Setting up with address probe list",
mid);
- sd = v4l2_i2c_new_probed_subdev(&hdw->i2c_adap,
+ sd = v4l2_i2c_new_probed_subdev(&hdw->v4l2_dev, &hdw->i2c_adap,
fname, fname,
i2caddr);
}
- hdw->i2c_adap.class = I2C_CLASS_TV_ANALOG;
if (!sd) {
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
requires special handling. */
sd->grp_id = mid;
- /* If we have both old and new i2c layers enabled, make sure that
- old layer isn't also tracking this module. This is a debugging
- aid, in normal situations there's no reason for both mechanisms
- to be enabled. */
- pvr2_i2c_untrack_subdev(hdw, sd);
pvr2_trace(PVR2_TRACE_INFO, "Attached sub-driver %s", fname);
if (!pvr2_hdw_dev_ok(hdw)) return;
+ hdw->force_dirty = !0;
+
if (!hdw->hdw_desc->flag_no_powerup) {
pvr2_hdw_cmd_powerup(hdw);
if (!pvr2_hdw_dev_ok(hdw)) return;
}
// This step MUST happen after the earlier powerup step.
- pvr2_i2c_track_init(hdw);
pvr2_i2c_core_init(hdw);
if (!pvr2_hdw_dev_ok(hdw)) return;
pvr2_hdw_load_modules(hdw);
if (!pvr2_hdw_dev_ok(hdw)) return;
+ v4l2_device_call_all(&hdw->v4l2_dev, 0, core, load_fw);
+
for (idx = 0; idx < CTRLDEF_COUNT; idx++) {
cptr = hdw->controls + idx;
if (cptr->info->skip_init) continue;
hdw->tuner_type);
}
- pvr2_i2c_core_check_stale(hdw);
if (!pvr2_hdw_dev_ok(hdw)) return;
hdw->ctl_read_urb = usb_alloc_urb(0,GFP_KERNEL);
if (!hdw->ctl_read_urb) goto fail;
- if (v4l2_device_register(&usb_dev->dev, &hdw->v4l2_dev) != 0) {
+ if (v4l2_device_register(&intf->dev, &hdw->v4l2_dev) != 0) {
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
"Error registering with v4l core, giving up");
goto fail;
hdw->workqueue = create_singlethread_workqueue(hdw->name);
INIT_WORK(&hdw->workpoll,pvr2_hdw_worker_poll);
- INIT_WORK(&hdw->worki2csync,pvr2_hdw_worker_i2c);
pvr2_trace(PVR2_TRACE_INIT,"Driver unit number is %d, name is %s",
hdw->unit_number,hdw->name);
/* If we don't do this, then there will be a dangling struct device
reference to our disappearing device persisting inside the V4L
core... */
- if (hdw->v4l2_dev.dev) {
- dev_set_drvdata(hdw->v4l2_dev.dev, NULL);
- hdw->v4l2_dev.dev = NULL;
- }
+ v4l2_device_disconnect(&hdw->v4l2_dev);
hdw->usb_dev = NULL;
hdw->usb_intf = NULL;
pvr2_hdw_render_useless(hdw);
pvr2_stream_destroy(hdw->vid_stream);
hdw->vid_stream = NULL;
}
- if (hdw->decoder_ctrl) {
- hdw->decoder_ctrl->detach(hdw->decoder_ctrl->ctxt);
- }
pvr2_i2c_core_done(hdw);
- pvr2_i2c_track_done(hdw);
v4l2_device_unregister(&hdw->v4l2_dev);
pvr2_hdw_remove_usb_stuff(hdw);
mutex_lock(&pvr2_unit_mtx); do {
}
#define PVR2_SUBDEV_SET_CONTROL(hdw, id, lab) \
- if ((hdw)->lab##_dirty) { \
+ if ((hdw)->lab##_dirty || (hdw)->force_dirty) { \
pvr2_subdev_set_control(hdw, id, #lab, (hdw)->lab##_val); \
}
pvr2_trace(PVR2_TRACE_CHIPS, "subdev update...");
- if (hdw->tuner_updated) {
+ if (hdw->tuner_updated || hdw->force_dirty) {
struct tuner_setup setup;
pvr2_trace(PVR2_TRACE_CHIPS, "subdev tuner set_type(%d)",
hdw->tuner_type);
if (((int)(hdw->tuner_type)) >= 0) {
+ memset(&setup, 0, sizeof(setup));
setup.addr = ADDR_UNSET;
setup.type = hdw->tuner_type;
setup.mode_mask = T_RADIO | T_ANALOG_TV;
}
}
- if (hdw->input_dirty || hdw->std_dirty) {
+ if (hdw->input_dirty || hdw->std_dirty || hdw->force_dirty) {
pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 set_standard");
if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
v4l2_device_call_all(&hdw->v4l2_dev, 0,
v4l2_std_id vs;
vs = hdw->std_mask_cur;
v4l2_device_call_all(&hdw->v4l2_dev, 0,
- tuner, s_std, vs);
+ core, s_std, vs);
}
hdw->tuner_signal_stale = !0;
hdw->cropcap_stale = !0;
PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_AUDIO_BASS, bass);
PVR2_SUBDEV_SET_CONTROL(hdw, V4L2_CID_AUDIO_TREBLE, treble);
- if (hdw->input_dirty || hdw->audiomode_dirty) {
+ if (hdw->input_dirty || hdw->audiomode_dirty || hdw->force_dirty) {
struct v4l2_tuner vt;
memset(&vt, 0, sizeof(vt));
vt.audmode = hdw->audiomode_val;
v4l2_device_call_all(&hdw->v4l2_dev, 0, tuner, s_tuner, &vt);
}
- if (hdw->freqDirty) {
+ if (hdw->freqDirty || hdw->force_dirty) {
unsigned long fv;
struct v4l2_frequency freq;
fv = pvr2_hdw_get_cur_freq(hdw);
s_frequency, &freq);
}
- if (hdw->res_hor_dirty || hdw->res_ver_dirty) {
+ if (hdw->res_hor_dirty || hdw->res_ver_dirty || hdw->force_dirty) {
struct v4l2_format fmt;
memset(&fmt, 0, sizeof(fmt));
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width = hdw->res_hor_val;
fmt.fmt.pix.height = hdw->res_ver_val;
- pvr2_trace(PVR2_TRACE_CHIPS,"subdev v4l2 set_size(%dx%d)",
+ pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 set_size(%dx%d)",
fmt.fmt.pix.width, fmt.fmt.pix.height);
v4l2_device_call_all(&hdw->v4l2_dev, 0, video, s_fmt, &fmt);
}
- if (hdw->srate_dirty) {
+ if (hdw->srate_dirty || hdw->force_dirty) {
u32 val;
pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 set_audio %d",
hdw->srate_val);
(*fp)(hdw, sd);
}
- if (hdw->tuner_signal_stale && hdw->cropcap_stale) {
+ if (hdw->tuner_signal_stale || hdw->cropcap_stale) {
pvr2_hdw_status_poll(hdw);
}
}
unsigned int idx;
struct pvr2_ctrl *cptr;
int value;
- int commit_flag = 0;
+ int commit_flag = hdw->force_dirty;
char buf[100];
unsigned int bcnt,ccnt;
cx2341x_ext_ctrls(&hdw->enc_ctl_state, 0, &cs,VIDIOC_S_EXT_CTRLS);
}
- /* Scan i2c core at this point - before we clear all the dirty
- bits. Various parts of the i2c core will notice dirty bits as
- appropriate and arrange to broadcast or directly send updates to
- the client drivers in order to keep everything in sync */
- pvr2_i2c_core_check_stale(hdw);
-
if (hdw->active_stream_type != hdw->desired_stream_type) {
/* Handle any side effects of stream config here */
hdw->active_stream_type = hdw->desired_stream_type;
pvr2_subdev_update(hdw);
hdw->tuner_updated = 0;
+ hdw->force_dirty = 0;
for (idx = 0; idx < hdw->control_cnt; idx++) {
cptr = hdw->controls + idx;
if (!cptr->info->clear_dirty) continue;
cptr->info->clear_dirty(cptr);
}
- /* Now execute i2c core update */
- pvr2_i2c_core_sync(hdw);
-
if ((hdw->pathway_state == PVR2_PATHWAY_ANALOG) &&
hdw->state_encoder_run) {
/* If encoder isn't running or it can't be touched, then
}
-static void pvr2_hdw_worker_i2c(struct work_struct *work)
-{
- struct pvr2_hdw *hdw = container_of(work,struct pvr2_hdw,worki2csync);
- LOCK_TAKE(hdw->big_lock); do {
- pvr2_i2c_core_sync(hdw);
- } while (0); LOCK_GIVE(hdw->big_lock);
-}
-
-
static void pvr2_hdw_worker_poll(struct work_struct *work)
{
int fl = 0;
int nr = pvr2_hdw_get_unit_number(hdw);
LOCK_TAKE(hdw->big_lock); do {
printk(KERN_INFO "pvrusb2: ================= START STATUS CARD #%d =================\n", nr);
- hdw->log_requested = !0;
- pvr2_i2c_core_check_stale(hdw);
- pvr2_i2c_core_sync(hdw);
- hdw->log_requested = 0;
v4l2_device_call_all(&hdw->v4l2_dev, 0, core, log_status);
pvr2_trace(PVR2_TRACE_INFO,"cx2341x config:");
cx2341x_log_status(&hdw->enc_ctl_state, "pvrusb2");
{
pvr2_trace(PVR2_TRACE_INIT,
"Requesting decoder reset");
- if (hdw->decoder_ctrl) {
- if (!hdw->decoder_ctrl->force_reset) {
- pvr2_trace(PVR2_TRACE_INIT,
- "Unable to reset decoder: not implemented");
- return -ENOTTY;
- }
- hdw->decoder_ctrl->force_reset(hdw->decoder_ctrl->ctxt);
- return 0;
- } else {
- }
if (hdw->decoder_client_id) {
v4l2_device_call_all(&hdw->v4l2_dev, hdw->decoder_client_id,
core, reset, 0);
stats.buffers_processed,
stats.buffers_failed);
}
- case 6: {
- struct v4l2_subdev *sd;
- unsigned int tcnt = 0;
- unsigned int ccnt;
- const char *p;
- unsigned int id;
- ccnt = scnprintf(buf,
- acnt,
- "Associated v4l2_subdev drivers:");
+ default: break;
+ }
+ return 0;
+}
+
+
+/* Generate report containing info about attached sub-devices and attached
+ i2c clients, including an indication of which attached i2c clients are
+ actually sub-devices. */
+static unsigned int pvr2_hdw_report_clients(struct pvr2_hdw *hdw,
+ char *buf, unsigned int acnt)
+{
+ struct v4l2_subdev *sd;
+ unsigned int tcnt = 0;
+ unsigned int ccnt;
+ struct i2c_client *client;
+ struct list_head *item;
+ void *cd;
+ const char *p;
+ unsigned int id;
+
+ ccnt = scnprintf(buf, acnt, "Associated v4l2-subdev drivers:");
+ tcnt += ccnt;
+ v4l2_device_for_each_subdev(sd, &hdw->v4l2_dev) {
+ id = sd->grp_id;
+ p = NULL;
+ if (id < ARRAY_SIZE(module_names)) p = module_names[id];
+ if (p) {
+ ccnt = scnprintf(buf + tcnt, acnt - tcnt, " %s", p);
+ tcnt += ccnt;
+ } else {
+ ccnt = scnprintf(buf + tcnt, acnt - tcnt,
+ " (unknown id=%u)", id);
+ tcnt += ccnt;
+ }
+ }
+ ccnt = scnprintf(buf + tcnt, acnt - tcnt, "\n");
+ tcnt += ccnt;
+
+ ccnt = scnprintf(buf + tcnt, acnt - tcnt, "I2C clients:\n");
+ tcnt += ccnt;
+
+ mutex_lock(&hdw->i2c_adap.clist_lock);
+ list_for_each(item, &hdw->i2c_adap.clients) {
+ client = list_entry(item, struct i2c_client, list);
+ ccnt = scnprintf(buf + tcnt, acnt - tcnt,
+ " %s: i2c=%02x", client->name, client->addr);
tcnt += ccnt;
+ cd = i2c_get_clientdata(client);
v4l2_device_for_each_subdev(sd, &hdw->v4l2_dev) {
- id = sd->grp_id;
- p = NULL;
- if (id < ARRAY_SIZE(module_names)) {
- p = module_names[id];
- }
- if (p) {
- ccnt = scnprintf(buf + tcnt,
- acnt - tcnt,
- " %s", p);
- } else {
- ccnt = scnprintf(buf + tcnt,
- acnt - tcnt,
- " (unknown id=%u)", id);
+ if (cd == sd) {
+ id = sd->grp_id;
+ p = NULL;
+ if (id < ARRAY_SIZE(module_names)) {
+ p = module_names[id];
+ }
+ if (p) {
+ ccnt = scnprintf(buf + tcnt,
+ acnt - tcnt,
+ " subdev=%s", p);
+ tcnt += ccnt;
+ } else {
+ ccnt = scnprintf(buf + tcnt,
+ acnt - tcnt,
+ " subdev= id %u)",
+ id);
+ tcnt += ccnt;
+ }
+ break;
}
- tcnt += ccnt;
}
- return tcnt;
- }
- default: break;
+ ccnt = scnprintf(buf + tcnt, acnt - tcnt, "\n");
+ tcnt += ccnt;
}
- return 0;
+ mutex_unlock(&hdw->i2c_adap.clist_lock);
+ return tcnt;
}
buf[0] = '\n'; ccnt = 1;
bcnt += ccnt; acnt -= ccnt; buf += ccnt;
}
+ ccnt = pvr2_hdw_report_clients(hdw, buf, acnt);
+ bcnt += ccnt; acnt -= ccnt; buf += ccnt;
LOCK_GIVE(hdw->big_lock);
return bcnt;
}
static void pvr2_hdw_state_log_state(struct pvr2_hdw *hdw)
{
- char buf[128];
- unsigned int idx,ccnt;
+ char buf[256];
+ unsigned int idx, ccnt;
+ unsigned int lcnt, ucnt;
for (idx = 0; ; idx++) {
ccnt = pvr2_hdw_report_unlocked(hdw,idx,buf,sizeof(buf));
if (!ccnt) break;
printk(KERN_INFO "%s %.*s\n",hdw->name,ccnt,buf);
}
+ ccnt = pvr2_hdw_report_clients(hdw, buf, sizeof(buf));
+ ucnt = 0;
+ while (ucnt < ccnt) {
+ lcnt = 0;
+ while ((lcnt + ucnt < ccnt) && (buf[lcnt + ucnt] != '\n')) {
+ lcnt++;
+ }
+ printk(KERN_INFO "%s %.*s\n", hdw->name, lcnt, buf + ucnt);
+ ucnt += lcnt + 1;
+ }
}
struct v4l2_tuner *vtp = &hdw->tuner_signal_info;
memset(vtp, 0, sizeof(*vtp));
hdw->tuner_signal_stale = 0;
- pvr2_i2c_core_status_poll(hdw);
/* Note: There apparently is no replacement for VIDIOC_CROPCAP
using v4l2-subdev - therefore we can't support that AT ALL right
now. (Of course, no sub-drivers seem to implement it either.
int setFl, u64 *val_ptr)
{
#ifdef CONFIG_VIDEO_ADV_DEBUG
- struct pvr2_i2c_client *cp;
struct v4l2_dbg_register req;
int stat = 0;
int okFl = 0;
/* It would be nice to know if a sub-device answered the request */
v4l2_device_call_all(&hdw->v4l2_dev, 0, core, g_register, &req);
if (!setFl) *val_ptr = req.val;
- if (!okFl) mutex_lock(&hdw->i2c_list_lock); do {
- list_for_each_entry(cp, &hdw->i2c_clients, list) {
- if (!v4l2_chip_match_i2c_client(
- cp->client,
- &req.match)) {
- continue;
- }
- stat = pvr2_i2c_client_cmd(
- cp,(setFl ? VIDIOC_DBG_S_REGISTER :
- VIDIOC_DBG_G_REGISTER),&req);
- if (!setFl) *val_ptr = req.val;
- okFl = !0;
- break;
- }
- } while (0); mutex_unlock(&hdw->i2c_list_lock);
if (okFl) {
return stat;
}