summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@infradead.org>2006-06-25 22:16:47 -0300
committerMauro Carvalho Chehab <mchehab@infradead.org>2006-06-25 22:16:47 -0300
commit6e3e1d3647a8df0faa85e8f74e42c0adfa97fb57 (patch)
tree4727e713cc778c7c1f466ed0bfb5f2a6b20e9193
parente27b9707f11774d40fd1e1278b5a11d4683313d5 (diff)
parent0217d884320494197ce193e3a7be37d2aadb298b (diff)
downloadmediapointer-dvb-s2-6e3e1d3647a8df0faa85e8f74e42c0adfa97fb57.tar.gz
mediapointer-dvb-s2-6e3e1d3647a8df0faa85e8f74e42c0adfa97fb57.tar.bz2
merge: http://linuxtv.org/hg/~mcisely/pvrusb2
From: Mauro Carvalho Chehab <mchehab@infradead.org> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-ctrl.c59
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-ctrl.h8
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c7
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-encoder.c377
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h31
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c471
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-hdw.h15
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-main.c8
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-std.c2
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-sysfs.c92
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c135
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c7
12 files changed, 778 insertions, 434 deletions
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-ctrl.c b/linux/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
index e55f43e44..20a1c7af7 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
@@ -58,6 +58,8 @@ int pvr2_ctrl_set_mask_value(struct pvr2_ctrl *cptr,int mask,int val)
if (val >= cptr->info->def.type_enum.count) {
break;
}
+ } else if (cptr->info->type != pvr2_ctl_bool) {
+ break;
}
ret = cptr->info->set_value(cptr,mask,val);
} else {
@@ -217,6 +219,32 @@ int pvr2_ctrl_get_valname(struct pvr2_ctrl *cptr,int val,
}
+/* Return V4L ID for this control or zero if none */
+int pvr2_ctrl_get_v4lid(struct pvr2_ctrl *cptr)
+{
+ if (!cptr) return 0;
+ return cptr->info->v4l_id;
+}
+
+
+unsigned int pvr2_ctrl_get_v4lflags(struct pvr2_ctrl *cptr)
+{
+ unsigned int flags = 0;
+
+ if (cptr->info->get_v4lflags) {
+ flags = cptr->info->get_v4lflags(cptr);
+ }
+
+ if (cptr->info->set_value) {
+ flags &= ~V4L2_CTRL_FLAG_READ_ONLY;
+ } else {
+ flags |= V4L2_CTRL_FLAG_READ_ONLY;
+ }
+
+ return flags;
+}
+
+
/* Return true if control is writable */
int pvr2_ctrl_is_writable(struct pvr2_ctrl *cptr)
{
@@ -313,6 +341,14 @@ static unsigned int gen_bitmask_string(int msk,int val,int msk_only,
}
+static const char *boolNames[] = {
+ "false",
+ "true",
+ "no",
+ "yes",
+};
+
+
static int parse_token(const char *ptr,unsigned int len,
int *valptr,
const char **names,unsigned int namecnt)
@@ -343,7 +379,7 @@ static int parse_token(const char *ptr,unsigned int len,
*valptr = simple_strtol(buf,&p2,0);
if (negfl) *valptr = -(*valptr);
if (*p2) return -EINVAL;
- return 0;
+ return 1;
}
@@ -458,21 +494,31 @@ int pvr2_ctrl_sym_to_value(struct pvr2_ctrl *cptr,
LOCK_TAKE(cptr->hdw->big_lock); do {
if (cptr->info->type == pvr2_ctl_int) {
ret = parse_token(ptr,len,valptr,0,0);
- if ((ret == 0) &&
+ if ((ret >= 0) &&
((*valptr < cptr->info->def.type_int.min_value) ||
(*valptr > cptr->info->def.type_int.max_value))) {
- ret = -EINVAL;
+ ret = -ERANGE;
}
if (maskptr) *maskptr = ~0;
+ } else if (cptr->info->type == pvr2_ctl_bool) {
+ ret = parse_token(
+ ptr,len,valptr,boolNames,
+ sizeof(boolNames)/sizeof(boolNames[0]));
+ if (ret == 1) {
+ *valptr = *valptr ? !0 : 0;
+ } else if (ret == 0) {
+ *valptr = (*valptr & 1) ? !0 : 0;
+ }
+ if (maskptr) *maskptr = 1;
} else if (cptr->info->type == pvr2_ctl_enum) {
ret = parse_token(
ptr,len,valptr,
cptr->info->def.type_enum.value_names,
cptr->info->def.type_enum.count);
- if ((ret == 0) &&
+ if ((ret >= 0) &&
((*valptr < 0) ||
(*valptr >= cptr->info->def.type_enum.count))) {
- ret = -EINVAL;
+ ret = -ERANGE;
}
if (maskptr) *maskptr = ~0;
} else if (cptr->info->type == pvr2_ctl_bitmask) {
@@ -498,6 +544,9 @@ int pvr2_ctrl_value_to_sym_internal(struct pvr2_ctrl *cptr,
if (cptr->info->type == pvr2_ctl_int) {
*len = scnprintf(buf,maxlen,"%d",val);
ret = 0;
+ } else if (cptr->info->type == pvr2_ctl_bool) {
+ *len = scnprintf(buf,maxlen,"%s",val ? "true" : "false");
+ ret = 0;
} else if (cptr->info->type == pvr2_ctl_enum) {
const char **names;
names = cptr->info->def.type_enum.value_names;
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-ctrl.h b/linux/drivers/media/video/pvrusb2/pvrusb2-ctrl.h
index 9d74151a3..c1680053c 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-ctrl.h
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-ctrl.h
@@ -27,6 +27,7 @@ enum pvr2_ctl_type {
pvr2_ctl_int = 0,
pvr2_ctl_enum = 1,
pvr2_ctl_bitmask = 2,
+ pvr2_ctl_bool = 3,
};
@@ -70,6 +71,13 @@ int pvr2_ctrl_get_valname(struct pvr2_ctrl *,int,char *,unsigned int,
/* Return true if control is writable */
int pvr2_ctrl_is_writable(struct pvr2_ctrl *);
+/* Return V4L flags value for control (or zero if there is no v4l control
+ actually under this control) */
+unsigned int pvr2_ctrl_get_v4lflags(struct pvr2_ctrl *);
+
+/* Return V4L ID for this control or zero if none */
+int pvr2_ctrl_get_v4lid(struct pvr2_ctrl *);
+
/* Return true if control has custom symbolic representation */
int pvr2_ctrl_has_custom_symbols(struct pvr2_ctrl *);
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c b/linux/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
index 47e7f5dbd..27eadaff7 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
@@ -104,12 +104,15 @@ static void set_audio(struct pvr2_v4l_cx2584x *ctxt)
hdw->srate_val);
switch (hdw->srate_val) {
default:
- case PVR2_CVAL_SRATE_48:
+ case V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000:
val = 48000;
break;
- case PVR2_CVAL_SRATE_44_1:
+ case V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100:
val = 44100;
break;
+ case V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000:
+ val = 32000;
+ break;
}
pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_AUDIO_CLOCK_FREQ,&val);
}
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-encoder.c b/linux/drivers/media/video/pvrusb2/pvrusb2-encoder.c
index 958500466..5b68bad01 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-encoder.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-encoder.c
@@ -23,41 +23,11 @@
#include "compat.h"
#include <linux/device.h> // for linux/firmware.h
#include <linux/firmware.h>
-#include <linux/videodev2.h>
-#include <media/cx2341x.h>
#include "pvrusb2-util.h"
#include "pvrusb2-encoder.h"
#include "pvrusb2-hdw-internal.h"
#include "pvrusb2-debug.h"
-static u32 pvr_tbl_emphasis [] = {
- [PVR2_CVAL_AUDIOEMPHASIS_NONE] = 0x0 << 12,
- [PVR2_CVAL_AUDIOEMPHASIS_50_15] = 0x1 << 12,
- [PVR2_CVAL_AUDIOEMPHASIS_CCITT] = 0x3 << 12,
-};
-
-static u32 pvr_tbl_srate[] = {
- [PVR2_CVAL_SRATE_48] = 0x01,
- [PVR2_CVAL_SRATE_44_1] = 0x00,
-};
-
-static u32 pvr_tbl_audiobitrate[] = {
- [PVR2_CVAL_AUDIOBITRATE_384] = 0xe << 4,
- [PVR2_CVAL_AUDIOBITRATE_320] = 0xd << 4,
- [PVR2_CVAL_AUDIOBITRATE_256] = 0xc << 4,
- [PVR2_CVAL_AUDIOBITRATE_224] = 0xb << 4,
- [PVR2_CVAL_AUDIOBITRATE_192] = 0xa << 4,
- [PVR2_CVAL_AUDIOBITRATE_160] = 0x9 << 4,
- [PVR2_CVAL_AUDIOBITRATE_128] = 0x8 << 4,
- [PVR2_CVAL_AUDIOBITRATE_112] = 0x7 << 4,
- [PVR2_CVAL_AUDIOBITRATE_96] = 0x6 << 4,
- [PVR2_CVAL_AUDIOBITRATE_80] = 0x5 << 4,
- [PVR2_CVAL_AUDIOBITRATE_64] = 0x4 << 4,
- [PVR2_CVAL_AUDIOBITRATE_56] = 0x3 << 4,
- [PVR2_CVAL_AUDIOBITRATE_48] = 0x2 << 4,
- [PVR2_CVAL_AUDIOBITRATE_32] = 0x1 << 4,
- [PVR2_CVAL_AUDIOBITRATE_VBR] = 0x0 << 4,
-};
/* Firmware mailbox flags - definitions found from ivtv */
@@ -66,7 +36,7 @@ static u32 pvr_tbl_audiobitrate[] = {
#define IVTV_MBOX_DRIVER_BUSY 0x00000001
-static int pvr2_write_encoder_words(struct pvr2_hdw *hdw,
+static int pvr2_encoder_write_words(struct pvr2_hdw *hdw,
const u32 *data, unsigned int dlen)
{
unsigned int idx;
@@ -107,7 +77,7 @@ static int pvr2_write_encoder_words(struct pvr2_hdw *hdw,
}
-static int pvr2_read_encoder_words(struct pvr2_hdw *hdw,int statusFl,
+static int pvr2_encoder_read_words(struct pvr2_hdw *hdw,int statusFl,
u32 *data, unsigned int dlen)
{
unsigned int idx;
@@ -148,15 +118,46 @@ static int pvr2_read_encoder_words(struct pvr2_hdw *hdw,int statusFl,
}
-static int pvr2_write_encoder_vcmd (struct pvr2_hdw *hdw, u8 cmd,
- int args, ...)
+/* This prototype is set up to be compatible with the
+ cx2341x_mbox_func prototype in cx2341x.h, which should be in
+ kernels 2.6.18 or later. We do this so that we can enable
+ cx2341x.ko to write to our encoder (by handing it a pointer to this
+ function). For earlier kernels this doesn't really matter. */
+static int pvr2_encoder_cmd(void *ctxt,
+ int cmd,
+ int arg_cnt_send,
+ int arg_cnt_recv,
+ u32 *argp)
{
unsigned int poll_count;
int ret = 0;
- va_list vl;
unsigned int idx;
+ /* These sizes look to be limited by the FX2 firmware implementation */
u32 wrData[16];
- u32 rdData[32];
+ u32 rdData[16];
+ struct pvr2_hdw *hdw = (struct pvr2_hdw *)ctxt;
+
+#if 0
+ {
+ char buf[150];
+ unsigned int ccnt,bcnt;
+
+ bcnt = scnprintf(buf,sizeof(buf),"Encoder Cmd %02x (",cmd);
+ for (idx = 0; idx < arg_cnt_send; idx++) {
+ if (idx) {
+ ccnt = scnprintf(buf+bcnt,
+ sizeof(buf)-bcnt," ");
+ bcnt += ccnt;
+ }
+ ccnt = scnprintf(buf+bcnt,sizeof(buf)-bcnt,
+ "0x%x",argp[idx]);
+ bcnt += ccnt;
+ }
+ ccnt = scnprintf(buf+bcnt,sizeof(buf)-bcnt,")");
+ bcnt += ccnt;
+ pvr2_trace(PVR2_TRACE_ENCODER,"%.*s",bcnt,buf);
+ }
+#endif
/*
@@ -190,6 +191,28 @@ static int pvr2_write_encoder_vcmd (struct pvr2_hdw *hdw, u8 cmd,
*/
+ if (arg_cnt_send > (sizeof(wrData)/sizeof(wrData[0]))-4) {
+ pvr2_trace(
+ PVR2_TRACE_ERROR_LEGS,
+ "Failed to write cx23416 command"
+ " - too many input arguments"
+ " (was given %u limit %u)",
+ arg_cnt_send,
+ (sizeof(wrData)/sizeof(wrData[0])) - 4);
+ return -EINVAL;
+ }
+
+ if (arg_cnt_recv > (sizeof(rdData)/sizeof(rdData[0]))-4) {
+ pvr2_trace(
+ PVR2_TRACE_ERROR_LEGS,
+ "Failed to write cx23416 command"
+ " - too many return arguments"
+ " (was given %u limit %u)",
+ arg_cnt_recv,
+ (sizeof(rdData)/sizeof(rdData[0])) - 4);
+ return -EINVAL;
+ }
+
LOCK_TAKE(hdw->ctl_lock); do {
@@ -197,25 +220,22 @@ static int pvr2_write_encoder_vcmd (struct pvr2_hdw *hdw, u8 cmd,
wrData[1] = cmd;
wrData[2] = 0;
wrData[3] = 0x00060000;
- va_start(vl, args);
- for (idx = 0; idx < args; idx++) {
- wrData[idx+4] = va_arg(vl, u32);
+ for (idx = 0; idx < arg_cnt_send; idx++) {
+ wrData[idx+4] = argp[idx];
}
- va_end(vl);
- args += 4;
- while (args < sizeof(wrData)/sizeof(wrData[0])) {
- wrData[args++] = 0;
+ for (; idx < (sizeof(wrData)/sizeof(wrData[0]))-4; idx++) {
+ wrData[idx+4] = 0;
}
- ret = pvr2_write_encoder_words(hdw,wrData,args);
+ ret = pvr2_encoder_write_words(hdw,wrData,idx);
if (ret) break;
wrData[0] = IVTV_MBOX_DRIVER_DONE|IVTV_MBOX_DRIVER_BUSY;
- ret = pvr2_write_encoder_words(hdw,wrData,1);
+ ret = pvr2_encoder_write_words(hdw,wrData,1);
if (ret) break;
poll_count = 0;
while (1) {
if (poll_count < 10000000) poll_count++;
- ret = pvr2_read_encoder_words(hdw,!0,rdData,1);
+ ret = pvr2_encoder_read_words(hdw,!0,rdData,1);
if (ret) break;
if (rdData[0] & IVTV_MBOX_FIRMWARE_DONE) {
break;
@@ -229,7 +249,7 @@ static int pvr2_write_encoder_vcmd (struct pvr2_hdw *hdw, u8 cmd,
pvr2_trace(
PVR2_TRACE_ERROR_LEGS,
"Encoder command: 0x%02x",cmd);
- for (idx = 4; idx < args; idx++) {
+ for (idx = 4; idx < arg_cnt_send; idx++) {
pvr2_trace(
PVR2_TRACE_ERROR_LEGS,
"Encoder arg%d: 0x%08x",
@@ -246,8 +266,11 @@ static int pvr2_write_encoder_vcmd (struct pvr2_hdw *hdw, u8 cmd,
}
if (ret) break;
wrData[0] = 0x7;
- ret = pvr2_read_encoder_words(hdw,0,rdData,16);
+ ret = pvr2_encoder_read_words(
+ hdw,0,rdData,
+ sizeof(rdData)/sizeof(rdData[0]));
if (ret) break;
+#if 0
for (idx = 0; idx < args; idx++) {
if (rdData[idx] != wrData[idx]) {
pvr2_trace(
@@ -257,9 +280,13 @@ static int pvr2_write_encoder_vcmd (struct pvr2_hdw *hdw, u8 cmd,
idx,wrData[idx],rdData[idx]);
}
}
+#endif
+ for (idx = 0; idx < arg_cnt_recv; idx++) {
+ argp[idx] = rdData[idx+4];
+ }
wrData[0] = 0x0;
- ret = pvr2_write_encoder_words(hdw,wrData,1);
+ ret = pvr2_encoder_write_words(hdw,wrData,1);
if (ret) break;
} while(0); LOCK_GIVE(hdw->ctl_lock);
@@ -267,176 +294,94 @@ static int pvr2_write_encoder_vcmd (struct pvr2_hdw *hdw, u8 cmd,
return ret;
}
-int pvr2_encoder_configure(struct pvr2_hdw *hdw)
+
+static int pvr2_encoder_vcmd(struct pvr2_hdw *hdw, int cmd,
+ int args, ...)
{
- int ret = 0, audio, i;
- v4l2_std_id vd_std = hdw->std_mask_cur;
- int height = hdw->res_ver_val;
- int width = hdw->res_hor_val;
- int height_full = !hdw->interlace_val;
-
- int is_30fps, is_ntsc;
-
- if (vd_std & V4L2_STD_NTSC) {
- is_ntsc=1;
- is_30fps=1;
- } else if (vd_std & V4L2_STD_PAL_M) {
- is_ntsc=0;
- is_30fps=1;
- } else {
- is_ntsc=0;
- is_30fps=0;
+ va_list vl;
+ unsigned int idx;
+ u32 data[12];
+
+ if (args > sizeof(data)/sizeof(data[0])) {
+ pvr2_trace(
+ PVR2_TRACE_ERROR_LEGS,
+ "Failed to write cx23416 command"
+ " - too many arguments"
+ " (was given %u limit %u)",
+ args,sizeof(data)/sizeof(data[0]));
+ return -EINVAL;
}
- pvr2_trace(PVR2_TRACE_ENCODER,"pvr2_encoder_configure");
-
- /* set stream output port. Some notes here: The ivtv-derived
- encoder documentation says that this command only gets a
- single argument. However the Windows driver for the model
- 29xxx series hardware has been sending 0x01 as a second
- argument, while the Windows driver for the model 24xxx
- series hardware has been sending 0x02 as a second argument.
- Confusing matters further are the observations that 0x01
- for that second argument simply won't work on the 24xxx
- hardware, while 0x02 will work on the 29xxx - except that
- when we use 0x02 then xawtv breaks due to a loss of
- synchronization with the mpeg packet headers. While xawtv
- should be fixed to let it resync better (I did try to
- contact Gerd about this but he has not answered), it has
- also been determined that sending 0x00 as this mystery
- second argument seems to work on both hardware models AND
- xawtv works again. So we're going to send 0x00. */
- ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_SET_OUTPUT_PORT, 2,
- 0x01, 0x00);
-
- /* set the Program Index Information. We want I,P,B frames (max 400) */
- ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_SET_PGM_INDEX_INFO, 2,
- 0x07, 0x0190);
-
- /* NOTE : windows driver sends these */
- /* Mike Isely <isely@pobox.com> 7-Mar-2006 The windows driver
- sends the following commands but if we do the same then
- many apps are no longer able to read the video stream.
- Leaving these out seems to do no harm at all, so they're
- commented out for that reason. */
-#ifdef notdef
- ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 5,0,0,0);
- ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 3,1,0,0);
- ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 8,0,0,0);
- ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 4,1,0,0);
- ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 0,3,0,0);
- ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_MISC,4,15,0,0,0);
-#endif
+ va_start(vl, args);
+ for (idx = 0; idx < args; idx++) {
+ data[idx] = va_arg(vl, u32);
+ }
+ va_end(vl);
- /* Strange compared to ivtv data. */
-#if 0
- ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2,
- 0x0120, 0x0120);
- ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2,
- 0x0131, 0x0131);
-#endif
- ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2,
- 0xf0, 0xf0);
+ return pvr2_encoder_cmd(hdw,cmd,args,0,data);
+}
- /* setup firmware to notify us about some events (don't know why...) */
- ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_SET_EVENT_NOTIFICATION, 4,
- 0, 0, 0x10000000, 0xffffffff);
+int pvr2_encoder_configure(struct pvr2_hdw *hdw)
+{
+ int ret;
+ pvr2_trace(PVR2_TRACE_ENCODER,"pvr2_encoder_configure"
+ " (cx2341x module)");
+ hdw->enc_ctl_state.port = CX2341X_PORT_STREAMING;
+ hdw->enc_ctl_state.width = hdw->res_hor_val;
+ hdw->enc_ctl_state.height = hdw->res_ver_val;
+ hdw->enc_ctl_state.is_50hz = ((hdw->std_mask_cur &
+ (V4L2_STD_NTSC|V4L2_STD_PAL_M)) ?
+ 0 : 1);
- /* set fps to 25 or 30 (1 or 0)*/
- ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_SET_FRAME_RATE, 1,
- is_30fps ? 0 : 1);
+ ret = 0;
- /* set encoding resolution */
- ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_SET_FRAME_SIZE, 2,
- (height_full ? height : (height / 2)),
- width);
- /* set encoding aspect ratio to 4:3 */
- ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_SET_ASPECT_RATIO, 1,
- 0x02);
+ if (!ret) ret = pvr2_encoder_vcmd(
+ hdw,CX2341X_ENC_SET_NUM_VSYNC_LINES, 2,
+ 0xf0, 0xf0);
- /* VBI */
+ /* setup firmware to notify us about some events (don't know why...) */
+ if (!ret) ret = pvr2_encoder_vcmd(
+ hdw,CX2341X_ENC_SET_EVENT_NOTIFICATION, 4,
+ 0, 0, 0x10000000, 0xffffffff);
+
+ if (!ret) ret = pvr2_encoder_vcmd(
+ hdw,CX2341X_ENC_SET_VBI_LINE, 5,
+ 0xffffffff,0,0,0,0);
+
+ if (ret) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "Failed to configure cx32416");
+ return ret;
+ }
- if (hdw->config == pvr2_config_vbi) {
- int lines = 2 * (is_30fps ? 12 : 18);
- int size = (4*((lines*1443+3)/4)) / lines;
- ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_SET_VBI_CONFIG, 7,
- 0xbd05, 1, 4,
- 0x25256262, 0x387f7f7f,
- lines , size);
-// 0x25256262, 0x13135454, lines , size);
- /* select vbi lines */
-#define line_used(l) (is_30fps ? (l >= 10 && l <= 21) : (l >= 6 && l <= 23))
- for (i = 2 ; i <= 24 ; i++){
- ret |= pvr2_write_encoder_vcmd(
- hdw,CX2341X_ENC_SET_VBI_LINE, 5,
- i-1,line_used(i), 0, 0, 0);
- ret |= pvr2_write_encoder_vcmd(
- hdw,CX2341X_ENC_SET_VBI_LINE, 5,
- (i-1) | (1 << 31),
- line_used(i), 0, 0, 0);
- }
- } else {
- ret |= pvr2_write_encoder_vcmd(
- hdw,CX2341X_ENC_SET_VBI_LINE, 5,
- 0xffffffff,0,0,0,0);
+ ret = cx2341x_update(hdw,pvr2_encoder_cmd,
+ (hdw->enc_cur_valid ? &hdw->enc_cur_state : 0),
+ &hdw->enc_ctl_state);
+ if (ret) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "Error from cx2341x module code=%d",ret);
+ return ret;
}
- /* set stream type, depending on resolution. */
- ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_SET_STREAM_TYPE, 1,
- height_full ? 0x0a : 0x0b);
- /* set video bitrate */
- ret |= pvr2_write_encoder_vcmd(
- hdw, CX2341X_ENC_SET_BIT_RATE, 3,
- (hdw->vbr_val ? 1 : 0),
- hdw->videobitrate_val,
- hdw->videopeak_val / 400);
- /* setup GOP structure (GOP size = 0f or 0c, 3-1 = 2 B-frames) */
- ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_SET_GOP_PROPERTIES, 2,
- is_30fps ? 0x0f : 0x0c, 0x03);
-
- /* enable 3:2 pulldown */
- ret |= pvr2_write_encoder_vcmd(hdw,CX2341X_ENC_SET_3_2_PULLDOWN,1,0);
-
- /* set GOP open/close property (open) */
- ret |= pvr2_write_encoder_vcmd(hdw,CX2341X_ENC_SET_GOP_CLOSURE,1,0);
-
- /* set audio stream properties 0x40b9? 0100 0000 1011 1001 */
- audio = (pvr_tbl_audiobitrate[hdw->audiobitrate_val] |
- pvr_tbl_srate[hdw->srate_val] |
- hdw->audiolayer_val << 2 |
- (hdw->audiocrc_val ? 1 << 14 : 0) |
- pvr_tbl_emphasis[hdw->audioemphasis_val]);
-
- ret |= pvr2_write_encoder_vcmd(hdw,CX2341X_ENC_SET_AUDIO_PROPERTIES,1,
- audio);
-
- /* set dynamic noise reduction filter to manual, Horiz/Vert */
- ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_SET_DNR_FILTER_MODE, 2,
- 0, 0x03);
-
- /* dynamic noise reduction filter param */
- ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_SET_DNR_FILTER_PROPS, 2
- , 0, 0);
-
- /* dynamic noise reduction median filter */
- ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_SET_CORING_LEVELS, 4,
- 0, 0xff, 0, 0xff);
-
- /* spacial prefiler parameter */
- ret |= pvr2_write_encoder_vcmd(hdw,
- CX2341X_ENC_SET_SPATIAL_FILTER_TYPE, 2,
- 0x01, 0x01);
-
- /* initialize video input */
- ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_INITIALIZE_INPUT, 0);
-
- if (!ret) {
- hdw->subsys_enabled_mask |= (1<<PVR2_SUBSYS_B_ENC_CFG);
+ ret = 0;
+
+ if (!ret) ret = pvr2_encoder_vcmd(
+ hdw, CX2341X_ENC_INITIALIZE_INPUT, 0);
+
+ if (ret) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "Failed to initialize cx32416 video input");
+ return ret;
}
- 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;
}
+
int pvr2_encoder_start(struct pvr2_hdw *hdw)
{
int status;
@@ -449,14 +394,14 @@ int pvr2_encoder_start(struct pvr2_hdw *hdw)
pvr2_hdw_gpio_chg_out(hdw,0xffffffff,0x00000000);
if (hdw->config == pvr2_config_vbi) {
- status = pvr2_write_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,
- 0x01,0x14);
+ status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,
+ 0x01,0x14);
} else if (hdw->config == pvr2_config_mpeg) {
- status = pvr2_write_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,
- 0,0x13);
+ status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,
+ 0,0x13);
} else {
- status = pvr2_write_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,
- 0,0x13);
+ status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,
+ 0,0x13);
}
if (!status) {
hdw->subsys_enabled_mask |= (1<<PVR2_SUBSYS_B_ENC_RUN);
@@ -472,14 +417,14 @@ int pvr2_encoder_stop(struct pvr2_hdw *hdw)
pvr2_write_register(hdw, 0x0048, 0xffffffff);
if (hdw->config == pvr2_config_vbi) {
- status = pvr2_write_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,
- 0x01,0x01,0x14);
+ status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,
+ 0x01,0x01,0x14);
} else if (hdw->config == pvr2_config_mpeg) {
- status = pvr2_write_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,
- 0x01,0,0x13);
+ status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,
+ 0x01,0,0x13);
} else {
- status = pvr2_write_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,
- 0x01,0,0x13);
+ status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,
+ 0x01,0,0x13);
}
/* change some GPIO data */
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
index 0d527abb5..cfec4d37c 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
@@ -44,6 +44,7 @@
#endif
#include "pvrusb2-hdw.h"
#include "pvrusb2-io.h"
+#include <media/cx2341x.h>
/* Legal values for the SRATE state variable */
#define PVR2_CVAL_SRATE_48 0
@@ -98,6 +99,7 @@ typedef int (*pvr2_ctlf_val_to_sym)(struct pvr2_ctrl *,int msk,int val,
typedef int (*pvr2_ctlf_sym_to_val)(struct pvr2_ctrl *,
const char *,unsigned int,
int *mskp,int *valp);
+typedef unsigned int (*pvr2_ctlf_get_v4lflags)(struct pvr2_ctrl *);
/* This structure describes a specific control. A table of these is set up
in pvrusb2-hdw.c. */
@@ -115,6 +117,7 @@ struct pvr2_ctl_info {
pvr2_ctlf_sym_to_val sym_to_val; /* Custom convert symbol->value */
pvr2_ctlf_is_dirty is_dirty; /* Return true if dirty */
pvr2_ctlf_clear_dirty clear_dirty; /* Clear dirty state */
+ pvr2_ctlf_get_v4lflags get_v4lflags;/* Retrieve v4l flags */
/* Control's type (int, enum, bitmask) */
enum pvr2_ctl_type type;
@@ -149,6 +152,13 @@ struct pvr2_ctl_info {
};
+/* Same as pvr2_ctl_info, but includes storage for the control description */
+#define PVR2_CTLD_INFO_DESC_SIZE 32
+struct pvr2_ctld_info {
+ struct pvr2_ctl_info info;
+ char desc[PVR2_CTLD_INFO_DESC_SIZE];
+};
+
struct pvr2_ctrl {
const struct pvr2_ctl_info *info;
struct pvr2_hdw *hdw;
@@ -329,6 +339,14 @@ struct pvr2_hdw {
int flag_bilingual;
struct pvr2_audio_stat *audio_stat;
+ /* 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 enc_cur_state is valid */
+ int enc_cur_valid;
+
/* Control state */
#define VCREATE_DATA(lab) int lab##_val; int lab##_dirty
VCREATE_DATA(brightness);
@@ -340,22 +358,17 @@ struct pvr2_hdw {
VCREATE_DATA(bass);
VCREATE_DATA(treble);
VCREATE_DATA(mute);
- VCREATE_DATA(srate);
- VCREATE_DATA(audiobitrate);
- VCREATE_DATA(audiocrc);
- VCREATE_DATA(audioemphasis);
- VCREATE_DATA(vbr);
- VCREATE_DATA(videobitrate);
- VCREATE_DATA(videopeak);
VCREATE_DATA(input);
VCREATE_DATA(audiomode);
VCREATE_DATA(res_hor);
VCREATE_DATA(res_ver);
- VCREATE_DATA(interlace);
- VCREATE_DATA(audiolayer);
+ VCREATE_DATA(srate);
#undef VCREATE_DATA
+ struct pvr2_ctld_info *mpeg_ctrl_info;
+
struct pvr2_ctrl *controls;
+ unsigned int control_cnt;
};
int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw);
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c
index 409343097..91a0ae19d 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c
@@ -24,9 +24,8 @@
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/firmware.h>
-#include <asm/semaphore.h>
#include <linux/videodev2.h>
-#include <media/cx2341x.h>
+#include <asm/semaphore.h>
#include "pvrusb2.h"
#include "pvrusb2-std.h"
#include "pvrusb2-util.h"
@@ -132,36 +131,105 @@ MODULE_PARM_DESC(tolerance,"specify stream error tolerance");
/* size of a firmware chunk */
#define FIRMWARE_CHUNK_SIZE 0x2000
+/* Define the list of additional controls we'll dynamically construct based
+ on query of the cx2341x module. */
+struct pvr2_mpeg_ids {
+ const char *strid;
+ int id;
+};
+static const struct pvr2_mpeg_ids mpeg_ids[] = {
+ {
+ .strid = "audio_layer",
+ .id = V4L2_CID_MPEG_AUDIO_ENCODING,
+ },{
+ .strid = "audio_bitrate",
+ .id = V4L2_CID_MPEG_AUDIO_L2_BITRATE,
+ },{
+ /* Already using audio_mode elsewhere :-( */
+ .strid = "mpeg_audio_mode",
+ .id = V4L2_CID_MPEG_AUDIO_MODE,
+ },{
+ .strid = "mpeg_audio_mode_extension",
+ .id = V4L2_CID_MPEG_AUDIO_MODE_EXTENSION,
+ },{
+ .strid = "audio_emphasis",
+ .id = V4L2_CID_MPEG_AUDIO_EMPHASIS,
+ },{
+ .strid = "audio_crc",
+ .id = V4L2_CID_MPEG_AUDIO_CRC,
+ },{
+ .strid = "video_aspect",
+ .id = V4L2_CID_MPEG_VIDEO_ASPECT,
+ },{
+ .strid = "video_b_frames",
+ .id = V4L2_CID_MPEG_VIDEO_B_FRAMES,
+ },{
+ .strid = "video_gop_size",
+ .id = V4L2_CID_MPEG_VIDEO_GOP_SIZE,
+ },{
+ .strid = "video_gop_closure",
+ .id = V4L2_CID_MPEG_VIDEO_GOP_CLOSURE,
+ },{
+ .strid = "video_pulldown",
+ .id = V4L2_CID_MPEG_VIDEO_PULLDOWN,
+ },{
+ .strid = "video_bitrate_mode",
+ .id = V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
+ },{
+ .strid = "video_bitrate",
+ .id = V4L2_CID_MPEG_VIDEO_BITRATE,
+ },{
+ .strid = "video_bitrate_peak",
+ .id = V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
+ },{
+ .strid = "video_temporal_decimation",
+ .id = V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION,
+ },{
+ .strid = "stream_type",
+ .id = V4L2_CID_MPEG_STREAM_TYPE,
+ },{
+ .strid = "video_spatial_filter_mode",
+ .id = V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE,
+ },{
+ .strid = "video_spatial_filter",
+ .id = V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER,
+ },{
+ .strid = "video_luma_spatial_filter_type",
+ .id = V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE,
+ },{
+ .strid = "video_chroma_spatial_filter_type",
+ .id = V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE,
+ },{
+ .strid = "video_temporal_filter_mode",
+ .id = V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE,
+ },{
+ .strid = "video_temporal_filter",
+ .id = V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER,
+ },{
+ .strid = "video_median_filter_type",
+ .id = V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE,
+ },{
+ .strid = "video_luma_median_filter_top",
+ .id = V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP,
+ },{
+ .strid = "video_luma_median_filter_bottom",
+ .id = V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM,
+ },{
+ .strid = "video_chroma_median_filter_top",
+ .id = V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP,
+ },{
+ .strid = "video_chroma_median_filter_bottom",
+ .id = V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM,
+ }
+};
+#define MPEGDEF_COUNT (sizeof(mpeg_ids)/sizeof(mpeg_ids[0]))
+
static const char *control_values_srate[] = {
[PVR2_CVAL_SRATE_48] = "48KHz",
[PVR2_CVAL_SRATE_44_1] = "44.1KHz",
};
-static const char *control_values_audiobitrate[] = {
- [PVR2_CVAL_AUDIOBITRATE_384] = "384kb/s",
- [PVR2_CVAL_AUDIOBITRATE_320] = "320kb/s",
- [PVR2_CVAL_AUDIOBITRATE_256] = "256kb/s",
- [PVR2_CVAL_AUDIOBITRATE_224] = "224kb/s",
- [PVR2_CVAL_AUDIOBITRATE_192] = "192kb/s",
- [PVR2_CVAL_AUDIOBITRATE_160] = "160kb/s",
- [PVR2_CVAL_AUDIOBITRATE_128] = "128kb/s",
- [PVR2_CVAL_AUDIOBITRATE_112] = "112kb/s",
- [PVR2_CVAL_AUDIOBITRATE_96] = "96kb/s",
- [PVR2_CVAL_AUDIOBITRATE_80] = "80kb/s",
- [PVR2_CVAL_AUDIOBITRATE_64] = "64kb/s",
- [PVR2_CVAL_AUDIOBITRATE_56] = "56kb/s",
- [PVR2_CVAL_AUDIOBITRATE_48] = "48kb/s",
- [PVR2_CVAL_AUDIOBITRATE_32] = "32kb/s",
- [PVR2_CVAL_AUDIOBITRATE_VBR] = "VBR",
-};
-
-
-static const char *control_values_audioemphasis[] = {
- [PVR2_CVAL_AUDIOEMPHASIS_NONE] = "None",
- [PVR2_CVAL_AUDIOEMPHASIS_50_15] = "50/15us",
- [PVR2_CVAL_AUDIOEMPHASIS_CCITT] = "CCITT J.17",
-};
static const char *control_values_input[] = {
@@ -278,6 +346,76 @@ static int ctrl_freq_set(struct pvr2_ctrl *cptr,int m,int v)
return 0;
}
+static int ctrl_cx2341x_is_dirty(struct pvr2_ctrl *cptr)
+{
+ return cptr->hdw->enc_stale != 0;
+}
+
+static void ctrl_cx2341x_clear_dirty(struct pvr2_ctrl *cptr)
+{
+ cptr->hdw->enc_stale = 0;
+}
+
+static int ctrl_cx2341x_get(struct pvr2_ctrl *cptr,int *vp)
+{
+ int ret;
+ struct v4l2_ext_controls cs;
+ struct v4l2_ext_control c1;
+ memset(&cs,0,sizeof(cs));
+ memset(&c1,0,sizeof(c1));
+ cs.controls = &c1;
+ cs.count = 1;
+ c1.id = cptr->info->v4l_id;
+ ret = cx2341x_ext_ctrls(&cptr->hdw->enc_ctl_state,&cs,
+ VIDIOC_G_EXT_CTRLS);
+ if (ret) return ret;
+ *vp = c1.value;
+ return 0;
+}
+
+static int ctrl_cx2341x_set(struct pvr2_ctrl *cptr,int m,int v)
+{
+ int ret;
+ struct v4l2_ext_controls cs;
+ struct v4l2_ext_control c1;
+ memset(&cs,0,sizeof(cs));
+ memset(&c1,0,sizeof(c1));
+ cs.controls = &c1;
+ cs.count = 1;
+ c1.id = cptr->info->v4l_id;
+ c1.value = v;
+ ret = cx2341x_ext_ctrls(&cptr->hdw->enc_ctl_state,&cs,
+ VIDIOC_S_EXT_CTRLS);
+ if (ret) return ret;
+ cptr->hdw->enc_stale = !0;
+ return 0;
+}
+
+static unsigned int ctrl_cx2341x_getv4lflags(struct pvr2_ctrl *cptr)
+{
+ struct v4l2_queryctrl qctrl;
+ struct pvr2_ctl_info *info;
+ qctrl.id = cptr->info->v4l_id;
+ cx2341x_ctrl_query(&cptr->hdw->enc_ctl_state,&qctrl);
+ /* Strip out the const so we can adjust a function pointer. It's
+ OK to do this here because we know this is a dynamically created
+ control, so the underlying storage for the info pointer is (a)
+ private to us, and (b) not in read-only storage. Either we do
+ this or we significantly complicate the underlying control
+ implementation. */
+ info = (struct pvr2_ctl_info *)(cptr->info);
+ if (qctrl.flags & V4L2_CTRL_FLAG_READ_ONLY) {
+ if (info->set_value) {
+ info->set_value = 0;
+ }
+ } else {
+ if (!(info->set_value)) {
+ info->set_value = ctrl_cx2341x_set;
+ }
+ }
+ return qctrl.flags;
+}
+
static int ctrl_streamingenabled_get(struct pvr2_ctrl *cptr,int *vp)
{
*vp = cptr->hdw->flag_streaming_enabled;
@@ -437,6 +575,9 @@ static void ctrl_stdenumcur_clear_dirty(struct pvr2_ctrl *cptr)
.def.type_enum.count = (sizeof(tab)/sizeof((tab)[0])), \
.def.type_enum.value_names = tab
+#define DEFBOOL \
+ .type = pvr2_ctl_bool
+
#define DEFMASK(msk,tab) \
.type = pvr2_ctl_bitmask, \
.def.type_bitmask.valid_bits = msk, \
@@ -468,19 +609,11 @@ VCREATE_FUNCS(balance)
VCREATE_FUNCS(bass)
VCREATE_FUNCS(treble)
VCREATE_FUNCS(mute)
-VCREATE_FUNCS(srate)
-VCREATE_FUNCS(audiobitrate)
-VCREATE_FUNCS(audiocrc)
-VCREATE_FUNCS(audioemphasis)
-VCREATE_FUNCS(vbr)
-VCREATE_FUNCS(videobitrate)
-VCREATE_FUNCS(videopeak)
VCREATE_FUNCS(input)
VCREATE_FUNCS(audiomode)
VCREATE_FUNCS(res_hor)
VCREATE_FUNCS(res_ver)
-VCREATE_FUNCS(interlace)
-VCREATE_FUNCS(audiolayer)
+VCREATE_FUNCS(srate)
#define MIN_FREQ 55250000L
#define MAX_FREQ 850000000L
@@ -549,69 +682,7 @@ static const struct pvr2_ctl_info control_defs[] = {
.name = "mute",
.default_value = 0,
DEFREF(mute),
- DEFINT(0,1),
- },{
- .v4l_id = V4L2_CID_PVR_SRATE,
- .desc = "Sample rate",
- .name = "srate",
- .default_value = PVR2_CVAL_SRATE_48,
- DEFREF(srate),
- DEFENUM(control_values_srate),
- },{
- .v4l_id = V4L2_CID_PVR_AUDIOBITRATE,
- .desc = "Audio Bitrate",
- .name = "audio_bitrate",
- .default_value = PVR2_CVAL_AUDIOBITRATE_224,
- DEFREF(audiobitrate),
- DEFENUM(control_values_audiobitrate),
- },{
- .v4l_id = V4L2_CID_PVR_AUDIOCRC,
- .desc = "Audio CRC",
- .name = "audio_crc",
- .default_value = 1,
- DEFREF(audiocrc),
- DEFINT(0,1),
- },{
- .desc = "Audio Layer",
- .name = "audio_layer",
- .default_value = 2,
- DEFREF(audiolayer),
- DEFINT(0,3),
- },{
- .v4l_id = V4L2_CID_PVR_AUDIOEMPHASIS,
- .desc = "Audio Emphasis",
- .name = "audio_emphasis",
- .default_value = PVR2_CVAL_AUDIOEMPHASIS_NONE,
- DEFREF(audioemphasis),
- DEFENUM(control_values_audioemphasis),
- },{
- .desc = "Interlace mode",
- .name = "interlace",
- .internal_id = PVR2_CID_INTERLACE,
- .default_value = 0,
- DEFREF(interlace),
- DEFINT(0,1),
- },{
- .v4l_id = V4L2_CID_PVR_VBR,
- .desc = "Variable video bitrate",
- .name = "vbr",
- .default_value = 0,
- DEFREF(vbr),
- DEFINT(0,1),
- },{
- .v4l_id = V4L2_CID_PVR_VIDEOBITRATE,
- .desc = "Average video bitrate",
- .name = "video_average_bitrate",
- .default_value = 6000000,
- DEFREF(videobitrate),
- DEFINT(500000,20000000),
- },{
- .v4l_id = V4L2_CID_PVR_VIDEOPEAK,
- .desc = "Peak video bitrate",
- .name = "video_peak_bitrate",
- .default_value = 6000000,
- DEFREF(videopeak),
- DEFINT(500000,20000000),
+ DEFBOOL,
},{
.desc = "Video Source",
.name = "input",
@@ -627,6 +698,27 @@ static const struct pvr2_ctl_info control_defs[] = {
DEFREF(audiomode),
DEFENUM(control_values_audiomode),
},{
+ .desc = "Horizontal capture resolution",
+ .name = "resolution_hor",
+ .internal_id = PVR2_CID_HRES,
+ .default_value = 720,
+ DEFREF(res_hor),
+ DEFINT(320,720),
+ },{
+ .desc = "Vertical capture resolution",
+ .name = "resolution_ver",
+ .internal_id = PVR2_CID_VRES,
+ .default_value = 480,
+ DEFREF(res_ver),
+ DEFINT(200,625),
+ },{
+ .v4l_id = V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ,
+ .desc = "Sample rate",
+ .name = "srate",
+ .default_value = PVR2_CVAL_SRATE_48,
+ DEFREF(srate),
+ DEFENUM(control_values_srate),
+ },{
.desc = "Tuner Frequency (Hz)",
.name = "frequency",
.internal_id = PVR2_CID_FREQUENCY,
@@ -655,24 +747,10 @@ static const struct pvr2_ctl_info control_defs[] = {
.get_value = ctrl_channelprog_get,
DEFINT(0,FREQTABLE_SIZE),
},{
- .desc = "Horizontal capture resolution",
- .name = "resolution_hor",
- .internal_id = PVR2_CID_HRES,
- .default_value = 720,
- DEFREF(res_hor),
- DEFINT(320,720),
- },{
- .desc = "Vertical capture resolution",
- .name = "resolution_ver",
- .internal_id = PVR2_CID_VRES,
- .default_value = 480,
- DEFREF(res_ver),
- DEFINT(200,625),
- },{
.desc = "Streaming Enabled",
.name = "streaming_enabled",
.get_value = ctrl_streamingenabled_get,
- DEFINT(0,1),
+ DEFBOOL,
},{
.desc = "USB Speed",
.name = "usb_speed",
@@ -682,7 +760,7 @@ static const struct pvr2_ctl_info control_defs[] = {
.desc = "Signal Present",
.name = "signal_present",
.get_value = ctrl_signal_get,
- DEFINT(0,1),
+ DEFBOOL,
},{
.desc = "Video Standards Available Mask",
.name = "video_standard_mask_available",
@@ -732,7 +810,7 @@ static const struct pvr2_ctl_info control_defs[] = {
}
};
-#define CTRL_COUNT (sizeof(control_defs)/sizeof(control_defs[0]))
+#define CTRLDEF_COUNT (sizeof(control_defs)/sizeof(control_defs[0]))
const char *pvr2_config_get_name(enum pvr2_config cfg)
@@ -956,6 +1034,10 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
if (ret < 0) return ret;
fwidx = ret;
ret = 0;
+ /* Since we're about to completely reinitialize the encoder,
+ invalidate our cached copy of its configuration state. Next
+ time we configure the encoder, then we'll fully configure it. */
+ hdw->enc_cur_valid = 0;
/* First prepare firmware loading */
ret |= pvr2_write_register(hdw, 0x0048, 0xffffffff); /*interrupt mask*/
@@ -1096,12 +1178,13 @@ void pvr2_hdw_subsys_bit_chg_no_lock(struct pvr2_hdw *hdw,
if (!hdw->flag_ok) return;
msk &= PVR2_SUBSYS_ALL;
+ nmsk = (hdw->subsys_enabled_mask & ~msk) | (val & msk);
+ nmsk &= PVR2_SUBSYS_ALL;
for (;;) {
tryCount++;
- vmsk = hdw->subsys_enabled_mask & PVR2_SUBSYS_ALL;
- nmsk = (vmsk & ~msk) | (val & msk);
- if (!(nmsk ^ vmsk)) break;
+ if (!((nmsk ^ hdw->subsys_enabled_mask) &
+ PVR2_SUBSYS_ALL)) break;
if (tryCount > 4) {
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
"Too many retries when configuring device;"
@@ -1450,7 +1533,7 @@ static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw)
return;
}
- pvr2_trace(PVR2_TRACE_EEPROM,
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
"Unable to select a viable initial video standard");
}
@@ -1509,7 +1592,7 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
pvr2_i2c_core_init(hdw);
if (!pvr2_hdw_dev_ok(hdw)) return;
- for (idx = 0; idx < CTRL_COUNT; idx++) {
+ for (idx = 0; idx < CTRLDEF_COUNT; idx++) {
cptr = hdw->controls + idx;
if (cptr->info->skip_init) continue;
if (!cptr->info->set_value) continue;
@@ -1651,6 +1734,8 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
int valid_std_mask;
struct pvr2_ctrl *cptr;
__u8 ifnum;
+ struct v4l2_queryctrl qctrl;
+ struct pvr2_ctl_info *ciptr;
hdw_type = devid - pvr2_device_table;
if (hdw_type >=
@@ -1665,22 +1750,74 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
hdw,pvr2_device_names[hdw_type]);
if (!hdw) goto fail;
memset(hdw,0,sizeof(*hdw));
+ cx2341x_fill_defaults(&hdw->enc_ctl_state);
- hdw->controls = kmalloc(sizeof(struct pvr2_ctrl) * CTRL_COUNT,
+ hdw->control_cnt = CTRLDEF_COUNT;
+ hdw->control_cnt += MPEGDEF_COUNT;
+ hdw->controls = kmalloc(sizeof(struct pvr2_ctrl) * hdw->control_cnt,
GFP_KERNEL);
if (!hdw->controls) goto fail;
- memset(hdw->controls,0,sizeof(struct pvr2_ctrl) * CTRL_COUNT);
+ memset(hdw->controls,0,sizeof(struct pvr2_ctrl) * hdw->control_cnt);
hdw->hdw_type = hdw_type;
-
+ for (idx = 0; idx < hdw->control_cnt; idx++) {
+ cptr = hdw->controls + idx;
+ cptr->hdw = hdw;
+ }
for (idx = 0; idx < 32; idx++) {
hdw->std_mask_ptrs[idx] = hdw->std_mask_names[idx];
}
-
- for (idx = 0; idx < CTRL_COUNT; idx++) {
+ for (idx = 0; idx < CTRLDEF_COUNT; idx++) {
cptr = hdw->controls + idx;
- cptr->hdw = hdw;
cptr->info = control_defs+idx;
}
+ /* Define and configure additional controls from cx2341x module. */
+ hdw->mpeg_ctrl_info = kmalloc(
+ sizeof(*(hdw->mpeg_ctrl_info)) * MPEGDEF_COUNT, GFP_KERNEL);
+ if (!hdw->mpeg_ctrl_info) goto fail;
+ memset(hdw->mpeg_ctrl_info,0,
+ sizeof(*(hdw->mpeg_ctrl_info)) * MPEGDEF_COUNT);
+ for (idx = 0; idx < MPEGDEF_COUNT; idx++) {
+ cptr = hdw->controls + idx + CTRLDEF_COUNT;
+ ciptr = &(hdw->mpeg_ctrl_info[idx].info);
+ ciptr->desc = hdw->mpeg_ctrl_info[idx].desc;
+ ciptr->name = mpeg_ids[idx].strid;
+ ciptr->v4l_id = mpeg_ids[idx].id;
+ ciptr->skip_init = !0;
+ ciptr->get_value = ctrl_cx2341x_get;
+ ciptr->get_v4lflags = ctrl_cx2341x_getv4lflags;
+ ciptr->is_dirty = ctrl_cx2341x_is_dirty;
+ if (!idx) ciptr->clear_dirty = ctrl_cx2341x_clear_dirty;
+ qctrl.id = ciptr->v4l_id;
+ cx2341x_ctrl_query(&hdw->enc_ctl_state,&qctrl);
+ if (!(qctrl.flags & V4L2_CTRL_FLAG_READ_ONLY)) {
+ ciptr->set_value = ctrl_cx2341x_set;
+ }
+ strncpy(hdw->mpeg_ctrl_info[idx].desc,qctrl.name,
+ PVR2_CTLD_INFO_DESC_SIZE);
+ hdw->mpeg_ctrl_info[idx].desc[PVR2_CTLD_INFO_DESC_SIZE-1] = 0;
+ ciptr->default_value = qctrl.default_value;
+ switch (qctrl.type) {
+ default:
+ case V4L2_CTRL_TYPE_INTEGER:
+ ciptr->type = pvr2_ctl_int;
+ ciptr->def.type_int.min_value = qctrl.minimum;
+ ciptr->def.type_int.max_value = qctrl.maximum;
+ break;
+ case V4L2_CTRL_TYPE_BOOLEAN:
+ ciptr->type = pvr2_ctl_bool;
+ break;
+ case V4L2_CTRL_TYPE_MENU:
+ ciptr->type = pvr2_ctl_enum;
+ ciptr->def.type_enum.value_names =
+ cx2341x_ctrl_get_menu(ciptr->v4l_id);
+ for (cnt1 = 0;
+ ciptr->def.type_enum.value_names[cnt1] != NULL;
+ cnt1++) { }
+ ciptr->def.type_enum.count = cnt1;
+ break;
+ }
+ cptr->info = ciptr;
+ }
// Initialize video standard enum dynamic control
cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDENUM);
@@ -1783,6 +1920,7 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
if (hdw->ctl_read_buffer) kfree(hdw->ctl_read_buffer);
if (hdw->ctl_write_buffer) kfree(hdw->ctl_write_buffer);
if (hdw->controls) kfree(hdw->controls);
+ if (hdw->mpeg_ctrl_info) kfree(hdw->mpeg_ctrl_info);
kfree(hdw);
}
return 0;
@@ -1847,7 +1985,8 @@ void pvr2_hdw_destroy(struct pvr2_hdw *hdw)
unit_pointers[hdw->unit_number] = 0;
}
} while (0); up(&pvr2_unit_sem);
- kfree(hdw->controls);
+ if (hdw->controls) kfree(hdw->controls);
+ if (hdw->mpeg_ctrl_info) kfree(hdw->mpeg_ctrl_info);
if (hdw->std_defs) kfree(hdw->std_defs);
if (hdw->std_enum_names) kfree(hdw->std_enum_names);
kfree(hdw);
@@ -1953,7 +2092,7 @@ int pvr2_hdw_get_stdenum_value(struct pvr2_hdw *hdw,
/* Get the number of defined controls */
unsigned int pvr2_hdw_get_ctrl_count(struct pvr2_hdw *hdw)
{
- return CTRL_COUNT;
+ return hdw->control_cnt;
}
@@ -1961,7 +2100,7 @@ unsigned int pvr2_hdw_get_ctrl_count(struct pvr2_hdw *hdw)
struct pvr2_ctrl *pvr2_hdw_get_ctrl_by_index(struct pvr2_hdw *hdw,
unsigned int idx)
{
- if (idx >= CTRL_COUNT) return 0;
+ if (idx >= hdw->control_cnt) return 0;
return hdw->controls + idx;
}
@@ -1975,7 +2114,7 @@ struct pvr2_ctrl *pvr2_hdw_get_ctrl_by_id(struct pvr2_hdw *hdw,
int i;
/* This could be made a lot more efficient, but for now... */
- for (idx = 0; idx < CTRL_COUNT; idx++) {
+ for (idx = 0; idx < hdw->control_cnt; idx++) {
cptr = hdw->controls + idx;
i = cptr->info->internal_id;
if (i && (i == ctl_id)) return cptr;
@@ -1984,7 +2123,7 @@ struct pvr2_ctrl *pvr2_hdw_get_ctrl_by_id(struct pvr2_hdw *hdw,
}
-/* Given an ID, retrieve the control structure associated with it. */
+/* Given a V4L ID, retrieve the control structure associated with it. */
struct pvr2_ctrl *pvr2_hdw_get_ctrl_v4l(struct pvr2_hdw *hdw,unsigned int ctl_id)
{
struct pvr2_ctrl *cptr;
@@ -1992,7 +2131,7 @@ struct pvr2_ctrl *pvr2_hdw_get_ctrl_v4l(struct pvr2_hdw *hdw,unsigned int ctl_id
int i;
/* This could be made a lot more efficient, but for now... */
- for (idx = 0; idx < CTRL_COUNT; idx++) {
+ for (idx = 0; idx < hdw->control_cnt; idx++) {
cptr = hdw->controls + idx;
i = cptr->info->v4l_id;
if (i && (i == ctl_id)) return cptr;
@@ -2001,11 +2140,36 @@ struct pvr2_ctrl *pvr2_hdw_get_ctrl_v4l(struct pvr2_hdw *hdw,unsigned int ctl_id
}
+/* Given a V4L ID for its immediate predecessor, retrieve the control
+ structure associated with it. */
+struct pvr2_ctrl *pvr2_hdw_get_ctrl_nextv4l(struct pvr2_hdw *hdw,
+ unsigned int ctl_id)
+{
+ struct pvr2_ctrl *cptr,*cp2;
+ unsigned int idx;
+ int i;
+
+ /* This could be made a lot more efficient, but for now... */
+ cp2 = 0;
+ for (idx = 0; idx < hdw->control_cnt; idx++) {
+ cptr = hdw->controls + idx;
+ i = cptr->info->v4l_id;
+ if (!i) continue;
+ if (i <= ctl_id) continue;
+ if (cp2 && (cp2->info->v4l_id < i)) continue;
+ cp2 = cptr;
+ }
+ return cp2;
+ return 0;
+}
+
+
static const char *get_ctrl_typename(enum pvr2_ctl_type tp)
{
switch (tp) {
case pvr2_ctl_int: return "integer";
case pvr2_ctl_enum: return "enum";
+ case pvr2_ctl_bool: return "boolean";
case pvr2_ctl_bitmask: return "bitmask";
}
return "";
@@ -2030,7 +2194,7 @@ int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw)
char buf[100];
unsigned int bcnt,ccnt;
- for (idx = 0; idx < CTRL_COUNT; idx++) {
+ for (idx = 0; idx < hdw->control_cnt; idx++) {
cptr = hdw->controls + idx;
if (cptr->info->is_dirty == 0) continue;
if (!cptr->info->is_dirty(cptr)) continue;
@@ -2074,37 +2238,45 @@ int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw)
hdw->res_ver_val = nvres;
hdw->res_ver_dirty = !0;
}
- if (!hdw->interlace_val) {
- hdw->interlace_val = 0;
- hdw->interlace_dirty = !0;
- }
}
if (hdw->std_dirty ||
+#if 0 /* Don't toggle encoder for now - seems to work better this way */
+ hdw->enc_stale ||
+ hdw->srate_dirty ||
hdw->res_ver_dirty ||
hdw->res_hor_dirty ||
- hdw->interlace_dirty ||
- hdw->vbr_dirty ||
- hdw->videobitrate_dirty ||
- hdw->videopeak_dirty ||
- hdw->audiobitrate_dirty ||
- hdw->srate_dirty ||
- hdw->audiolayer_dirty ||
- hdw->audiocrc_dirty ||
- hdw->audioemphasis_dirty) {
+#endif
+ 0) {
/* If any of this changes, then the encoder needs to be
reconfigured, and we need to reset the stream. */
stale_subsys_mask |= (1<<PVR2_SUBSYS_B_ENC_CFG);
stale_subsys_mask |= hdw->subsys_stream_mask;
}
+ if (hdw->srate_dirty) {
+ /* Write new sample rate into control structure since
+ * the master copy is stale. We must track srate
+ * separate from the mpeg control structure because
+ * other logic also uses this value. */
+ struct v4l2_ext_controls cs;
+ struct v4l2_ext_control c1;
+ memset(&cs,0,sizeof(cs));
+ memset(&c1,0,sizeof(c1));
+ cs.controls = &c1;
+ cs.count = 1;
+ c1.id = V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ;
+ c1.value = hdw->srate_val;
+ cx2341x_ext_ctrls(&hdw->enc_ctl_state,&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);
- for (idx = 0; idx < CTRL_COUNT; idx++) {
+ for (idx = 0; idx < hdw->control_cnt; idx++) {
cptr = hdw->controls + idx;
if (!cptr->info->clear_dirty) continue;
cptr->info->clear_dirty(cptr);
@@ -2234,11 +2406,16 @@ struct pvr2_stream *pvr2_hdw_get_video_stream(struct pvr2_hdw *hp)
void pvr2_hdw_trigger_module_log(struct pvr2_hdw *hdw)
{
+ int nr = pvr2_hdw_get_unit_number(hdw);
LOCK_TAKE(hdw->big_lock); do {
hdw->log_requested = !0;
+ printk(KERN_INFO "pvrusb2: ================= START STATUS CARD #%d =================\n", nr);
pvr2_i2c_core_check_stale(hdw);
hdw->log_requested = 0;
pvr2_i2c_core_sync(hdw);
+ pvr2_trace(PVR2_TRACE_INFO,"cx2341x config:");
+ cx2341x_log_status(&hdw->enc_ctl_state,0);
+ printk(KERN_INFO "pvrusb2: ================== END STATUS CARD #%d ==================\n", nr);
} while (0); LOCK_GIVE(hdw->big_lock);
}
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.h
index ba70f5d48..310fe9d3d 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.h
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.h
@@ -27,16 +27,6 @@
#include "pvrusb2-io.h"
#include "pvrusb2-ctrl.h"
-/* Private V4L2-compatible controls available in this driver, look these up
- with pvr2_hdw_get_ctrl_v4l(). */
-#define V4L2_CID_PVR_SRATE (V4L2_CID_PRIVATE_BASE)
-#define V4L2_CID_PVR_AUDIOBITRATE (V4L2_CID_PRIVATE_BASE+1)
-#define V4L2_CID_PVR_AUDIOCRC (V4L2_CID_PRIVATE_BASE+2)
-#define V4L2_CID_PVR_AUDIOEMPHASIS (V4L2_CID_PRIVATE_BASE+3)
-#define V4L2_CID_PVR_VBR (V4L2_CID_PRIVATE_BASE+4)
-#define V4L2_CID_PVR_VIDEOBITRATE (V4L2_CID_PRIVATE_BASE+5)
-#define V4L2_CID_PVR_VIDEOPEAK (V4L2_CID_PRIVATE_BASE+6)
-#define V4L2_CID_PVR_VIDEOSTANDARD (V4L2_CID_PRIVATE_BASE+7)
/* Private internal control ids, look these up with
pvr2_hdw_get_ctrl_by_id() - these are NOT visible in V4L */
@@ -48,7 +38,6 @@
#define PVR2_CID_FREQUENCY 6
#define PVR2_CID_HRES 7
#define PVR2_CID_VRES 8
-#define PVR2_CID_INTERLACE 9
/* Legal values for the INPUT state variable */
#define PVR2_CVAL_INPUT_TV 0
@@ -154,6 +143,10 @@ struct pvr2_ctrl *pvr2_hdw_get_ctrl_by_id(struct pvr2_hdw *,unsigned int);
/* Retrieve a control handle given its V4L ID (if any) */
struct pvr2_ctrl *pvr2_hdw_get_ctrl_v4l(struct pvr2_hdw *,unsigned int ctl_id);
+/* Retrieve a control handle given its immediate predecessor V4L ID (if any) */
+struct pvr2_ctrl *pvr2_hdw_get_ctrl_nextv4l(struct pvr2_hdw *,
+ unsigned int ctl_id);
+
/* Commit all control changes made up to this point */
int pvr2_hdw_commit_ctl(struct pvr2_hdw *);
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-main.c b/linux/drivers/media/video/pvrusb2/pvrusb2-main.c
index 245f7a36d..b81b5a62e 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-main.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-main.c
@@ -47,14 +47,6 @@
PVR2_TRACE_INFO| \
PVR2_TRACE_TOLERANCE| \
PVR2_TRACE_TRAP| \
- PVR2_TRACE_FIRMWARE| \
- PVR2_TRACE_EEPROM | \
- PVR2_TRACE_INIT | \
- PVR2_TRACE_I2C | \
- PVR2_TRACE_CHIPS | \
- PVR2_TRACE_START_STOP | \
- PVR2_TRACE_CTL | \
- PVR2_TRACE_DEBUGIFC | \
0)
int pvrusb2_debug = DEFAULT_DEBUG_MASK;
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-std.c b/linux/drivers/media/video/pvrusb2/pvrusb2-std.c
index 64ba223c2..134063693 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-std.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-std.c
@@ -21,6 +21,8 @@
#include "pvrusb2-std.h"
#include "pvrusb2-debug.h"
+#include <asm/string.h>
+#include <linux/slab.h>
struct std_name {
const char *name;
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/linux/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
index 075882877..812a779c8 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
@@ -56,6 +56,7 @@ struct pvr2_sysfs_debugifc {
struct pvr2_sysfs_ctl_item {
struct class_device_attribute attr_name;
+ struct class_device_attribute attr_type;
struct class_device_attribute attr_min;
struct class_device_attribute attr_max;
struct class_device_attribute attr_enum;
@@ -65,7 +66,7 @@ struct pvr2_sysfs_ctl_item {
struct pvr2_ctrl *cptr;
struct pvr2_sysfs *chptr;
struct pvr2_sysfs_ctl_item *item_next;
- struct attribute *attr_gen[6];
+ struct attribute *attr_gen[7];
struct attribute_group grp;
char name[80];
};
@@ -93,6 +94,33 @@ static ssize_t show_name(int id,struct class_device *class_dev,char *buf)
return scnprintf(buf,PAGE_SIZE,"%s\n",name);
}
+static ssize_t show_type(int id,struct class_device *class_dev,char *buf)
+{
+ struct pvr2_ctrl *cptr;
+ struct pvr2_sysfs *sfp;
+ const char *name;
+ enum pvr2_ctl_type tp;
+
+ sfp = (struct pvr2_sysfs *)class_dev->class_data;
+ if (!sfp) return -EINVAL;
+ cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
+ if (!cptr) return -EINVAL;
+
+ tp = pvr2_ctrl_get_type(cptr);
+ switch (tp) {
+ case pvr2_ctl_int: name = "integer"; break;
+ case pvr2_ctl_enum: name = "enum"; break;
+ case pvr2_ctl_bitmask: name = "bitmask"; break;
+ case pvr2_ctl_bool: name = "boolean"; break;
+ default: name = "?"; break;
+ }
+ pvr2_sysfs_trace("pvr2_sysfs(%p) show_type(cid=%d) is %s",sfp,id,name);
+
+ if (!name) return -EINVAL;
+
+ return scnprintf(buf,PAGE_SIZE,"%s\n",name);
+}
+
static ssize_t show_min(int id,struct class_device *class_dev,char *buf)
{
struct pvr2_ctrl *cptr;
@@ -190,6 +218,7 @@ static ssize_t show_enum(int id,struct class_device *class_dev,char *buf)
bcnt = 0;
for (val = 0; val < ecnt; val++) {
pvr2_ctrl_get_valname(cptr,val,buf+bcnt,PAGE_SIZE-bcnt,&ccnt);
+ if (!ccnt) continue;
bcnt += ccnt;
if (bcnt >= PAGE_SIZE) break;
buf[bcnt] = '\n';
@@ -289,6 +318,7 @@ static ssize_t sf_name##_##ctl_id(struct class_device *class_dev,const char *buf
#define CREATE_BATCH(ctl_id) \
CREATE_SHOW_INSTANCE(show_name,ctl_id) \
+CREATE_SHOW_INSTANCE(show_type,ctl_id) \
CREATE_SHOW_INSTANCE(show_min,ctl_id) \
CREATE_SHOW_INSTANCE(show_max,ctl_id) \
CREATE_SHOW_INSTANCE(show_val_norm,ctl_id) \
@@ -332,9 +362,36 @@ CREATE_BATCH(30)
CREATE_BATCH(31)
CREATE_BATCH(32)
CREATE_BATCH(33)
+CREATE_BATCH(34)
+CREATE_BATCH(35)
+CREATE_BATCH(36)
+CREATE_BATCH(37)
+CREATE_BATCH(38)
+CREATE_BATCH(39)
+CREATE_BATCH(40)
+CREATE_BATCH(41)
+CREATE_BATCH(42)
+CREATE_BATCH(43)
+CREATE_BATCH(44)
+CREATE_BATCH(45)
+CREATE_BATCH(46)
+CREATE_BATCH(47)
+CREATE_BATCH(48)
+CREATE_BATCH(49)
+CREATE_BATCH(50)
+CREATE_BATCH(51)
+CREATE_BATCH(52)
+CREATE_BATCH(53)
+CREATE_BATCH(54)
+CREATE_BATCH(55)
+CREATE_BATCH(56)
+CREATE_BATCH(57)
+CREATE_BATCH(58)
+CREATE_BATCH(59)
struct pvr2_sysfs_func_set {
ssize_t (*show_name)(struct class_device *,char *);
+ ssize_t (*show_type)(struct class_device *,char *);
ssize_t (*show_min)(struct class_device *,char *);
ssize_t (*show_max)(struct class_device *,char *);
ssize_t (*show_enum)(struct class_device *,char *);
@@ -350,6 +407,7 @@ struct pvr2_sysfs_func_set {
#define INIT_BATCH(ctl_id) \
[ctl_id] = { \
.show_name = show_name_##ctl_id, \
+ .show_type = show_type_##ctl_id, \
.show_min = show_min_##ctl_id, \
.show_max = show_max_##ctl_id, \
.show_enum = show_enum_##ctl_id, \
@@ -395,6 +453,32 @@ static struct pvr2_sysfs_func_set funcs[] = {
INIT_BATCH(31),
INIT_BATCH(32),
INIT_BATCH(33),
+ INIT_BATCH(34),
+ INIT_BATCH(35),
+ INIT_BATCH(36),
+ INIT_BATCH(37),
+ INIT_BATCH(38),
+ INIT_BATCH(39),
+ INIT_BATCH(40),
+ INIT_BATCH(41),
+ INIT_BATCH(42),
+ INIT_BATCH(43),
+ INIT_BATCH(44),
+ INIT_BATCH(45),
+ INIT_BATCH(46),
+ INIT_BATCH(47),
+ INIT_BATCH(48),
+ INIT_BATCH(49),
+ INIT_BATCH(50),
+ INIT_BATCH(51),
+ INIT_BATCH(52),
+ INIT_BATCH(53),
+ INIT_BATCH(54),
+ INIT_BATCH(55),
+ INIT_BATCH(56),
+ INIT_BATCH(57),
+ INIT_BATCH(58),
+ INIT_BATCH(59),
};
@@ -434,6 +518,11 @@ static void pvr2_sysfs_add_control(struct pvr2_sysfs *sfp,int ctl_id)
cip->attr_name.attr.mode = S_IRUGO;
cip->attr_name.show = fp->show_name;
+ cip->attr_type.attr.owner = THIS_MODULE;
+ cip->attr_type.attr.name = "type";
+ cip->attr_type.attr.mode = S_IRUGO;
+ cip->attr_type.show = fp->show_type;
+
cip->attr_min.attr.owner = THIS_MODULE;
cip->attr_min.attr.name = "min_val";
cip->attr_min.attr.mode = S_IRUGO;
@@ -469,6 +558,7 @@ static void pvr2_sysfs_add_control(struct pvr2_sysfs *sfp,int ctl_id)
acnt = 0;
cip->attr_gen[acnt++] = &cip->attr_name.attr;
+ cip->attr_gen[acnt++] = &cip->attr_type.attr;
cip->attr_gen[acnt++] = &cip->attr_val.attr;
cip->attr_val.show = fp->show_val_norm;
cip->attr_val.store = fp->store_val_norm;
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
index 78cdd01c8..01d8d8f4a 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
@@ -450,12 +450,6 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
vf->fmt.pix.width = val;
val = 0;
pvr2_ctrl_get_value(
- pvr2_hdw_get_ctrl_by_id(hdw,
- PVR2_CID_INTERLACE),
- &val);
- if (val) vf->fmt.pix.width /= 2;
- val = 0;
- pvr2_ctrl_get_value(
pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_VRES),
&val);
vf->fmt.pix.height = val;
@@ -482,25 +476,22 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
int h = vf->fmt.pix.height;
int w = vf->fmt.pix.width;
- int vd_std, hf, hh;
- vd_std = 0;
- pvr2_ctrl_get_value(
- pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDCUR),
- &vd_std);
- if (vd_std & V4L2_STD_525_60) {
- hf=480;
- } else {
- hf=576;
+ if (h < 200) {
+ h = 200;
+ } else if (h > 625) {
+ h = 625;
+ }
+ if (w < 320) {
+ w = 320;
+ } else if (w > 720) {
+ w = 720;
}
- hh = (int) (hf / 2);
memcpy(vf, &pvr_format[PVR_FORMAT_PIX],
sizeof(struct v4l2_format));
- if (w > 720)
- vf->fmt.pix.width = 720;
- vf->fmt.pix.width &= 0xff0;
- vf->fmt.pix.height = (h > hh) ? hf : hh;
+ vf->fmt.pix.width = w;
+ vf->fmt.pix.height = h;
if (cmd == VIDIOC_S_FMT) {
pvr2_ctrl_set_value(
@@ -511,10 +502,6 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
pvr2_hdw_get_ctrl_by_id(hdw,
PVR2_CID_VRES),
vf->fmt.pix.height);
- pvr2_ctrl_set_value(
- pvr2_hdw_get_ctrl_by_id(
- hdw,PVR2_CID_INTERLACE),
- vf->fmt.pix.height != hf);
}
} break;
case V4L2_BUF_TYPE_VBI_CAPTURE:
@@ -547,13 +534,27 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
struct pvr2_ctrl *cptr;
struct v4l2_queryctrl *vc = (struct v4l2_queryctrl *)arg;
ret = 0;
- cptr = pvr2_hdw_get_ctrl_v4l(hdw,vc->id);
+ if (vc->id & V4L2_CTRL_FLAG_NEXT_CTRL) {
+ cptr = pvr2_hdw_get_ctrl_nextv4l(
+ hdw,(vc->id & ~V4L2_CTRL_FLAG_NEXT_CTRL));
+ if (cptr) vc->id = pvr2_ctrl_get_v4lid(cptr);
+ } else {
+ cptr = pvr2_hdw_get_ctrl_v4l(hdw,vc->id);
+ }
if (!cptr) {
+ pvr2_trace(PVR2_TRACE_V4LIOCTL,
+ "QUERYCTRL id=0x%x not implemented here",
+ vc->id);
ret = -EINVAL;
break;
}
- strlcpy(vc->name,pvr2_ctrl_get_name(cptr),sizeof(vc->name));
+ pvr2_trace(PVR2_TRACE_V4LIOCTL,
+ "QUERYCTRL id=0x%x mapping name=%s (%s)",
+ vc->id,pvr2_ctrl_get_name(cptr),
+ pvr2_ctrl_get_desc(cptr));
+ strlcpy(vc->name,pvr2_ctrl_get_desc(cptr),sizeof(vc->name));
+ vc->flags = pvr2_ctrl_get_v4lflags(cptr);
vc->default_value = pvr2_ctrl_get_def(cptr);
switch (pvr2_ctrl_get_type(cptr)) {
case pvr2_ctl_enum:
@@ -562,6 +563,12 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
vc->maximum = pvr2_ctrl_get_cnt(cptr) - 1;
vc->step = 1;
break;
+ case pvr2_ctl_bool:
+ vc->type = V4L2_CTRL_TYPE_BOOLEAN;
+ vc->minimum = 0;
+ vc->maximum = 1;
+ vc->step = 1;
+ break;
case pvr2_ctl_int:
vc->type = V4L2_CTRL_TYPE_INTEGER;
vc->minimum = pvr2_ctrl_get_min(cptr);
@@ -569,6 +576,9 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
vc->step = 1;
break;
default:
+ pvr2_trace(PVR2_TRACE_V4LIOCTL,
+ "QUERYCTRL id=0x%x name=%s not mappable",
+ vc->id,pvr2_ctrl_get_name(cptr));
ret = -EINVAL;
break;
}
@@ -605,13 +615,72 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
break;
}
- case VIDIOC_LOG_STATUS:
+ case VIDIOC_G_EXT_CTRLS:
+ {
+ struct v4l2_ext_controls *ctls =
+ (struct v4l2_ext_controls *)arg;
+ struct v4l2_ext_control *ctrl;
+ unsigned int idx;
+ int val;
+ for (idx = 0; idx < ctls->count; idx++) {
+ ctrl = ctls->controls + idx;
+ ret = pvr2_ctrl_get_value(
+ pvr2_hdw_get_ctrl_v4l(hdw,ctrl->id),&val);
+ if (ret) {
+ ctls->error_idx = idx;
+ break;
+ }
+ /* Ensure that if read as a 64 bit value, the user
+ will still get a hopefully sane value */
+ ctrl->value64 = 0;
+ ctrl->value = val;
+ }
+ break;
+ }
+
+ case VIDIOC_S_EXT_CTRLS:
+ {
+ struct v4l2_ext_controls *ctls =
+ (struct v4l2_ext_controls *)arg;
+ struct v4l2_ext_control *ctrl;
+ unsigned int idx;
+ for (idx = 0; idx < ctls->count; idx++) {
+ ctrl = ctls->controls + idx;
+ ret = pvr2_ctrl_set_value(
+ pvr2_hdw_get_ctrl_v4l(hdw,ctrl->id),
+ ctrl->value);
+ if (ret) {
+ ctls->error_idx = idx;
+ break;
+ }
+ }
+ break;
+ }
+
+ case VIDIOC_TRY_EXT_CTRLS:
{
- int nr = pvr2_hdw_get_unit_number(hdw);
+ struct v4l2_ext_controls *ctls =
+ (struct v4l2_ext_controls *)arg;
+ struct v4l2_ext_control *ctrl;
+ struct pvr2_ctrl *pctl;
+ unsigned int idx;
+ /* For the moment just validate that the requested control
+ actually exists. */
+ for (idx = 0; idx < ctls->count; idx++) {
+ ctrl = ctls->controls + idx;
+ pctl = pvr2_hdw_get_ctrl_v4l(hdw,ctrl->id);
+ if (!pctl) {
+ ret = -EINVAL;
+ ctls->error_idx = idx;
+ break;
+ }
+ }
+ break;
+ }
- printk(KERN_INFO "pvrusb2: ================= START STATUS CARD #%d =================\n", nr);
+ case VIDIOC_LOG_STATUS:
+ {
pvr2_hdw_trigger_module_log(hdw);
- printk(KERN_INFO "pvrusb2: ================== END STATUS CARD #%d ==================\n", nr);
ret = 0;
break;
}
@@ -625,11 +694,11 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
if (ret < 0) {
if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) {
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ pvr2_trace(PVR2_TRACE_V4LIOCTL,
"pvr2_v4l2_do_ioctl failure, ret=%d",ret);
} else {
- if (pvrusb2_debug & PVR2_TRACE_ERROR_LEGS) {
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) {
+ pvr2_trace(PVR2_TRACE_V4LIOCTL,
"pvr2_v4l2_do_ioctl failure, ret=%d"
" command was:",ret);
v4l_print_ioctl(pvr2_hdw_get_driver_name(hdw),
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c b/linux/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c
index 4127c82f7..e4ec7f251 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c
@@ -91,12 +91,15 @@ static void set_audio(struct pvr2_v4l_decoder *ctxt)
hdw->srate_val);
switch (hdw->srate_val) {
default:
- case PVR2_CVAL_SRATE_48:
+ case V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000:
val = 48000;
break;
- case PVR2_CVAL_SRATE_44_1:
+ case V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100:
val = 44100;
break;
+ case V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000:
+ val = 32000;
+ break;
}
pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_AUDIO_CLOCK_FREQ,&val);
}