summaryrefslogtreecommitdiff
path: root/linux/drivers/media/video/pvrusb2
diff options
context:
space:
mode:
authorrmcc@localhost.localdomain <rmcc@localhost.localdomain>2006-05-18 16:06:06 +0100
committerrmcc@localhost.localdomain <rmcc@localhost.localdomain>2006-05-18 16:06:06 +0100
commitaad2e973e44590acd4c1b55dd32eadad842e7fdb (patch)
treede152190bd763eb849cf2952cfb468169f3881ba /linux/drivers/media/video/pvrusb2
parentf637ab4e875bd28b68bbd4d776c2071683050b5c (diff)
parent122bd90fa6f72e1366146662e7fb9a6581aab68e (diff)
downloadmediapointer-dvb-s2-aad2e973e44590acd4c1b55dd32eadad842e7fdb.tar.gz
mediapointer-dvb-s2-aad2e973e44590acd4c1b55dd32eadad842e7fdb.tar.bz2
merge: from master
From: Ricardo Cerqueira <v4l@cerqueira.org> merging master changes Signed-off-by: Ricardo Cerqueira <v4l@cerqueira.org>
Diffstat (limited to 'linux/drivers/media/video/pvrusb2')
-rw-r--r--linux/drivers/media/video/pvrusb2/Kconfig49
-rw-r--r--linux/drivers/media/video/pvrusb2/Makefile15
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-audio.c43
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-context.c2
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-context.h3
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-ctrl.c549
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-ctrl.h115
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c276
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.h54
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-debugifc.c14
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-demod.c2
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-eeprom.c118
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-eeprom.h1
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-encoder.c88
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h177
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c1433
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-hdw.h186
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c18
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c101
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h2
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c234
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-io.c3
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-ioread.c3
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-main.c20
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-std.c406
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-std.h61
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-sysfs.c478
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-tuner.c2
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c478
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c19
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-wm8775.c170
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-wm8775.h54
32 files changed, 3620 insertions, 1554 deletions
diff --git a/linux/drivers/media/video/pvrusb2/Kconfig b/linux/drivers/media/video/pvrusb2/Kconfig
index 9824ad267..207efa6c0 100644
--- a/linux/drivers/media/video/pvrusb2/Kconfig
+++ b/linux/drivers/media/video/pvrusb2/Kconfig
@@ -1,6 +1,6 @@
config VIDEO_PVRUSB2
tristate "Hauppauge WinTV-PVR USB2 support"
- depends on VIDEO_DEV && USB && I2C && EXPERIMENTAL
+ depends on VIDEO_V4L1 && USB && I2C && EXPERIMENTAL
select FW_LOADER
select VIDEO_TUNER
select VIDEO_TVEEPROM
@@ -12,3 +12,50 @@ config VIDEO_PVRUSB2
To compile this driver as a module, choose M here: the
module will be called pvrusb2
+
+config VIDEO_PVRUSB2_24XXX
+ bool "Hauppauge WinTV-PVR USB2 support for 24xxx model series"
+ depends on VIDEO_PVRUSB2 && EXPERIMENTAL
+ select VIDEO_CX25840
+ select VIDEO_WM8775
+ ---help---
+ This option enables inclusion of additional logic to operate
+ newer WinTV-PVR USB2 devices whose model number is of the
+ form "24xxx" (leading prefix of "24" followed by 3 digits).
+ To see if you may need this option, examine the white
+ sticker on the underside of your device. Enabling this
+ option will not harm support for older devices, however it
+ is a separate option because of the experimental nature of
+ this new feature.
+
+ If you are in doubt, say N.
+
+ Note: This feature is _very_ experimental. You have been
+ warned.
+
+config VIDEO_PVRUSB2_SYSFS
+ bool "pvrusb2 sysfs support"
+ default y
+ depends on VIDEO_PVRUSB2 && SYSFS && EXPERIMENTAL
+ ---help---
+ This option enables the operation of a sysfs based
+ interface for query and control of the pvrusb2 driver.
+
+ This is not generally needed for v4l applications,
+ although certain applications are optimized to take
+ advantage of this feature.
+
+ If you are in doubt, say Y.
+
+ Note: This feature is experimental and subject to change.
+
+config VIDEO_PVRUSB2_DEBUGIFC
+ bool "pvrusb2 debug interface"
+ depends on VIDEO_PVRUSB2_SYSFS
+ ---help---
+ This option enables the inclusion of a debug interface
+ in the pvrusb2 driver, hosted through sysfs.
+
+ You do not need to select this option unless you plan
+ on debugging the driver or performing a manual firmware
+ extraction.
diff --git a/linux/drivers/media/video/pvrusb2/Makefile b/linux/drivers/media/video/pvrusb2/Makefile
index c83742fb1..fed603ad0 100644
--- a/linux/drivers/media/video/pvrusb2/Makefile
+++ b/linux/drivers/media/video/pvrusb2/Makefile
@@ -1,11 +1,18 @@
+obj-pvrusb2-sysfs-$(CONFIG_VIDEO_PVRUSB2_SYSFS) := pvrusb2-sysfs.o
+obj-pvrusb2-debugifc-$(CONFIG_VIDEO_PVRUSB2_DEBUGIFC) := pvrusb2-debugifc.o
+
+obj-pvrusb2-24xxx-$(CONFIG_VIDEO_PVRUSB2_24XXX) := \
+ pvrusb2-cx2584x-v4l.o \
+ pvrusb2-wm8775.o
+
pvrusb2-objs := pvrusb2-i2c-core.o pvrusb2-i2c-cmd-v4l2.o \
pvrusb2-audio.o pvrusb2-i2c-chips-v4l2.o \
pvrusb2-encoder.o pvrusb2-video-v4l.o \
pvrusb2-eeprom.o pvrusb2-tuner.o pvrusb2-demod.o \
pvrusb2-main.o pvrusb2-hdw.o pvrusb2-v4l2.o \
- pvrusb2-sysfs.o pvrusb2-context.o pvrusb2-io.o \
- pvrusb2-ioread.o pvrusb2-debugifc.o
+ pvrusb2-ctrl.o pvrusb2-std.o \
+ pvrusb2-context.o pvrusb2-io.o pvrusb2-ioread.o \
+ $(obj-pvrusb2-24xxx-y) \
+ $(obj-pvrusb2-sysfs-y) $(obj-pvrusb2-debugifc-y)
obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2.o
-
-EXTRA_CFLAGS += -I$(src)/..
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-audio.c b/linux/drivers/media/video/pvrusb2/pvrusb2-audio.c
index 79395d540..30e3a38f6 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-audio.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-audio.c
@@ -24,7 +24,7 @@
#include "pvrusb2-audio.h"
#include "pvrusb2-hdw-internal.h"
#include "pvrusb2-debug.h"
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
#include <media/msp3400.h>
#include <media/v4l2-common.h>
@@ -37,26 +37,6 @@ struct pvr2_msp3400_handler {
};
-static int xlat_audiomode_to_v4l2(int id)
-{
- switch (id) {
- case PVR2_CVAL_AUDIOMODE_MONO:
- return V4L2_TUNER_MODE_MONO;
- case PVR2_CVAL_AUDIOMODE_STEREO:
- return V4L2_TUNER_MODE_STEREO;
- case PVR2_CVAL_AUDIOMODE_SAP:
- return V4L2_TUNER_MODE_SAP;
- case PVR2_CVAL_AUDIOMODE_LANG1:
- return V4L2_TUNER_MODE_LANG1;
- case PVR2_CVAL_AUDIOMODE_LANG2:
- return V4L2_TUNER_MODE_LANG2;
- case PVR2_CVAL_AUDIOMODE_LANG1_LANG2:
- return V4L2_TUNER_MODE_LANG1_LANG2;
- }
- return V4L2_TUNER_MODE_STEREO;
-}
-
-
/* This function selects the correct audio input source */
static void set_stereo(struct pvr2_msp3400_handler *ctxt)
{
@@ -65,17 +45,16 @@ static void set_stereo(struct pvr2_msp3400_handler *ctxt)
pvr2_trace(PVR2_TRACE_CHIPS,"i2c msp3400 v4l2 set_stereo");
- if (hdw->controls[PVR2_CID_INPUT].value == PVR2_CVAL_INPUT_TV) {
+ if (hdw->input_val == PVR2_CVAL_INPUT_TV) {
struct v4l2_tuner vt;
memset(&vt,0,sizeof(vt));
- vt.audmode = xlat_audiomode_to_v4l2(
- hdw->controls[PVR2_CID_AUDIOMODE].value);
+ vt.audmode = hdw->audiomode_val;
pvr2_i2c_client_cmd(ctxt->client,VIDIOC_S_TUNER,&vt);
}
route.input = MSP_INPUT_DEFAULT;
- route.output = MSP_OUTPUT(MSP_OUT_SCART1_DA);
- switch (hdw->controls[PVR2_CID_INPUT].value) {
+ route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1);
+ switch (hdw->input_val) {
case PVR2_CVAL_INPUT_TV:
break;
case PVR2_CVAL_INPUT_RADIO:
@@ -83,14 +62,14 @@ static void set_stereo(struct pvr2_msp3400_handler *ctxt)
we're still using the tuner. */
/* HV: actually it is more likely to be the SCART2 input if
the ivtv experience is any indication. */
- route.input = MSP_INPUT(MSP_IN_SCART_2, MSP_IN_TUNER_1,
- MSP_DSP_OUT_SCART, MSP_DSP_OUT_SCART);
+ route.input = MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1,
+ MSP_DSP_IN_SCART, MSP_DSP_IN_SCART);
break;
case PVR2_CVAL_INPUT_SVIDEO:
case PVR2_CVAL_INPUT_COMPOSITE:
/* SCART 1 input */
- route.input = MSP_INPUT(MSP_IN_SCART_1, MSP_IN_TUNER_1,
- MSP_DSP_OUT_SCART, MSP_DSP_OUT_SCART);
+ route.input = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1,
+ MSP_DSP_IN_SCART, MSP_DSP_IN_SCART);
break;
}
pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_S_AUDIO_ROUTING,&route);
@@ -100,8 +79,8 @@ static void set_stereo(struct pvr2_msp3400_handler *ctxt)
static int check_stereo(struct pvr2_msp3400_handler *ctxt)
{
struct pvr2_hdw *hdw = ctxt->hdw;
- return ((hdw->controls[PVR2_CID_INPUT].dirty != 0)||
- (hdw->controls[PVR2_CID_AUDIOMODE].dirty != 0));
+ return (hdw->input_dirty ||
+ hdw->audiomode_dirty);
}
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-context.c b/linux/drivers/media/video/pvrusb2/pvrusb2-context.c
index f3fd61f21..40dc59871 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-context.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-context.c
@@ -47,11 +47,9 @@ static void pvr2_context_trigger_poll(struct pvr2_context *mp)
static void pvr2_context_poll(struct pvr2_context *mp)
{
- pvr2_trace(PVR2_TRACE_DEBUG,"pvr2_context_poll BEGIN");
pvr2_context_enter(mp); do {
pvr2_hdw_poll(mp->hdw);
} while (0); pvr2_context_exit(mp);
- pvr2_trace(PVR2_TRACE_DEBUG,"pvr2_context_poll END");
}
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-context.h b/linux/drivers/media/video/pvrusb2/pvrusb2-context.h
index 910086ba2..69c1f3a92 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-context.h
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-context.h
@@ -22,8 +22,7 @@
#include "compat.h"
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
-#include <asm/atomic.h>
-#include <asm/mutex.h>
+#include <linux/mutex.h>
#else
#include <asm/semaphore.h>
#endif
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-ctrl.c b/linux/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
new file mode 100644
index 000000000..e55f43e44
--- /dev/null
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
@@ -0,0 +1,549 @@
+/*
+ *
+ * $Id$
+ *
+ * Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include "pvrusb2-ctrl.h"
+#include "pvrusb2-hdw-internal.h"
+#include "compat.h"
+#include <linux/errno.h>
+#include <linux/string.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
+#include <linux/mutex.h>
+#else
+#include <asm/semaphore.h>
+#endif
+
+
+/* Set the given control. */
+int pvr2_ctrl_set_value(struct pvr2_ctrl *cptr,int val)
+{
+ return pvr2_ctrl_set_mask_value(cptr,~0,val);
+}
+
+
+/* Set/clear specific bits of the given control. */
+int pvr2_ctrl_set_mask_value(struct pvr2_ctrl *cptr,int mask,int val)
+{
+ int ret = 0;
+ if (!cptr) return -EINVAL;
+ LOCK_TAKE(cptr->hdw->big_lock); do {
+ if (cptr->info->set_value != 0) {
+ if (cptr->info->type == pvr2_ctl_bitmask) {
+ mask &= cptr->info->def.type_bitmask.valid_bits;
+ } else if (cptr->info->type == pvr2_ctl_int) {
+ if (val < cptr->info->def.type_int.min_value) {
+ break;
+ }
+ if (val > cptr->info->def.type_int.max_value) {
+ break;
+ }
+ } else if (cptr->info->type == pvr2_ctl_enum) {
+ if (val >= cptr->info->def.type_enum.count) {
+ break;
+ }
+ }
+ ret = cptr->info->set_value(cptr,mask,val);
+ } else {
+ ret = -EPERM;
+ }
+ } while(0); LOCK_GIVE(cptr->hdw->big_lock);
+ return ret;
+}
+
+
+/* Get the current value of the given control. */
+int pvr2_ctrl_get_value(struct pvr2_ctrl *cptr,int *valptr)
+{
+ int ret = 0;
+ if (!cptr) return -EINVAL;
+ LOCK_TAKE(cptr->hdw->big_lock); do {
+ ret = cptr->info->get_value(cptr,valptr);
+ } while(0); LOCK_GIVE(cptr->hdw->big_lock);
+ return ret;
+}
+
+
+/* Retrieve control's type */
+enum pvr2_ctl_type pvr2_ctrl_get_type(struct pvr2_ctrl *cptr)
+{
+ if (!cptr) return pvr2_ctl_int;
+ return cptr->info->type;
+}
+
+
+/* Retrieve control's maximum value (int type) */
+int pvr2_ctrl_get_max(struct pvr2_ctrl *cptr)
+{
+ int ret = 0;
+ if (!cptr) return 0;
+ LOCK_TAKE(cptr->hdw->big_lock); do {
+ if (cptr->info->type == pvr2_ctl_int) {
+ ret = cptr->info->def.type_int.max_value;
+ }
+ } while(0); LOCK_GIVE(cptr->hdw->big_lock);
+ return ret;
+}
+
+
+/* Retrieve control's minimum value (int type) */
+int pvr2_ctrl_get_min(struct pvr2_ctrl *cptr)
+{
+ int ret = 0;
+ if (!cptr) return 0;
+ LOCK_TAKE(cptr->hdw->big_lock); do {
+ if (cptr->info->type == pvr2_ctl_int) {
+ ret = cptr->info->def.type_int.min_value;
+ }
+ } while(0); LOCK_GIVE(cptr->hdw->big_lock);
+ return ret;
+}
+
+
+/* Retrieve control's default value (any type) */
+int pvr2_ctrl_get_def(struct pvr2_ctrl *cptr)
+{
+ int ret = 0;
+ if (!cptr) return 0;
+ LOCK_TAKE(cptr->hdw->big_lock); do {
+ if (cptr->info->type == pvr2_ctl_int) {
+ ret = cptr->info->default_value;
+ }
+ } while(0); LOCK_GIVE(cptr->hdw->big_lock);
+ return ret;
+}
+
+
+/* Retrieve control's enumeration count (enum only) */
+int pvr2_ctrl_get_cnt(struct pvr2_ctrl *cptr)
+{
+ int ret = 0;
+ if (!cptr) return 0;
+ LOCK_TAKE(cptr->hdw->big_lock); do {
+ if (cptr->info->type == pvr2_ctl_enum) {
+ ret = cptr->info->def.type_enum.count;
+ }
+ } while(0); LOCK_GIVE(cptr->hdw->big_lock);
+ return ret;
+}
+
+
+/* Retrieve control's valid mask bits (bit mask only) */
+int pvr2_ctrl_get_mask(struct pvr2_ctrl *cptr)
+{
+ int ret = 0;
+ if (!cptr) return 0;
+ LOCK_TAKE(cptr->hdw->big_lock); do {
+ if (cptr->info->type == pvr2_ctl_bitmask) {
+ ret = cptr->info->def.type_bitmask.valid_bits;
+ }
+ } while(0); LOCK_GIVE(cptr->hdw->big_lock);
+ return ret;
+}
+
+
+/* Retrieve the control's name */
+const char *pvr2_ctrl_get_name(struct pvr2_ctrl *cptr)
+{
+ if (!cptr) return 0;
+ return cptr->info->name;
+}
+
+
+/* Retrieve the control's desc */
+const char *pvr2_ctrl_get_desc(struct pvr2_ctrl *cptr)
+{
+ if (!cptr) return 0;
+ return cptr->info->desc;
+}
+
+
+/* Retrieve a control enumeration or bit mask value */
+int pvr2_ctrl_get_valname(struct pvr2_ctrl *cptr,int val,
+ char *bptr,unsigned int bmax,
+ unsigned int *blen)
+{
+ int ret = -EINVAL;
+ if (!cptr) return 0;
+ *blen = 0;
+ LOCK_TAKE(cptr->hdw->big_lock); do {
+ if (cptr->info->type == pvr2_ctl_enum) {
+ const char **names;
+ names = cptr->info->def.type_enum.value_names;
+ if ((val >= 0) &&
+ (val < cptr->info->def.type_enum.count)) {
+ if (names[val]) {
+ *blen = scnprintf(
+ bptr,bmax,"%s",
+ names[val]);
+ } else {
+ *blen = 0;
+ }
+ ret = 0;
+ }
+ } else if (cptr->info->type == pvr2_ctl_bitmask) {
+ const char **names;
+ unsigned int idx;
+ int msk;
+ names = cptr->info->def.type_bitmask.bit_names;
+ val &= cptr->info->def.type_bitmask.valid_bits;
+ for (idx = 0, msk = 1; val; idx++, msk <<= 1) {
+ if (val & msk) {
+ *blen = scnprintf(bptr,bmax,"%s",
+ names[idx]);
+ ret = 0;
+ break;
+ }
+ }
+ }
+ } while(0); LOCK_GIVE(cptr->hdw->big_lock);
+ return ret;
+}
+
+
+/* Return true if control is writable */
+int pvr2_ctrl_is_writable(struct pvr2_ctrl *cptr)
+{
+ if (!cptr) return 0;
+ return cptr->info->set_value != 0;
+}
+
+
+/* Return true if control has custom symbolic representation */
+int pvr2_ctrl_has_custom_symbols(struct pvr2_ctrl *cptr)
+{
+ if (!cptr) return 0;
+ if (!cptr->info->val_to_sym) return 0;
+ if (!cptr->info->sym_to_val) return 0;
+ return !0;
+}
+
+
+/* Convert a given mask/val to a custom symbolic value */
+int pvr2_ctrl_custom_value_to_sym(struct pvr2_ctrl *cptr,
+ int mask,int val,
+ char *buf,unsigned int maxlen,
+ unsigned int *len)
+{
+ if (!cptr) return -EINVAL;
+ if (!cptr->info->val_to_sym) return -EINVAL;
+ return cptr->info->val_to_sym(cptr,mask,val,buf,maxlen,len);
+}
+
+
+/* Convert a symbolic value to a mask/value pair */
+int pvr2_ctrl_custom_sym_to_value(struct pvr2_ctrl *cptr,
+ const char *buf,unsigned int len,
+ int *maskptr,int *valptr)
+{
+ if (!cptr) return -EINVAL;
+ if (!cptr->info->sym_to_val) return -EINVAL;
+ return cptr->info->sym_to_val(cptr,buf,len,maskptr,valptr);
+}
+
+
+static unsigned int gen_bitmask_string(int msk,int val,int msk_only,
+ const char **names,
+ char *ptr,unsigned int len)
+{
+ unsigned int idx;
+ long sm,um;
+ int spcFl;
+ unsigned int uc,cnt;
+ const char *idStr;
+
+ spcFl = 0;
+ uc = 0;
+ um = 0;
+ for (idx = 0, sm = 1; msk; idx++, sm <<= 1) {
+ if (sm & msk) {
+ msk &= ~sm;
+ idStr = names[idx];
+ if (idStr) {
+ cnt = scnprintf(ptr,len,"%s%s%s",
+ (spcFl ? " " : ""),
+ (msk_only ? "" :
+ ((val & sm) ? "+" : "-")),
+ idStr);
+ ptr += cnt; len -= cnt; uc += cnt;
+ spcFl = !0;
+ } else {
+ um |= sm;
+ }
+ }
+ }
+ if (um) {
+ if (msk_only) {
+ cnt = scnprintf(ptr,len,"%s0x%lx",
+ (spcFl ? " " : ""),
+ um);
+ ptr += cnt; len -= cnt; uc += cnt;
+ spcFl = !0;
+ } else if (um & val) {
+ cnt = scnprintf(ptr,len,"%s+0x%lx",
+ (spcFl ? " " : ""),
+ um & val);
+ ptr += cnt; len -= cnt; uc += cnt;
+ spcFl = !0;
+ } else if (um & ~val) {
+ cnt = scnprintf(ptr,len,"%s+0x%lx",
+ (spcFl ? " " : ""),
+ um & ~val);
+ ptr += cnt; len -= cnt; uc += cnt;
+ spcFl = !0;
+ }
+ }
+ return uc;
+}
+
+
+static int parse_token(const char *ptr,unsigned int len,
+ int *valptr,
+ const char **names,unsigned int namecnt)
+{
+ char buf[33];
+ unsigned int slen;
+ unsigned int idx;
+ int negfl;
+ char *p2;
+ *valptr = 0;
+ if (!names) namecnt = 0;
+ for (idx = 0; idx < namecnt; idx++) {
+ if (!names[idx]) continue;
+ slen = strlen(names[idx]);
+ if (slen != len) continue;
+ if (memcmp(names[idx],ptr,slen)) continue;
+ *valptr = idx;
+ return 0;
+ }
+ negfl = 0;
+ if ((*ptr == '-') || (*ptr == '+')) {
+ negfl = (*ptr == '-');
+ ptr++; len--;
+ }
+ if (len >= sizeof(buf)) return -EINVAL;
+ memcpy(buf,ptr,len);
+ buf[len] = 0;
+ *valptr = simple_strtol(buf,&p2,0);
+ if (negfl) *valptr = -(*valptr);
+ if (*p2) return -EINVAL;
+ return 0;
+}
+
+
+static int parse_mtoken(const char *ptr,unsigned int len,
+ int *valptr,
+ const char **names,int valid_bits)
+{
+ char buf[33];
+ unsigned int slen;
+ unsigned int idx;
+ char *p2;
+ int msk;
+ *valptr = 0;
+ for (idx = 0, msk = 1; valid_bits; idx++, msk <<= 1) {
+ if (!msk & valid_bits) continue;
+ valid_bits &= ~msk;
+ if (!names[idx]) continue;
+ slen = strlen(names[idx]);
+ if (slen != len) continue;
+ if (memcmp(names[idx],ptr,slen)) continue;
+ *valptr = msk;
+ return 0;
+ }
+ if (len >= sizeof(buf)) return -EINVAL;
+ memcpy(buf,ptr,len);
+ buf[len] = 0;
+ *valptr = simple_strtol(buf,&p2,0);
+ if (*p2) return -EINVAL;
+ return 0;
+}
+
+
+static int parse_tlist(const char *ptr,unsigned int len,
+ int *maskptr,int *valptr,
+ const char **names,int valid_bits)
+{
+ unsigned int cnt;
+ int mask,val,kv,mode,ret;
+ mask = 0;
+ val = 0;
+ ret = 0;
+ while (len) {
+ cnt = 0;
+ while ((cnt < len) &&
+ ((ptr[cnt] <= 32) ||
+ (ptr[cnt] >= 127))) cnt++;
+ ptr += cnt;
+ len -= cnt;
+ mode = 0;
+ if ((*ptr == '-') || (*ptr == '+')) {
+ mode = (*ptr == '-') ? -1 : 1;
+ ptr++;
+ len--;
+ }
+ cnt = 0;
+ while (cnt < len) {
+ if (ptr[cnt] <= 32) break;
+ if (ptr[cnt] >= 127) break;
+ cnt++;
+ }
+ if (!cnt) break;
+ if (parse_mtoken(ptr,cnt,&kv,names,valid_bits)) {
+ ret = -EINVAL;
+ break;
+ }
+ ptr += cnt;
+ len -= cnt;
+ switch (mode) {
+ case 0:
+ mask = valid_bits;
+ val |= kv;
+ break;
+ case -1:
+ mask |= kv;
+ val &= ~kv;
+ break;
+ case 1:
+ mask |= kv;
+ val |= kv;
+ break;
+ default:
+ break;
+ }
+ }
+ *maskptr = mask;
+ *valptr = val;
+ return ret;
+}
+
+
+/* Convert a symbolic value to a mask/value pair */
+int pvr2_ctrl_sym_to_value(struct pvr2_ctrl *cptr,
+ const char *ptr,unsigned int len,
+ int *maskptr,int *valptr)
+{
+ int ret = -EINVAL;
+ unsigned int cnt;
+
+ *maskptr = 0;
+ *valptr = 0;
+
+ cnt = 0;
+ while ((cnt < len) && ((ptr[cnt] <= 32) || (ptr[cnt] >= 127))) cnt++;
+ len -= cnt; ptr += cnt;
+ cnt = 0;
+ while ((cnt < len) && ((ptr[len-(cnt+1)] <= 32) ||
+ (ptr[len-(cnt+1)] >= 127))) cnt++;
+ len -= cnt;
+
+ if (!len) return -EINVAL;
+
+ 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) &&
+ ((*valptr < cptr->info->def.type_int.min_value) ||
+ (*valptr > cptr->info->def.type_int.max_value))) {
+ ret = -EINVAL;
+ }
+ if (maskptr) *maskptr = ~0;
+ } 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) &&
+ ((*valptr < 0) ||
+ (*valptr >= cptr->info->def.type_enum.count))) {
+ ret = -EINVAL;
+ }
+ if (maskptr) *maskptr = ~0;
+ } else if (cptr->info->type == pvr2_ctl_bitmask) {
+ ret = parse_tlist(
+ ptr,len,maskptr,valptr,
+ cptr->info->def.type_bitmask.bit_names,
+ cptr->info->def.type_bitmask.valid_bits);
+ }
+ } while(0); LOCK_GIVE(cptr->hdw->big_lock);
+ return ret;
+}
+
+
+/* Convert a given mask/val to a symbolic value */
+int pvr2_ctrl_value_to_sym_internal(struct pvr2_ctrl *cptr,
+ int mask,int val,
+ char *buf,unsigned int maxlen,
+ unsigned int *len)
+{
+ int ret = -EINVAL;
+
+ *len = 0;
+ if (cptr->info->type == pvr2_ctl_int) {
+ *len = scnprintf(buf,maxlen,"%d",val);
+ ret = 0;
+ } else if (cptr->info->type == pvr2_ctl_enum) {
+ const char **names;
+ names = cptr->info->def.type_enum.value_names;
+ if ((val >= 0) &&
+ (val < cptr->info->def.type_enum.count)) {
+ if (names[val]) {
+ *len = scnprintf(
+ buf,maxlen,"%s",
+ names[val]);
+ } else {
+ *len = 0;
+ }
+ ret = 0;
+ }
+ } else if (cptr->info->type == pvr2_ctl_bitmask) {
+ *len = gen_bitmask_string(
+ val & mask & cptr->info->def.type_bitmask.valid_bits,
+ ~0,!0,
+ cptr->info->def.type_bitmask.bit_names,
+ buf,maxlen);
+ }
+ return ret;
+}
+
+
+/* Convert a given mask/val to a symbolic value */
+int pvr2_ctrl_value_to_sym(struct pvr2_ctrl *cptr,
+ int mask,int val,
+ char *buf,unsigned int maxlen,
+ unsigned int *len)
+{
+ int ret;
+ LOCK_TAKE(cptr->hdw->big_lock); do {
+ ret = pvr2_ctrl_value_to_sym_internal(cptr,mask,val,
+ buf,maxlen,len);
+ } while(0); LOCK_GIVE(cptr->hdw->big_lock);
+ return ret;
+}
+
+
+/*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+ *** Local Variables: ***
+ *** mode: c ***
+ *** fill-column: 75 ***
+ *** tab-width: 8 ***
+ *** c-basic-offset: 8 ***
+ *** End: ***
+ */
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-ctrl.h b/linux/drivers/media/video/pvrusb2/pvrusb2-ctrl.h
new file mode 100644
index 000000000..9d74151a3
--- /dev/null
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-ctrl.h
@@ -0,0 +1,115 @@
+/*
+ *
+ * $Id$
+ *
+ * Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#ifndef __PVRUSB2_CTRL_H
+#define __PVRUSB2_CTRL_H
+
+struct pvr2_ctrl;
+
+enum pvr2_ctl_type {
+ pvr2_ctl_int = 0,
+ pvr2_ctl_enum = 1,
+ pvr2_ctl_bitmask = 2,
+};
+
+
+/* Set the given control. */
+int pvr2_ctrl_set_value(struct pvr2_ctrl *,int val);
+
+/* Set/clear specific bits of the given control. */
+int pvr2_ctrl_set_mask_value(struct pvr2_ctrl *,int mask,int val);
+
+/* Get the current value of the given control. */
+int pvr2_ctrl_get_value(struct pvr2_ctrl *,int *valptr);
+
+/* Retrieve control's type */
+enum pvr2_ctl_type pvr2_ctrl_get_type(struct pvr2_ctrl *);
+
+/* Retrieve control's maximum value (int type) */
+int pvr2_ctrl_get_max(struct pvr2_ctrl *);
+
+/* Retrieve control's minimum value (int type) */
+int pvr2_ctrl_get_min(struct pvr2_ctrl *);
+
+/* Retrieve control's default value (any type) */
+int pvr2_ctrl_get_def(struct pvr2_ctrl *);
+
+/* Retrieve control's enumeration count (enum only) */
+int pvr2_ctrl_get_cnt(struct pvr2_ctrl *);
+
+/* Retrieve control's valid mask bits (bit mask only) */
+int pvr2_ctrl_get_mask(struct pvr2_ctrl *);
+
+/* Retrieve the control's name */
+const char *pvr2_ctrl_get_name(struct pvr2_ctrl *);
+
+/* Retrieve the control's desc */
+const char *pvr2_ctrl_get_desc(struct pvr2_ctrl *);
+
+/* Retrieve a control enumeration or bit mask value */
+int pvr2_ctrl_get_valname(struct pvr2_ctrl *,int,char *,unsigned int,
+ unsigned int *);
+
+/* Return true if control is writable */
+int pvr2_ctrl_is_writable(struct pvr2_ctrl *);
+
+/* Return true if control has custom symbolic representation */
+int pvr2_ctrl_has_custom_symbols(struct pvr2_ctrl *);
+
+/* Convert a given mask/val to a custom symbolic value */
+int pvr2_ctrl_custom_value_to_sym(struct pvr2_ctrl *,
+ int mask,int val,
+ char *buf,unsigned int maxlen,
+ unsigned int *len);
+
+/* Convert a symbolic value to a mask/value pair */
+int pvr2_ctrl_custom_sym_to_value(struct pvr2_ctrl *,
+ const char *buf,unsigned int len,
+ int *maskptr,int *valptr);
+
+/* Convert a given mask/val to a symbolic value */
+int pvr2_ctrl_value_to_sym(struct pvr2_ctrl *,
+ int mask,int val,
+ char *buf,unsigned int maxlen,
+ unsigned int *len);
+
+/* Convert a symbolic value to a mask/value pair */
+int pvr2_ctrl_sym_to_value(struct pvr2_ctrl *,
+ const char *buf,unsigned int len,
+ int *maskptr,int *valptr);
+
+/* Convert a given mask/val to a symbolic value - must already be
+ inside of critical region. */
+int pvr2_ctrl_value_to_sym_internal(struct pvr2_ctrl *,
+ int mask,int val,
+ char *buf,unsigned int maxlen,
+ unsigned int *len);
+
+#endif /* __PVRUSB2_CTRL_H */
+
+/*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+ *** Local Variables: ***
+ *** mode: c ***
+ *** fill-column: 75 ***
+ *** tab-width: 8 ***
+ *** c-basic-offset: 8 ***
+ *** End: ***
+ */
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c b/linux/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
new file mode 100644
index 000000000..47e7f5dbd
--- /dev/null
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
@@ -0,0 +1,276 @@
+/*
+ *
+ * $Id$
+ *
+ * Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/*
+
+ This source file is specifically designed to interface with the
+ cx2584x, in kernels 2.6.16 or newer.
+
+*/
+
+#include "pvrusb2-cx2584x-v4l.h"
+#include "pvrusb2-video-v4l.h"
+#include "pvrusb2-i2c-cmd-v4l2.h"
+
+
+#include "pvrusb2-hdw-internal.h"
+#include "pvrusb2-debug.h"
+#include <media/cx25840.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+
+struct pvr2_v4l_cx2584x {
+ struct pvr2_i2c_handler handler;
+ struct pvr2_decoder_ctrl ctrl;
+ struct pvr2_i2c_client *client;
+ struct pvr2_hdw *hdw;
+ unsigned long stale_mask;
+};
+
+
+static void set_input(struct pvr2_v4l_cx2584x *ctxt)
+{
+ struct pvr2_hdw *hdw = ctxt->hdw;
+ struct v4l2_routing route;
+ enum cx25840_video_input vid_input;
+ enum cx25840_audio_input aud_input;
+
+ memset(&route,0,sizeof(route));
+
+ switch(hdw->input_val) {
+ case PVR2_CVAL_INPUT_TV:
+ vid_input = CX25840_COMPOSITE7;
+ aud_input = CX25840_AUDIO8;
+ break;
+ case PVR2_CVAL_INPUT_COMPOSITE:
+ vid_input = CX25840_COMPOSITE3;
+ aud_input = CX25840_AUDIO_SERIAL;
+ break;
+ case PVR2_CVAL_INPUT_SVIDEO:
+ vid_input = CX25840_SVIDEO1;
+ aud_input = CX25840_AUDIO_SERIAL;
+ break;
+ case PVR2_CVAL_INPUT_RADIO:
+ default:
+ // Just set it to be composite input for now...
+ vid_input = CX25840_COMPOSITE3;
+ aud_input = CX25840_AUDIO_SERIAL;
+ break;
+ }
+
+ pvr2_trace(PVR2_TRACE_CHIPS,"i2c cx2584x set_input vid=0x%x aud=0x%x",
+ vid_input,aud_input);
+ route.input = (u32)vid_input;
+ pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_S_VIDEO_ROUTING,&route);
+ route.input = (u32)aud_input;
+ pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_S_AUDIO_ROUTING,&route);
+}
+
+
+static int check_input(struct pvr2_v4l_cx2584x *ctxt)
+{
+ struct pvr2_hdw *hdw = ctxt->hdw;
+ return hdw->input_dirty != 0;
+}
+
+
+static void set_audio(struct pvr2_v4l_cx2584x *ctxt)
+{
+ u32 val;
+ struct pvr2_hdw *hdw = ctxt->hdw;
+
+ pvr2_trace(PVR2_TRACE_CHIPS,"i2c cx2584x set_audio %d",
+ hdw->srate_val);
+ switch (hdw->srate_val) {
+ default:
+ case PVR2_CVAL_SRATE_48:
+ val = 48000;
+ break;
+ case PVR2_CVAL_SRATE_44_1:
+ val = 44100;
+ break;
+ }
+ pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_AUDIO_CLOCK_FREQ,&val);
+}
+
+
+static int check_audio(struct pvr2_v4l_cx2584x *ctxt)
+{
+ struct pvr2_hdw *hdw = ctxt->hdw;
+ return hdw->srate_dirty != 0;
+}
+
+
+struct pvr2_v4l_cx2584x_ops {
+ void (*update)(struct pvr2_v4l_cx2584x *);
+ int (*check)(struct pvr2_v4l_cx2584x *);
+};
+
+
+static const struct pvr2_v4l_cx2584x_ops decoder_ops[] = {
+ { .update = set_input, .check = check_input},
+ { .update = set_audio, .check = check_audio},
+};
+
+
+static void decoder_detach(struct pvr2_v4l_cx2584x *ctxt)
+{
+ ctxt->client->handler = 0;
+ ctxt->hdw->decoder_ctrl = 0;
+ kfree(ctxt);
+}
+
+
+static int decoder_check(struct pvr2_v4l_cx2584x *ctxt)
+{
+ unsigned long msk;
+ unsigned int idx;
+
+ for (idx = 0; idx < sizeof(decoder_ops)/sizeof(decoder_ops[0]);
+ idx++) {
+ msk = 1 << idx;
+ if (ctxt->stale_mask & msk) continue;
+ if (decoder_ops[idx].check(ctxt)) {
+ ctxt->stale_mask |= msk;
+ }
+ }
+ return ctxt->stale_mask != 0;
+}
+
+
+static void decoder_update(struct pvr2_v4l_cx2584x *ctxt)
+{
+ unsigned long msk;
+ unsigned int idx;
+
+ for (idx = 0; idx < sizeof(decoder_ops)/sizeof(decoder_ops[0]);
+ idx++) {
+ msk = 1 << idx;
+ if (!(ctxt->stale_mask & msk)) continue;
+ ctxt->stale_mask &= ~msk;
+ decoder_ops[idx].update(ctxt);
+ }
+}
+
+
+static void decoder_enable(struct pvr2_v4l_cx2584x *ctxt,int fl)
+{
+ pvr2_trace(PVR2_TRACE_CHIPS,"i2c cx25840 decoder_enable(%d)",fl);
+ pvr2_v4l2_cmd_stream(ctxt->client,fl);
+}
+
+
+static int decoder_detect(struct pvr2_i2c_client *cp)
+{
+ int ret;
+ /* Attempt to query the decoder - let's see if it will answer */
+ struct v4l2_queryctrl qc;
+
+ memset(&qc,0,sizeof(qc));
+
+ qc.id = V4L2_CID_BRIGHTNESS;
+
+ ret = pvr2_i2c_client_cmd(cp,VIDIOC_QUERYCTRL,&qc);
+ return ret == 0; /* Return true if it answered */
+}
+
+
+static int decoder_is_tuned(struct pvr2_v4l_cx2584x *ctxt)
+{
+ struct v4l2_tuner vt;
+ int ret;
+
+ memset(&vt,0,sizeof(vt));
+ ret = pvr2_i2c_client_cmd(ctxt->client,VIDIOC_G_TUNER,&vt);
+ if (ret < 0) return -EINVAL;
+ return vt.signal ? 1 : 0;
+}
+
+
+static unsigned int decoder_describe(struct pvr2_v4l_cx2584x *ctxt,
+ char *buf,unsigned int cnt)
+{
+ return scnprintf(buf,cnt,"handler: pvrusb2-cx2584x-v4l");
+}
+
+
+static void decoder_reset(struct pvr2_v4l_cx2584x *ctxt)
+{
+ int ret;
+ ret = pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_RESET,0);
+ pvr2_trace(PVR2_TRACE_CHIPS,"i2c cx25840 decoder_reset (ret=%d)",ret);
+}
+
+
+const static struct pvr2_i2c_handler_functions hfuncs = {
+ .detach = (void (*)(void *))decoder_detach,
+ .check = (int (*)(void *))decoder_check,
+ .update = (void (*)(void *))decoder_update,
+ .describe = (unsigned int (*)(void *,char *,unsigned int))decoder_describe,
+};
+
+
+int pvr2_i2c_cx2584x_v4l_setup(struct pvr2_hdw *hdw,
+ struct pvr2_i2c_client *cp)
+{
+ struct pvr2_v4l_cx2584x *ctxt;
+
+ if (hdw->decoder_ctrl) return 0;
+ if (cp->handler) return 0;
+ if (!decoder_detect(cp)) return 0;
+
+ ctxt = kmalloc(sizeof(*ctxt),GFP_KERNEL);
+ if (!ctxt) return 0;
+ memset(ctxt,0,sizeof(*ctxt));
+
+ ctxt->handler.func_data = ctxt;
+ ctxt->handler.func_table = &hfuncs;
+ ctxt->ctrl.ctxt = ctxt;
+ ctxt->ctrl.detach = (void (*)(void *))decoder_detach;
+ ctxt->ctrl.enable = (void (*)(void *,int))decoder_enable;
+ ctxt->ctrl.tuned = (int (*)(void *))decoder_is_tuned;
+ ctxt->ctrl.force_reset = (void (*)(void*))decoder_reset;
+ ctxt->client = cp;
+ ctxt->hdw = hdw;
+ ctxt->stale_mask = (1 << (sizeof(decoder_ops)/
+ sizeof(decoder_ops[0]))) - 1;
+ hdw->decoder_ctrl = &ctxt->ctrl;
+ cp->handler = &ctxt->handler;
+ pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x cx2584x V4L2 handler set up",
+ cp->client->addr);
+ return !0;
+}
+
+
+
+
+/*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+ *** Local Variables: ***
+ *** mode: c ***
+ *** fill-column: 70 ***
+ *** tab-width: 8 ***
+ *** c-basic-offset: 8 ***
+ *** End: ***
+ */
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.h b/linux/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.h
new file mode 100644
index 000000000..5dea8d7b3
--- /dev/null
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.h
@@ -0,0 +1,54 @@
+/*
+ *
+ * $Id$
+ *
+ * Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef __PVRUSB2_CX2584X_V4L_H
+#define __PVRUSB2_CX2584X_V4L_H
+
+/*
+
+ This module connects the pvrusb2 driver to the I2C chip level
+ driver which handles combined device audio & video processing.
+ This interface is used internally by the driver; higher level code
+ should only interact through the interface provided by
+ pvrusb2-hdw.h.
+
+*/
+
+#include "compat.h"
+
+
+#include "pvrusb2-i2c-core.h"
+
+int pvr2_i2c_cx2584x_v4l_setup(struct pvr2_hdw *,struct pvr2_i2c_client *);
+
+
+#endif /* __PVRUSB2_CX2584X_V4L_H */
+
+/*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+ *** Local Variables: ***
+ *** mode: c ***
+ *** fill-column: 70 ***
+ *** tab-width: 8 ***
+ *** c-basic-offset: 8 ***
+ *** End: ***
+ */
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-debugifc.c b/linux/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
index bcfe468eb..586900e36 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
@@ -32,11 +32,11 @@ struct debugifc_mask_item {
};
static struct debugifc_mask_item mask_items[] = {
- {"ENC_FIRMWARE",PVR2_SUBSYS_ENC_FIRMWARE},
- {"ENC_CFG",PVR2_SUBSYS_ENC_CFG},
- {"DIG_RUN",PVR2_SUBSYS_DIGITIZER_RUN},
- {"USB_RUN",PVR2_SUBSYS_USBSTREAM_RUN},
- {"ENC_RUN",PVR2_SUBSYS_ENC_RUN},
+ {"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)},
};
@@ -362,11 +362,13 @@ int pvr2_debugifc_do1cmd(struct pvr2_hdw *hdw,const char *buf,
} else if (debugifc_match_keyword(wptr,wlen,"bus")) {
pvr2_hdw_device_reset(hdw);
} else if (debugifc_match_keyword(wptr,wlen,"soft")) {
- return pvr2_hdw_cmd_soft_reset(hdw);
+ return pvr2_hdw_cmd_powerup(hdw);
} else if (debugifc_match_keyword(wptr,wlen,"deep")) {
return pvr2_hdw_cmd_deep_reset(hdw);
} else if (debugifc_match_keyword(wptr,wlen,"firmware")) {
return pvr2_upload_firmware2(hdw);
+ } else if (debugifc_match_keyword(wptr,wlen,"decoder")) {
+ return pvr2_hdw_cmd_decoder_reset(hdw);
}
return -EINVAL;
} else if (debugifc_match_keyword(wptr,wlen,"subsys_flags")) {
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-demod.c b/linux/drivers/media/video/pvrusb2/pvrusb2-demod.c
index dca787dfa..f082ecee2 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-demod.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-demod.c
@@ -26,7 +26,7 @@
#include "pvrusb2-hdw-internal.h"
#include "pvrusb2-debug.h"
#include "compat.h"
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
#include <media/tuner.h>
#include <media/v4l2-common.h>
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-eeprom.c b/linux/drivers/media/video/pvrusb2/pvrusb2-eeprom.c
index 60ee45ca2..4003149a1 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-eeprom.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-eeprom.c
@@ -27,56 +27,7 @@
#define trace_eeprom(...) pvr2_trace(PVR2_TRACE_EEPROM,__VA_ARGS__)
-/*
-
- isely@pobox.com 16-Oct-2005 - There are two method by which we can
- theoretically retrieve information from the device's eeprom:
-
- Method #1: We expect tveeprom to attach to our I2C adapter as a
- client, in which case we send it a command to tell us what it
- knows about the device. This is the "indirect" method.
-
- Method #2: We retrieve the eeprom contents ourselves and call into
- tveeprom_hauppauge_analog() to parse the data and tell us what
- it knows about the device. This is the "direct" method.
-
- Unfortunately it isn't perfectly clear which method is the best.
- They each have pros and cons:
-
- #1 is simpler & more portable and has an API which is more stable.
-
- #1 doesn't provide as much information as #2 does. For example, we
- can't retrieve the device's serial number with method #1.
-
- #1 requires that tveeprom.ko autonomously detect the eeprom chip on
- its own; we can't help it out here. Worse still, it seems that
- the eeprom in some PVR USB2 devices (like mine) can't be detected
- correctly (I don't see an ack on a zero length write which is
- what the I2C core attempts).
-
- #2 uses an unstable API. Current the ivtv implementation of #2 uses
- a completely different tveeprom struct than the v4l
- implementation of #2. This causes a usability nightmare.
-
- Since I can't decide, both methods are implemented below. Method #2
- (direct) is the default choice, but if you want to try method #1,
- then define PVR2_EEPROM_INDIRECT and cross your fingers...
- If you use method #1, please be aware that you won't have a serial
- number for the device and thus the sysfs interface may be a little
- different. In addition, if tveeprom.ko fails to detect the eeprom
- you may have to force it using standard i2c module options (try
- force=-1,80). FINALLY (and this may foreclose this option for you
- completely), the PVR USB2 eeprom seems to have valid data only in
- the upper 128 bytes - the lower 128 bytes causes tveeprom.ko to
- abort. In method #2 we only read the upper 128 bytes...
-
- */
-
-
-
-
-/* Stuff common to direct approach of operation tveeprom */
/*
@@ -121,7 +72,7 @@ static u8 *pvr2_eeprom_fetch(struct pvr2_hdw *hdw)
/* FX2 documentation states that a 16bit-addressed eeprom is
expected if the I2C address is an odd number (yeah, this is
- strange bit it's what they do) */
+ strange but it's what they do) */
mode16 = (addr & 1);
eepromSize = (mode16 ? 4096 : 256);
trace_eeprom("Examining %d byte eeprom at location 0x%x"
@@ -132,7 +83,7 @@ static u8 *pvr2_eeprom_fetch(struct pvr2_hdw *hdw)
msg[0].flags = 0;
msg[0].len = mode16 ? 2 : 1;
msg[0].buf = iadd;
- msg[1].addr = hdw->eeprom_addr;
+ msg[1].addr = addr;
msg[1].flags = I2C_M_RD;
/* We have to do the actual eeprom data fetch ourselves, because
@@ -165,15 +116,7 @@ static u8 *pvr2_eeprom_fetch(struct pvr2_hdw *hdw)
}
-/*VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV*/
-/* BEGIN DIRECT METHOD, V4L ONLY */
-
-
-/* Directly call eeprom analysis function within tveeprom. This
- version directly assumes it is talking to the V4L version of
- tveeprom.ko and does not attempt anything ugly to maintain
- backwards compatibility. */
-
+/* Directly call eeprom analysis function within tveeprom. */
int pvr2_eeprom_analyze(struct pvr2_hdw *hdw)
{
u8 *eeprom;
@@ -204,66 +147,13 @@ int pvr2_eeprom_analyze(struct pvr2_hdw *hdw)
trace_eeprom("rev_str=%s",tvdata.rev_str);
hdw->tuner_type = tvdata.tuner_type;
hdw->serial_number = tvdata.serial_number;
- hdw->video_standards = tvdata.tuner_formats;
+ hdw->std_mask_eeprom = tvdata.tuner_formats;
kfree(eeprom);
return 0;
}
-
-
-/* END DIRECT METHOD, V4L ONLY */
-/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
-
-
-
-
-
-
-
-static v4l2_std_id std_choices[] = {
- [PVR2_CVAL_VIDEOSTANDARD_NTSC_M] = V4L2_STD_NTSC_M,
- [PVR2_CVAL_VIDEOSTANDARD_PAL_BG] = V4L2_STD_PAL_BG,
- [PVR2_CVAL_VIDEOSTANDARD_PAL_I] = V4L2_STD_PAL_I,
- [PVR2_CVAL_VIDEOSTANDARD_PAL_DK] = V4L2_STD_PAL_DK,
- [PVR2_CVAL_VIDEOSTANDARD_SECAM_L] = V4L2_STD_SECAM_L,
- [PVR2_CVAL_VIDEOSTANDARD_PAL_M] = V4L2_STD_PAL_M,
-};
-
-void pvr2_eeprom_set_default_standard(struct pvr2_hdw *hdw)
-{
- int vstd_value = 0;
- int vstd_found = 0;
- unsigned int idx;
- v4l2_std_id vs = (v4l2_std_id)hdw->video_standards;
-
- for (idx = 0; idx < sizeof(std_choices)/sizeof(std_choices[0]);
- idx++) {
- if (!(vs & std_choices[idx])) continue;
- trace_eeprom("Detected video standard %s (from eeprom)",
- pvr2_hdw_get_ctl_value_name(
- hdw,PVR2_CID_VIDEOSTANDARD,idx));
- if (vstd_found) continue;
- vstd_value = idx;
- vstd_found = !0;
- }
-
- if (!vstd_found) {
- trace_eeprom("eeprom unable to recognize"
- " a known video standard");
- return;
- }
-
- trace_eeprom("Setting initial video standard to %s"
- " (detected from eeprom)",
- pvr2_hdw_get_ctl_value_name(hdw,
- PVR2_CID_VIDEOSTANDARD,
- vstd_value));
- pvr2_hdw_set_ctl_value_internal(hdw,PVR2_CID_VIDEOSTANDARD,vstd_value);
-}
-
-
/*
Stuff for Emacs to see, in order to encourage consistent editing style:
*** Local Variables: ***
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-eeprom.h b/linux/drivers/media/video/pvrusb2/pvrusb2-eeprom.h
index 061cecd91..84242975d 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-eeprom.h
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-eeprom.h
@@ -26,7 +26,6 @@
struct pvr2_hdw;
int pvr2_eeprom_analyze(struct pvr2_hdw *);
-void pvr2_eeprom_set_default_standard(struct pvr2_hdw *);
#endif /* __PVRUSB2_EEPROM_H */
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-encoder.c b/linux/drivers/media/video/pvrusb2/pvrusb2-encoder.c
index 97931d3c4..6c66e258f 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-encoder.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-encoder.c
@@ -22,7 +22,7 @@
#include <linux/device.h> // for linux/firmware.h
#include <linux/firmware.h>
-#include "cx2341x.h"
+#include <media/cx2341x.h>
#include "pvrusb2-util.h"
#include "pvrusb2-encoder.h"
#include "pvrusb2-hdw-internal.h"
@@ -268,50 +268,62 @@ static int pvr2_write_encoder_vcmd (struct pvr2_hdw *hdw, u8 cmd,
int pvr2_encoder_configure(struct pvr2_hdw *hdw)
{
int ret = 0, audio, i;
- int vd_std = hdw->controls[PVR2_CID_VIDEOSTANDARD].value;
- int height = hdw->controls[PVR2_CID_VRES].value;
- int width = hdw->controls[PVR2_CID_HRES].value;
- int height_full = !hdw->controls[PVR2_CID_INTERLACE].value;
+ 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;
- switch (vd_std) {
- case PVR2_CVAL_VIDEOSTANDARD_NTSC_M:
+ if (vd_std & V4L2_STD_NTSC) {
is_ntsc=1;
is_30fps=1;
- break;
- case PVR2_CVAL_VIDEOSTANDARD_PAL_M:
+ } else if (vd_std & V4L2_STD_PAL_M) {
is_ntsc=0;
is_30fps=1;
- break;
- default:
+ } else {
is_ntsc=0;
is_30fps=0;
- break;
}
pvr2_trace(PVR2_TRACE_ENCODER,"pvr2_encoder_configure");
- /* set stream output port. */
+ /* 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, 0x01);
+ 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 some 0xdc */
-
- /* Mike Isely <isely@pobox.com> 19-Jun-2005 I've confirmed
- that the Windows driver seems to issue these commands, but
- right now I have no idea what these do (and neither does
- the ivtv driver). But, if I leave them in, then mplayer
- goes nuts with xrun errors. So for now we don't do this.
- It sure would be nice to know what these are for. */
-#if 0
- ret |= pvr2_write_encoder_vcmd(hdw, 0xdc, 1, 5);
- ret |= pvr2_write_encoder_vcmd(hdw, 0xdc, 2, 3, 1);
- ret |= pvr2_write_encoder_vcmd(hdw, 0xdc, 1, 8);
+ /* 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
/* Strange compared to ivtv data. */
@@ -373,9 +385,9 @@ int pvr2_encoder_configure(struct pvr2_hdw *hdw)
/* set video bitrate */
ret |= pvr2_write_encoder_vcmd(
hdw, CX2341X_ENC_SET_BIT_RATE, 3,
- (hdw->controls[PVR2_CID_VBR].value ? 1 : 0),
- hdw->controls[PVR2_CID_AVERAGEVIDEOBITRATE].value,
- (u32) (hdw->controls[PVR2_CID_PEAKVIDEOBITRATE].value) / 400);
+ (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);
@@ -387,13 +399,11 @@ int pvr2_encoder_configure(struct pvr2_hdw *hdw)
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->controls[
- PVR2_CID_AUDIOBITRATE].value] |
- pvr_tbl_srate[hdw->controls[PVR2_CID_SRATE].value] |
- hdw->controls[PVR2_CID_AUDIOLAYER].value << 2 |
- (hdw->controls[PVR2_CID_AUDIOCRC].value ? 1 << 14 : 0) |
- pvr_tbl_emphasis[hdw->controls[
- PVR2_CID_AUDIOEMPHASIS].value]);
+ 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);
@@ -419,7 +429,7 @@ int pvr2_encoder_configure(struct pvr2_hdw *hdw)
ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_INITIALIZE_INPUT, 0);
if (!ret) {
- hdw->subsys_enabled_mask |= PVR2_SUBSYS_ENC_CFG;
+ hdw->subsys_enabled_mask |= (1<<PVR2_SUBSYS_B_ENC_CFG);
}
return ret;
@@ -447,7 +457,7 @@ int pvr2_encoder_start(struct pvr2_hdw *hdw)
0,0x13);
}
if (!status) {
- hdw->subsys_enabled_mask |= PVR2_SUBSYS_ENC_RUN;
+ hdw->subsys_enabled_mask |= (1<<PVR2_SUBSYS_B_ENC_RUN);
}
return status;
}
@@ -477,7 +487,7 @@ int pvr2_encoder_stop(struct pvr2_hdw *hdw)
pvr2_hdw_gpio_chg_out(hdw,0xffffffff,0x00000000);
if (!status) {
- hdw->subsys_enabled_mask &= ~PVR2_SUBSYS_ENC_RUN;
+ hdw->subsys_enabled_mask &= ~(1<<PVR2_SUBSYS_B_ENC_RUN);
}
return status;
}
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
index 1b161773b..0d527abb5 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
@@ -34,17 +34,48 @@
*/
#include "compat.h"
+#include <linux/config.h>
#include <linux/videodev2.h>
#include <linux/i2c.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
-#include <asm/atomic.h>
-#include <asm/mutex.h>
+#include <linux/mutex.h>
#else
#include <asm/semaphore.h>
#endif
#include "pvrusb2-hdw.h"
#include "pvrusb2-io.h"
+/* Legal values for the SRATE state variable */
+#define PVR2_CVAL_SRATE_48 0
+#define PVR2_CVAL_SRATE_44_1 1
+
+/* Legal values for the AUDIOBITRATE state variable */
+#define PVR2_CVAL_AUDIOBITRATE_384 0
+#define PVR2_CVAL_AUDIOBITRATE_320 1
+#define PVR2_CVAL_AUDIOBITRATE_256 2
+#define PVR2_CVAL_AUDIOBITRATE_224 3
+#define PVR2_CVAL_AUDIOBITRATE_192 4
+#define PVR2_CVAL_AUDIOBITRATE_160 5
+#define PVR2_CVAL_AUDIOBITRATE_128 6
+#define PVR2_CVAL_AUDIOBITRATE_112 7
+#define PVR2_CVAL_AUDIOBITRATE_96 8
+#define PVR2_CVAL_AUDIOBITRATE_80 9
+#define PVR2_CVAL_AUDIOBITRATE_64 10
+#define PVR2_CVAL_AUDIOBITRATE_56 11
+#define PVR2_CVAL_AUDIOBITRATE_48 12
+#define PVR2_CVAL_AUDIOBITRATE_32 13
+#define PVR2_CVAL_AUDIOBITRATE_VBR 14
+
+/* Legal values for the AUDIOEMPHASIS state variable */
+#define PVR2_CVAL_AUDIOEMPHASIS_NONE 0
+#define PVR2_CVAL_AUDIOEMPHASIS_50_15 1
+#define PVR2_CVAL_AUDIOEMPHASIS_CCITT 2
+
+/* Legal values for PVR2_CID_HSM */
+#define PVR2_CVAL_HSM_FAIL 0
+#define PVR2_CVAL_HSM_FULL 1
+#define PVR2_CVAL_HSM_HIGH 2
+
#define PVR2_VID_ENDPOINT 0x84
#define PVR2_UNK_ENDPOINT 0x86 /* maybe raw yuv ? */
#define PVR2_VBI_ENDPOINT 0x88
@@ -58,11 +89,72 @@
struct pvr2_decoder;
-struct pvr2_ctl_state {
- int value;
- int dirty;
+typedef int (*pvr2_ctlf_is_dirty)(struct pvr2_ctrl *);
+typedef void (*pvr2_ctlf_clear_dirty)(struct pvr2_ctrl *);
+typedef int (*pvr2_ctlf_get_value)(struct pvr2_ctrl *,int *);
+typedef int (*pvr2_ctlf_set_value)(struct pvr2_ctrl *,int msk,int val);
+typedef int (*pvr2_ctlf_val_to_sym)(struct pvr2_ctrl *,int msk,int val,
+ char *,unsigned int,unsigned int *);
+typedef int (*pvr2_ctlf_sym_to_val)(struct pvr2_ctrl *,
+ const char *,unsigned int,
+ int *mskp,int *valp);
+
+/* This structure describes a specific control. A table of these is set up
+ in pvrusb2-hdw.c. */
+struct pvr2_ctl_info {
+ /* Control's name suitable for use as an identifier */
+ const char *name;
+
+ /* Short description of control */
+ const char *desc;
+
+ /* Control's implementation */
+ pvr2_ctlf_get_value get_value; /* Get its value */
+ pvr2_ctlf_set_value set_value; /* Set its value */
+ pvr2_ctlf_val_to_sym val_to_sym; /* Custom convert value->symbol */
+ 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 */
+
+ /* Control's type (int, enum, bitmask) */
+ enum pvr2_ctl_type type;
+
+ /* Associated V4L control ID, if any */
+ int v4l_id;
+
+ /* Associated driver internal ID, if any */
+ int internal_id;
+
+ /* Don't implicitly initialize this control's value */
+ int skip_init;
+
+ /* Starting value for this control */
+ int default_value;
+
+ /* Type-specific control information */
+ union {
+ struct { /* Integer control */
+ long min_value; /* lower limit */
+ long max_value; /* upper limit */
+ } type_int;
+ struct { /* enumerated control */
+ unsigned int count; /* enum value count */
+ const char **value_names; /* symbol names */
+ } type_enum;
+ struct { /* bitmask control */
+ unsigned int valid_bits; /* bits in use */
+ const char **bit_names; /* symbol name/bit */
+ } type_bitmask;
+ } def;
};
+
+struct pvr2_ctrl {
+ const struct pvr2_ctl_info *info;
+ struct pvr2_hdw *hdw;
+};
+
+
struct pvr2_audio_stat {
void *ctxt;
void (*detach)(void *);
@@ -74,6 +166,7 @@ struct pvr2_decoder_ctrl {
void (*detach)(void *);
void (*enable)(void *,int);
int (*tuned)(void *);
+ void (*force_reset)(void *);
};
#define PVR2_I2C_PEND_DETECT 0x01 /* Need to detect a client type */
@@ -95,7 +188,12 @@ struct pvr2_decoder_ctrl {
/* Known major hardware variants, keyed from device ID */
#define PVR2_HDW_TYPE_29XXX 0
+#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
#define PVR2_HDW_TYPE_24XXX 1
+#endif
+
+typedef int (*pvr2_i2c_func)(struct pvr2_hdw *,u8,u8 *,u16,u8 *, u16);
+#define PVR2_I2C_FUNC_CNT 128
/* This structure contains all state data directly needed to
manipulate the hardware (as opposed to complying with a kernel
@@ -127,6 +225,8 @@ struct pvr2_hdw {
/* I2C stuff */
struct i2c_adapter i2c_adap;
struct i2c_algorithm i2c_algo;
+ pvr2_i2c_func i2c_func[PVR2_I2C_FUNC_CNT];
+ int i2c_cx25840_hack_state;
int i2c_linked;
unsigned int i2c_pend_types; /* Which types of update are needed */
unsigned long i2c_pend_mask; /* Change bits we need to scan */
@@ -141,6 +241,8 @@ struct pvr2_hdw {
/* Frequency table */
unsigned int freqTable[FREQTABLE_SIZE];
+ unsigned int freqProgSlot;
+ unsigned int freqSlot;
/* Stuff for handling low level control interaction with device */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
@@ -190,7 +292,25 @@ struct pvr2_hdw {
/* Tuner / frequency control stuff */
unsigned int tuner_type;
int tuner_updated;
- unsigned long video_standards;
+ unsigned int freqVal;
+ int freqDirty;
+
+ /* Video standard handling */
+ v4l2_std_id std_mask_eeprom; // Hardware supported selections
+ v4l2_std_id std_mask_avail; // Which standards we may select from
+ v4l2_std_id std_mask_cur; // Currently selected standard(s)
+ unsigned int std_enum_cnt; // # of enumerated standards
+ int std_enum_cur; // selected standard enumeration value
+ int std_dirty; // True if std_mask_cur has changed
+ struct pvr2_ctl_info std_info_enum;
+ struct pvr2_ctl_info std_info_avail;
+ struct pvr2_ctl_info std_info_cur;
+ struct v4l2_standard *std_defs;
+ const char **std_enum_names;
+
+ // Generated string names, one per actual V4L2 standard
+ const char *std_mask_ptrs[32];
+ char std_mask_names[32][10];
int unit_number; /* ID for driver instance */
unsigned long serial_number; /* ID for hardware itself */
@@ -209,14 +329,51 @@ struct pvr2_hdw {
int flag_bilingual;
struct pvr2_audio_stat *audio_stat;
- /* Every last bit of controllable state */
- struct pvr2_ctl_state controls[PVR2_CID_COUNT];
+ /* Control state */
+#define VCREATE_DATA(lab) int lab##_val; int lab##_dirty
+ VCREATE_DATA(brightness);
+ VCREATE_DATA(contrast);
+ VCREATE_DATA(saturation);
+ VCREATE_DATA(hue);
+ VCREATE_DATA(volume);
+ VCREATE_DATA(balance);
+ 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);
+#undef VCREATE_DATA
+
+ struct pvr2_ctrl *controls;
};
-int pvr2_hdw_set_ctl_value_internal(struct pvr2_hdw *hdw,
- unsigned int ctl_id,int value);
int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw);
+unsigned int pvr2_hdw_get_signal_status_internal(struct pvr2_hdw *);
+
+void pvr2_hdw_subsys_bit_chg_no_lock(struct pvr2_hdw *hdw,
+ unsigned long msk,unsigned long val);
+void pvr2_hdw_subsys_stream_bit_chg_no_lock(struct pvr2_hdw *hdw,
+ unsigned long msk,
+ unsigned long val);
+
+void pvr2_hdw_internal_find_stdenum(struct pvr2_hdw *hdw);
+void pvr2_hdw_internal_set_std_avail(struct pvr2_hdw *hdw);
+
+int pvr2_i2c_basic_op(struct pvr2_hdw *,u8 i2c_addr,
+ u8 *wdata,u16 wlen,
+ u8 *rdata,u16 rlen);
#endif /* __PVRUSB2_HDW_INTERNAL_H */
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c
index 539456b44..333419d6f 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c
@@ -25,7 +25,9 @@
#include <linux/slab.h>
#include <linux/firmware.h>
#include <asm/semaphore.h>
+#include <media/cx2341x.h>
#include "pvrusb2.h"
+#include "pvrusb2-std.h"
#include "pvrusb2-util.h"
#include "pvrusb2-hdw.h"
#include "pvrusb2-i2c-core.h"
@@ -37,7 +39,9 @@
struct usb_device_id pvr2_device_table[] = {
[PVR2_HDW_TYPE_29XXX] = { USB_DEVICE(0x2040, 0x2900) },
+#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
[PVR2_HDW_TYPE_24XXX] = { USB_DEVICE(0x2040, 0x2400) },
+#endif
{ }
};
@@ -45,7 +49,45 @@ MODULE_DEVICE_TABLE(usb, pvr2_device_table);
static const char *pvr2_device_names[] = {
[PVR2_HDW_TYPE_29XXX] = "WinTV PVR USB2 Model Category 29xxxx",
+#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
[PVR2_HDW_TYPE_24XXX] = "WinTV PVR USB2 Model Category 24xxxx",
+#endif
+};
+
+struct pvr2_string_table {
+ const char **lst;
+ unsigned int cnt;
+};
+
+#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
+// Names of other client modules to request for 24xxx model hardware
+static const char *pvr2_client_24xxx[] = {
+ "cx25840",
+ "tuner",
+ "tda9887",
+ "wm8775",
+};
+#endif
+
+// Names of other client modules to request for 29xxx model hardware
+static const char *pvr2_client_29xxx[] = {
+ "msp3400",
+ "saa7115",
+ "tuner",
+ "tda9887",
+};
+
+static struct pvr2_string_table pvr2_client_lists[] = {
+ [PVR2_HDW_TYPE_29XXX] = {
+ pvr2_client_29xxx,
+ sizeof(pvr2_client_29xxx)/sizeof(pvr2_client_29xxx[0]),
+ },
+#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
+ [PVR2_HDW_TYPE_24XXX] = {
+ pvr2_client_24xxx,
+ sizeof(pvr2_client_24xxx)/sizeof(pvr2_client_24xxx[0]),
+ },
+#endif
};
static struct pvr2_hdw *unit_pointers[PVR_NUM] = {[ 0 ... PVR_NUM-1 ] = 0};
@@ -56,6 +98,7 @@ static int initusbreset = 1;
static int procreload = 0;
static int tuner[PVR_NUM] = { [0 ... PVR_NUM-1] = -1 };
static int tolerance[PVR_NUM] = { [0 ... PVR_NUM-1] = 0 };
+static int video_std[PVR_NUM] = { [0 ... PVR_NUM-1] = 0 };
static int init_pause_msec = 0;
module_param(ctlchg, int, S_IRUGO|S_IWUSR);
@@ -69,6 +112,8 @@ MODULE_PARM_DESC(procreload,
"Attempt init failure recovery with firmware reload");
module_param_array(tuner, int, NULL, 0444);
MODULE_PARM_DESC(tuner,"specify installed tuner type");
+module_param_array(video_std, int, NULL, 0444);
+MODULE_PARM_DESC(video_std,"specify initial video standard");
module_param_array(tolerance, int, NULL, 0444);
MODULE_PARM_DESC(tolerance,"specify stream error tolerance");
@@ -86,22 +131,6 @@ MODULE_PARM_DESC(tolerance,"specify stream error tolerance");
/* size of a firmware chunk */
#define FIRMWARE_CHUNK_SIZE 0x2000
-typedef int (*pvr2_ctl_set_func)(struct pvr2_hdw *,int ctl_id,int val);
-typedef int (*pvr2_ctl_get_func)(struct pvr2_hdw *,int ctl_id);
-
-struct pvr2_ctl_def {
- const char *name;
- pvr2_ctl_set_func set_func;
- pvr2_ctl_get_func get_func;
- int max_value;
- int min_value;
- int skip_init;
- int default_value;
- const char **value_defs_ptr;
- unsigned int value_defs_count;
-};
-
-
static const char *control_values_srate[] = {
[PVR2_CVAL_SRATE_48] = "48KHz",
[PVR2_CVAL_SRATE_44_1] = "44.1KHz",
@@ -134,16 +163,6 @@ static const char *control_values_audioemphasis[] = {
};
-static const char *control_values_videostandard[] = {
- [PVR2_CVAL_VIDEOSTANDARD_NTSC_M] = "NTSC-M",
- [PVR2_CVAL_VIDEOSTANDARD_SECAM_L] = "SECAM-L",
- [PVR2_CVAL_VIDEOSTANDARD_PAL_BG] = "PAL-BG",
- [PVR2_CVAL_VIDEOSTANDARD_PAL_I] = "PAL-I",
- [PVR2_CVAL_VIDEOSTANDARD_PAL_DK] = "PAL-DK",
- [PVR2_CVAL_VIDEOSTANDARD_PAL_M] = "PAL-M",
-};
-
-
static const char *control_values_input[] = {
[PVR2_CVAL_INPUT_TV] = "television", /*xawtv needs this name*/
[PVR2_CVAL_INPUT_RADIO] = "radio",
@@ -153,12 +172,11 @@ static const char *control_values_input[] = {
static const char *control_values_audiomode[] = {
- [PVR2_CVAL_AUDIOMODE_MONO] = "Mono",
- [PVR2_CVAL_AUDIOMODE_STEREO] = "Stereo",
- [PVR2_CVAL_AUDIOMODE_SAP] = "SAP",
- [PVR2_CVAL_AUDIOMODE_LANG1] = "Lang1",
- [PVR2_CVAL_AUDIOMODE_LANG2] = "Lang2",
- [PVR2_CVAL_AUDIOMODE_LANG1_LANG2] = "Lang1+Lang2",
+ [V4L2_TUNER_MODE_MONO] = "Mono",
+ [V4L2_TUNER_MODE_STEREO] = "Stereo",
+ [V4L2_TUNER_MODE_LANG1] = "Lang1",
+ [V4L2_TUNER_MODE_LANG2] = "Lang2",
+ [V4L2_TUNER_MODE_LANG1_LANG2] = "Lang1+Lang2",
};
@@ -169,231 +187,551 @@ static const char *control_values_hsm[] = {
};
-#define VDEF(x) \
- .value_defs_ptr = x, \
- .value_defs_count = (sizeof(x)/sizeof(x[0]))
+static const char *control_values_subsystem[] = {
+ [PVR2_SUBSYS_B_ENC_FIRMWARE] = "enc_firmware",
+ [PVR2_SUBSYS_B_ENC_CFG] = "enc_config",
+ [PVR2_SUBSYS_B_DIGITIZER_RUN] = "digitizer_run",
+ [PVR2_SUBSYS_B_USBSTREAM_RUN] = "usbstream_run",
+ [PVR2_SUBSYS_B_ENC_RUN] = "enc_run",
+};
+
+
+static int ctrl_channelfreq_get(struct pvr2_ctrl *cptr,int *vp)
+{
+ struct pvr2_hdw *hdw = cptr->hdw;
+ if ((hdw->freqProgSlot > 0) && (hdw->freqProgSlot <= FREQTABLE_SIZE)) {
+ *vp = hdw->freqTable[hdw->freqProgSlot-1];
+ } else {
+ *vp = 0;
+ }
+ return 0;
+}
+
+static int ctrl_channelfreq_set(struct pvr2_ctrl *cptr,int m,int v)
+{
+ struct pvr2_hdw *hdw = cptr->hdw;
+ if ((hdw->freqProgSlot > 0) && (hdw->freqProgSlot <= FREQTABLE_SIZE)) {
+ hdw->freqTable[hdw->freqProgSlot-1] = v;
+ }
+ return 0;
+}
+
+static int ctrl_channelprog_get(struct pvr2_ctrl *cptr,int *vp)
+{
+ *vp = cptr->hdw->freqProgSlot;
+ return 0;
+}
+
+static int ctrl_channelprog_set(struct pvr2_ctrl *cptr,int m,int v)
+{
+ struct pvr2_hdw *hdw = cptr->hdw;
+ if ((v >= 0) && (v <= FREQTABLE_SIZE)) {
+ hdw->freqProgSlot = v;
+ }
+ return 0;
+}
+
+static int ctrl_channel_get(struct pvr2_ctrl *cptr,int *vp)
+{
+ *vp = cptr->hdw->freqSlot;
+ return 0;
+}
+
+static int ctrl_channel_set(struct pvr2_ctrl *cptr,int m,int v)
+{
+ unsigned freq = 0;
+ struct pvr2_hdw *hdw = cptr->hdw;
+ hdw->freqSlot = v;
+ if ((hdw->freqSlot > 0) && (hdw->freqSlot <= FREQTABLE_SIZE)) {
+ freq = hdw->freqTable[hdw->freqSlot-1];
+ }
+ if (freq && (freq != hdw->freqVal)) {
+ hdw->freqVal = freq;
+ hdw->freqDirty = !0;
+ }
+ return 0;
+}
+
+static int ctrl_freq_get(struct pvr2_ctrl *cptr,int *vp)
+{
+ *vp = cptr->hdw->freqVal;
+ return 0;
+}
+
+static int ctrl_freq_is_dirty(struct pvr2_ctrl *cptr)
+{
+ return cptr->hdw->freqDirty != 0;
+}
+
+static void ctrl_freq_clear_dirty(struct pvr2_ctrl *cptr)
+{
+ cptr->hdw->freqDirty = 0;
+}
+
+static int ctrl_freq_set(struct pvr2_ctrl *cptr,int m,int v)
+{
+ struct pvr2_hdw *hdw = cptr->hdw;
+ hdw->freqVal = v;
+ hdw->freqDirty = !0;
+ hdw->freqSlot = 0;
+ return 0;
+}
+
+static int ctrl_streamingenabled_get(struct pvr2_ctrl *cptr,int *vp)
+{
+ *vp = cptr->hdw->flag_streaming_enabled;
+ return 0;
+}
+
+static int ctrl_hsm_get(struct pvr2_ctrl *cptr,int *vp)
+{
+ int result = pvr2_hdw_is_hsm(cptr->hdw);
+ *vp = PVR2_CVAL_HSM_FULL;
+ if (result < 0) *vp = PVR2_CVAL_HSM_FAIL;
+ if (result) *vp = PVR2_CVAL_HSM_HIGH;
+ return 0;
+}
+
+static int ctrl_stdavail_get(struct pvr2_ctrl *cptr,int *vp)
+{
+ *vp = cptr->hdw->std_mask_avail;
+ return 0;
+}
+
+static int ctrl_stdavail_set(struct pvr2_ctrl *cptr,int m,int v)
+{
+ struct pvr2_hdw *hdw = cptr->hdw;
+ v4l2_std_id ns;
+ ns = hdw->std_mask_avail;
+ ns = (ns & ~m) | (v & m);
+ if (ns == hdw->std_mask_avail) return 0;
+ hdw->std_mask_avail = ns;
+ pvr2_hdw_internal_set_std_avail(hdw);
+ pvr2_hdw_internal_find_stdenum(hdw);
+ return 0;
+}
+
+static int ctrl_std_val_to_sym(struct pvr2_ctrl *cptr,int msk,int val,
+ char *bufPtr,unsigned int bufSize,
+ unsigned int *len)
+{
+ *len = pvr2_std_id_to_str(bufPtr,bufSize,msk & val);
+ return 0;
+}
+
+static int ctrl_std_sym_to_val(struct pvr2_ctrl *cptr,
+ const char *bufPtr,unsigned int bufSize,
+ int *mskp,int *valp)
+{
+ int ret;
+ v4l2_std_id id;
+ ret = pvr2_std_str_to_id(&id,bufPtr,bufSize);
+ if (ret < 0) return ret;
+ if (mskp) *mskp = id;
+ if (valp) *valp = id;
+ return 0;
+}
+
+static int ctrl_stdcur_get(struct pvr2_ctrl *cptr,int *vp)
+{
+ *vp = cptr->hdw->std_mask_cur;
+ return 0;
+}
+
+static int ctrl_stdcur_set(struct pvr2_ctrl *cptr,int m,int v)
+{
+ struct pvr2_hdw *hdw = cptr->hdw;
+ v4l2_std_id ns;
+ ns = hdw->std_mask_cur;
+ ns = (ns & ~m) | (v & m);
+ if (ns == hdw->std_mask_cur) return 0;
+ hdw->std_mask_cur = ns;
+ hdw->std_dirty = !0;
+ pvr2_hdw_internal_find_stdenum(hdw);
+ return 0;
+}
+
+static int ctrl_stdcur_is_dirty(struct pvr2_ctrl *cptr)
+{
+ return cptr->hdw->std_dirty != 0;
+}
+
+static void ctrl_stdcur_clear_dirty(struct pvr2_ctrl *cptr)
+{
+ cptr->hdw->std_dirty = 0;
+}
+
+static int ctrl_signal_get(struct pvr2_ctrl *cptr,int *vp)
+{
+ *vp = ((pvr2_hdw_get_signal_status_internal(cptr->hdw) &
+ PVR2_SIGNAL_OK) ? 1 : 0);
+ return 0;
+}
+
+static int ctrl_subsys_get(struct pvr2_ctrl *cptr,int *vp)
+{
+ *vp = cptr->hdw->subsys_enabled_mask;
+ return 0;
+}
+
+static int ctrl_subsys_set(struct pvr2_ctrl *cptr,int m,int v)
+{
+ pvr2_hdw_subsys_bit_chg_no_lock(cptr->hdw,m,v);
+ return 0;
+}
+
+static int ctrl_subsys_stream_get(struct pvr2_ctrl *cptr,int *vp)
+{
+ *vp = cptr->hdw->subsys_stream_mask;
+ return 0;
+}
+
+static int ctrl_subsys_stream_set(struct pvr2_ctrl *cptr,int m,int v)
+{
+ pvr2_hdw_subsys_stream_bit_chg_no_lock(cptr->hdw,m,v);
+ return 0;
+}
+
+static int ctrl_stdenumcur_set(struct pvr2_ctrl *cptr,int m,int v)
+{
+ struct pvr2_hdw *hdw = cptr->hdw;
+ if (v < 0) return -EINVAL;
+ if (v > hdw->std_enum_cnt) return -EINVAL;
+ hdw->std_enum_cur = v;
+ if (!v) return 0;
+ v--;
+ if (hdw->std_mask_cur == hdw->std_defs[v].id) return 0;
+ hdw->std_mask_cur = hdw->std_defs[v].id;
+ hdw->std_dirty = !0;
+ return 0;
+}
+
+
+static int ctrl_stdenumcur_get(struct pvr2_ctrl *cptr,int *vp)
+{
+ *vp = cptr->hdw->std_enum_cur;
+ return 0;
+}
-static int pvr2_ctl_set_chanprog_id(struct pvr2_hdw *hdw,int ctl_id,int value);
-static int pvr2_ctl_get_chanprog_id(struct pvr2_hdw *hdw,int ctl_id);
-static int pvr2_ctl_get_signal(struct pvr2_hdw *hdw,int ctl_id);
-static int pvr2_ctl_get_streaming(struct pvr2_hdw *hdw,int ctl_id);
-static int pvr2_ctl_get_hsm(struct pvr2_hdw *hdw,int ctl_id);
-static int pvr2_ctl_get_subsys_mask(struct pvr2_hdw *hdw,int ctl_id);
-static int pvr2_ctl_set_subsys_mask(struct pvr2_hdw *hdw,int ctl_id,int val);
-static int pvr2_ctl_get_subsys_stream_mask(struct pvr2_hdw *hdw,int ctl_id);
-static int pvr2_ctl_set_subsys_stream_mask(struct pvr2_hdw *hdw,int ctl_id,
- int val);
-static struct pvr2_ctl_def control_defs[PVR2_CID_COUNT] =
+static int ctrl_stdenumcur_is_dirty(struct pvr2_ctrl *cptr)
{
- [PVR2_CID_BRIGHTNESS] = {
- .name = "Brightness",
- .min_value = 0,
- .max_value = 255,
+ return cptr->hdw->std_dirty != 0;
+}
+
+
+static void ctrl_stdenumcur_clear_dirty(struct pvr2_ctrl *cptr)
+{
+ cptr->hdw->std_dirty = 0;
+}
+
+
+#define DEFINT(vmin,vmax) \
+ .type = pvr2_ctl_int, \
+ .def.type_int.min_value = vmin, \
+ .def.type_int.max_value = vmax
+
+#define DEFENUM(tab) \
+ .type = pvr2_ctl_enum, \
+ .def.type_enum.count = (sizeof(tab)/sizeof((tab)[0])), \
+ .def.type_enum.value_names = tab
+
+#define DEFMASK(msk,tab) \
+ .type = pvr2_ctl_bitmask, \
+ .def.type_bitmask.valid_bits = msk, \
+ .def.type_bitmask.bit_names = tab
+
+#define DEFREF(vname) \
+ .set_value = ctrl_set_##vname, \
+ .get_value = ctrl_get_##vname, \
+ .is_dirty = ctrl_isdirty_##vname, \
+ .clear_dirty = ctrl_cleardirty_##vname
+
+
+#define VCREATE_FUNCS(vname) \
+static int ctrl_get_##vname(struct pvr2_ctrl *cptr,int *vp) \
+{*vp = cptr->hdw->vname##_val; return 0;} \
+static int ctrl_set_##vname(struct pvr2_ctrl *cptr,int m,int v) \
+{cptr->hdw->vname##_val = v; cptr->hdw->vname##_dirty = !0; return 0;} \
+static int ctrl_isdirty_##vname(struct pvr2_ctrl *cptr) \
+{return cptr->hdw->vname##_dirty != 0;} \
+static void ctrl_cleardirty_##vname(struct pvr2_ctrl *cptr) \
+{cptr->hdw->vname##_dirty = 0;}
+
+VCREATE_FUNCS(brightness)
+VCREATE_FUNCS(contrast)
+VCREATE_FUNCS(saturation)
+VCREATE_FUNCS(hue)
+VCREATE_FUNCS(volume)
+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)
+
+#define MIN_FREQ 55250000L
+#define MAX_FREQ 850000000L
+
+/* Table definition of all controls which can be manipulated */
+static const struct pvr2_ctl_info control_defs[] = {
+ {
+ .v4l_id = V4L2_CID_BRIGHTNESS,
+ .desc = "Brightness",
+ .name = "brightness",
.default_value = 128,
- },
- [PVR2_CID_CONTRAST] = {
- .name = "Contrast",
- .min_value = 0,
- .max_value = 127,
+ DEFREF(brightness),
+ DEFINT(0,255),
+ },{
+ .v4l_id = V4L2_CID_CONTRAST,
+ .desc = "Contrast",
+ .name = "contrast",
.default_value = 68,
- },
- [PVR2_CID_SATURATION] = {
- .name = "Saturation",
- .min_value = 0,
- .max_value = 127,
+ DEFREF(contrast),
+ DEFINT(0,127),
+ },{
+ .v4l_id = V4L2_CID_SATURATION,
+ .desc = "Saturation",
+ .name = "saturation",
.default_value = 64,
- },
- [PVR2_CID_HUE] = {
- .name = "Hue",
- .min_value = -128,
- .max_value = 127,
+ DEFREF(saturation),
+ DEFINT(0,127),
+ },{
+ .v4l_id = V4L2_CID_HUE,
+ .desc = "Hue",
+ .name = "hue",
.default_value = 0,
- },
- [PVR2_CID_VOLUME] = {
- .name = "Volume",
- .min_value = 0,
- .max_value = 65535,
+ DEFREF(hue),
+ DEFINT(-128,127),
+ },{
+ .v4l_id = V4L2_CID_AUDIO_VOLUME,
+ .desc = "Volume",
+ .name = "volume",
.default_value = 65535,
- },
- [PVR2_CID_BALANCE] = {
- .name = "Balance",
- .min_value = -32768,
- .max_value = 32767,
+ DEFREF(volume),
+ DEFINT(0,65535),
+ },{
+ .v4l_id = V4L2_CID_AUDIO_BALANCE,
+ .desc = "Balance",
+ .name = "balance",
.default_value = 0,
- },
- [PVR2_CID_BASS] = {
- .name = "Bass",
- .min_value = -32768,
- .max_value = 32767,
+ DEFREF(balance),
+ DEFINT(-32768,32767),
+ },{
+ .v4l_id = V4L2_CID_AUDIO_BASS,
+ .desc = "Bass",
+ .name = "bass",
.default_value = 0,
- },
- [PVR2_CID_TREBLE] = {
- .name = "Treble",
- .min_value = -32768,
- .max_value = 32767,
+ DEFREF(bass),
+ DEFINT(-32768,32767),
+ },{
+ .v4l_id = V4L2_CID_AUDIO_TREBLE,
+ .desc = "Treble",
+ .name = "treble",
.default_value = 0,
- },
- [PVR2_CID_MUTE] = {
- .name = "Mute",
- .min_value = 0,
- .max_value = 1,
+ DEFREF(treble),
+ DEFINT(-32768,32767),
+ },{
+ .v4l_id = V4L2_CID_AUDIO_MUTE,
+ .desc = "Mute",
+ .name = "mute",
.default_value = 0,
- },
- [PVR2_CID_SRATE] = {
- .name = "Sample rate",
- .min_value = PVR2_CVAL_SRATE_MIN,
- .max_value = PVR2_CVAL_SRATE_MAX,
+ DEFREF(mute),
+ DEFINT(0,1),
+ },{
+ .v4l_id = V4L2_CID_PVR_SRATE,
+ .desc = "Sample rate",
+ .name = "srate",
.default_value = PVR2_CVAL_SRATE_48,
- VDEF(control_values_srate),
- },
- [PVR2_CID_AUDIOBITRATE] = {
- .name = "Audio Bitrate",
- .min_value = PVR2_CVAL_AUDIOBITRATE_MIN,
- .max_value = PVR2_CVAL_AUDIOBITRATE_MAX,
+ DEFREF(srate),
+ DEFENUM(control_values_srate),
+ },{
+ .v4l_id = V4L2_CID_PVR_AUDIOBITRATE,
+ .desc = "Audio Bitrate",
+ .name = "audio_bitrate",
.default_value = PVR2_CVAL_AUDIOBITRATE_224,
- VDEF(control_values_audiobitrate),
- },
- [PVR2_CID_AUDIOCRC] = {
- .name = "Audio CRC",
- .min_value = 0,
- .max_value = 1,
+ DEFREF(audiobitrate),
+ DEFENUM(control_values_audiobitrate),
+ },{
+ .v4l_id = V4L2_CID_PVR_AUDIOCRC,
+ .desc = "Audio CRC",
+ .name = "audio_crc",
.default_value = 1,
- },
- [PVR2_CID_AUDIOEMPHASIS] = {
- .name = "Audio Emphasis",
- .min_value = PVR2_CVAL_AUDIOEMPHASIS_MIN,
- .max_value = PVR2_CVAL_AUDIOEMPHASIS_MAX,
+ 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,
- VDEF(control_values_audioemphasis),
- },
- [PVR2_CID_VBR] = {
- .name = "Variable video bitrate",
- .min_value = 0,
- .max_value = 1,
+ DEFREF(audioemphasis),
+ DEFENUM(control_values_audioemphasis),
+ },{
+ .desc = "Interlace mode",
+ .name = "interlace",
+ .internal_id = PVR2_CID_INTERLACE,
.default_value = 0,
- },
- [PVR2_CID_AVERAGEVIDEOBITRATE] = {
- .name = "Average video bitrate",
- .min_value = 1,
- .max_value = 20000000,
+ 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,
- },
- [PVR2_CID_PEAKVIDEOBITRATE] = {
- .name = "Peak video bitrate",
- .min_value = 1,
- .max_value = 20000000,
+ DEFREF(videobitrate),
+ DEFINT(500000,20000000),
+ },{
+ .v4l_id = V4L2_CID_PVR_VIDEOPEAK,
+ .desc = "Peak video bitrate",
+ .name = "video_peak_bitrate",
.default_value = 6000000,
- },
- [PVR2_CID_VIDEOSTANDARD] = {
- .name = "Video Standard",
- .min_value = PVR2_CVAL_VIDEOSTANDARD_MIN,
- .max_value = PVR2_CVAL_VIDEOSTANDARD_MAX,
- .default_value = PVR2_CVAL_VIDEOSTANDARD_NTSC_M,
- VDEF(control_values_videostandard),
- },
- [PVR2_CID_INPUT] = {
- .name = "Video Source",
- .min_value = PVR2_CVAL_INPUT_MIN,
- .max_value = PVR2_CVAL_INPUT_MAX,
+ DEFREF(videopeak),
+ DEFINT(500000,20000000),
+ },{
+ .desc = "Video Source",
+ .name = "input",
+ .internal_id = PVR2_CID_INPUT,
.default_value = PVR2_CVAL_INPUT_TV,
- VDEF(control_values_input),
- },
- [PVR2_CID_AUDIOMODE] = {
- .name = "Audio Mode",
- .min_value = PVR2_CVAL_AUDIOMODE_MIN,
- .max_value = PVR2_CVAL_AUDIOMODE_MAX,
- .default_value = PVR2_CVAL_AUDIOMODE_STEREO,
- VDEF(control_values_audiomode),
- },
- [PVR2_CID_FREQUENCY] = {
- .name = "Tuner Frequency (Hz)",
- .min_value = 55250000L,
- .max_value = 850000000L,
+ DEFREF(input),
+ DEFENUM(control_values_input),
+ },{
+ .desc = "Audio Mode",
+ .name = "audio_mode",
+ .internal_id = PVR2_CID_AUDIOMODE,
+ .default_value = V4L2_TUNER_MODE_STEREO,
+ DEFREF(audiomode),
+ DEFENUM(control_values_audiomode),
+ },{
+ .desc = "Tuner Frequency (Hz)",
+ .name = "frequency",
+ .internal_id = PVR2_CID_FREQUENCY,
.default_value = 175250000L,
- },
- [PVR2_CID_HRES] = {
- .name = "Horizontal capture resolution",
- .min_value = 320,
- .max_value = 720,
+ .set_value = ctrl_freq_set,
+ .get_value = ctrl_freq_get,
+ .is_dirty = ctrl_freq_is_dirty,
+ .clear_dirty = ctrl_freq_clear_dirty,
+ DEFINT(MIN_FREQ,MAX_FREQ),
+ },{
+ .desc = "Channel",
+ .name = "channel",
+ .set_value = ctrl_channel_set,
+ .get_value = ctrl_channel_get,
+ DEFINT(0,FREQTABLE_SIZE),
+ },{
+ .desc = "Channel Program Frequency",
+ .name = "freq_table_value",
+ .set_value = ctrl_channelfreq_set,
+ .get_value = ctrl_channelfreq_get,
+ DEFINT(MIN_FREQ,MAX_FREQ),
+ },{
+ .desc = "Channel Program ID",
+ .name = "freq_table_channel",
+ .set_value = ctrl_channelprog_set,
+ .get_value = ctrl_channelprog_get,
+ DEFINT(0,FREQTABLE_SIZE),
+ },{
+ .desc = "Horizontal capture resolution",
+ .name = "resolution_hor",
+ .internal_id = PVR2_CID_HRES,
.default_value = 720,
- },
- [PVR2_CID_VRES] = {
- .name = "Vertical capture resolution",
- .min_value = 200,
- .max_value = 625,
+ DEFREF(res_hor),
+ DEFINT(320,720),
+ },{
+ .desc = "Vertical capture resolution",
+ .name = "resolution_ver",
+ .internal_id = PVR2_CID_VRES,
.default_value = 480,
- },
- [PVR2_CID_INTERLACE] = {
- .name = "Interlace mode",
- .min_value = 0,
- .max_value = 1,
- .default_value = 0,
- },
- [PVR2_CID_AUDIOLAYER] = {
- .name = "Audio Layer",
- .min_value = 0, /* This is all a wild guess */
- .max_value = 3,
- .default_value = 2, /* Appears to be all that is supported */
- },
- [PVR2_CID_CHANNEL] = {
- .name = "Channel",
- .min_value = 0,
- .max_value = FREQTABLE_SIZE,
- .default_value = 0,
- },
- [PVR2_CID_CHANPROG_ID] = {
- .name = "Channel Program ID",
- .min_value = 0,
- .max_value = FREQTABLE_SIZE,
- .default_value = 0,
- },
- [PVR2_CID_CHANPROG_FREQ] = {
- .name = "Channel Program Frequency",
- .min_value = 55250000L,
- .max_value = 850000000L,
+ DEFREF(res_ver),
+ DEFINT(200,625),
+ },{
+ .desc = "Streaming Enabled",
+ .name = "streaming_enabled",
+ .get_value = ctrl_streamingenabled_get,
+ DEFINT(0,1),
+ },{
+ .desc = "USB Speed",
+ .name = "usb_speed",
+ .get_value = ctrl_hsm_get,
+ DEFENUM(control_values_hsm),
+ },{
+ .desc = "Signal Present",
+ .name = "signal_present",
+ .get_value = ctrl_signal_get,
+ DEFINT(0,1),
+ },{
+ .desc = "Video Standards Available Mask",
+ .name = "video_standard_mask_available",
+ .internal_id = PVR2_CID_STDAVAIL,
.skip_init = !0,
- .set_func = pvr2_ctl_set_chanprog_id,
- .get_func = pvr2_ctl_get_chanprog_id,
- },
- [PVR2_CID_SIGNAL_PRESENT] = {
- .name = "Signal Present",
- .min_value = 0,
- .max_value = 1,
- .get_func = pvr2_ctl_get_signal,
- },
- [PVR2_CID_STREAMING_ENABLED] = {
- .name = "Streaming Enabled",
- .min_value = 0,
- .max_value = 1,
- .get_func = pvr2_ctl_get_streaming,
- },
- [PVR2_CID_HSM] = {
- .name = "USB Speed",
- .min_value = PVR2_CVAL_HSM_MIN,
- .max_value = PVR2_CVAL_HSM_MAX,
- .get_func = pvr2_ctl_get_hsm,
- VDEF(control_values_hsm),
- },
- [PVR2_CID_SUBSYS_MASK] = {
- .name = "Subsystem enabled mask",
- .min_value = 0,
- .max_value = 0x7fffffff,
+ .get_value = ctrl_stdavail_get,
+ .set_value = ctrl_stdavail_set,
+ .val_to_sym = ctrl_std_val_to_sym,
+ .sym_to_val = ctrl_std_sym_to_val,
+ .type = pvr2_ctl_bitmask,
+ },{
+ .desc = "Video Standards In Use Mask",
+ .name = "video_standard_mask_active",
+ .internal_id = PVR2_CID_STDCUR,
.skip_init = !0,
- .get_func = pvr2_ctl_get_subsys_mask,
- .set_func = pvr2_ctl_set_subsys_mask,
- },
- [PVR2_CID_SUBSYS_STREAM_MASK] = {
- .name = "Subsystem stream mask",
- .min_value = 0,
- .max_value = 0x7fffffff,
+ .get_value = ctrl_stdcur_get,
+ .set_value = ctrl_stdcur_set,
+ .is_dirty = ctrl_stdcur_is_dirty,
+ .clear_dirty = ctrl_stdcur_clear_dirty,
+ .val_to_sym = ctrl_std_val_to_sym,
+ .sym_to_val = ctrl_std_sym_to_val,
+ .type = pvr2_ctl_bitmask,
+ },{
+ .desc = "Subsystem enabled mask",
+ .name = "debug_subsys_mask",
.skip_init = !0,
- .get_func = pvr2_ctl_get_subsys_stream_mask,
- .set_func = pvr2_ctl_set_subsys_stream_mask,
- },
+ .get_value = ctrl_subsys_get,
+ .set_value = ctrl_subsys_set,
+ DEFMASK(PVR2_SUBSYS_ALL,control_values_subsystem),
+ },{
+ .desc = "Subsystem stream mask",
+ .name = "debug_subsys_stream_mask",
+ .skip_init = !0,
+ .get_value = ctrl_subsys_stream_get,
+ .set_value = ctrl_subsys_stream_set,
+ DEFMASK(PVR2_SUBSYS_ALL,control_values_subsystem),
+ },{
+ .desc = "Video Standard Name",
+ .name = "video_standard",
+ .internal_id = PVR2_CID_STDENUM,
+ .skip_init = !0,
+ .get_value = ctrl_stdenumcur_get,
+ .set_value = ctrl_stdenumcur_set,
+ .is_dirty = ctrl_stdenumcur_is_dirty,
+ .clear_dirty = ctrl_stdenumcur_clear_dirty,
+ .type = pvr2_ctl_enum,
+ }
};
-#undef VDEF
+#define CTRL_COUNT (sizeof(control_defs)/sizeof(control_defs[0]))
const char *pvr2_config_get_name(enum pvr2_config cfg)
@@ -511,21 +849,22 @@ int pvr2_upload_firmware1(struct pvr2_hdw *hdw)
static const char *fw_files_29xxx[] = {
"v4l-pvrusb2-29xxx-01.fw",
};
+#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
static const char *fw_files_24xxx[] = {
"v4l-pvrusb2-24xxx-01.fw",
};
- static const struct {
- const char **lst;
- unsigned int cnt;
- } fw_file_defs[] = {
+#endif
+ static const struct pvr2_string_table fw_file_defs[] = {
[PVR2_HDW_TYPE_29XXX] = {
fw_files_29xxx,
sizeof(fw_files_29xxx)/sizeof(fw_files_29xxx[0]),
},
+#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
[PVR2_HDW_TYPE_24XXX] = {
fw_files_24xxx,
sizeof(fw_files_24xxx)/sizeof(fw_files_24xxx[0]),
},
+#endif
};
hdw->fw1_state = FW1_STATE_FAILED; // default result
@@ -605,7 +944,7 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
int ret = 0;
int fwidx;
static const char *fw_files[] = {
- "v4l-cx2341x-enc.fw",
+ CX2341X_FIRM_ENC_FILENAME,
};
trace_firmware("pvr2_upload_firmware2");
@@ -618,7 +957,6 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
ret = 0;
/* First prepare firmware loading */
- ret |= pvr2_hdw_cmd_soft_reset(hdw);
ret |= pvr2_write_register(hdw, 0x0048, 0xffffffff); /*interrupt mask*/
ret |= pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000088); /*gpio dir*/
ret |= pvr2_hdw_gpio_chg_out(hdw,0xffffffff,0x00000008); /*gpio output state*/
@@ -704,17 +1042,17 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
"firmware2 upload post-proc failure");
} else {
- hdw->subsys_enabled_mask |= PVR2_SUBSYS_ENC_FIRMWARE;
+ hdw->subsys_enabled_mask |= (1<<PVR2_SUBSYS_B_ENC_FIRMWARE);
}
return ret;
}
#define FIRMWARE_RECOVERY_BITS \
- (PVR2_SUBSYS_ENC_CFG | \
- PVR2_SUBSYS_ENC_RUN | \
- PVR2_SUBSYS_ENC_FIRMWARE | \
- PVR2_SUBSYS_USBSTREAM_RUN)
+ ((1<<PVR2_SUBSYS_B_ENC_CFG) | \
+ (1<<PVR2_SUBSYS_B_ENC_RUN) | \
+ (1<<PVR2_SUBSYS_B_ENC_FIRMWARE) | \
+ (1<<PVR2_SUBSYS_B_USBSTREAM_RUN))
/*
@@ -782,7 +1120,7 @@ void pvr2_hdw_subsys_bit_chg_no_lock(struct pvr2_hdw *hdw,
vmsk = (nmsk ^ hdw->subsys_enabled_mask) &
hdw->subsys_enabled_mask;
if (vmsk) {
- if (vmsk & PVR2_SUBSYS_ENC_RUN) {
+ if (vmsk & (1<<PVR2_SUBSYS_B_ENC_RUN)) {
pvr2_trace(PVR2_TRACE_CTL,
"/*---TRACE_CTL----*/"
" pvr2_encoder_stop");
@@ -795,13 +1133,13 @@ void pvr2_hdw_subsys_bit_chg_no_lock(struct pvr2_hdw *hdw,
continue;
}
}
- if (vmsk & PVR2_SUBSYS_USBSTREAM_RUN) {
+ if (vmsk & (1<<PVR2_SUBSYS_B_USBSTREAM_RUN)) {
pvr2_trace(PVR2_TRACE_CTL,
"/*---TRACE_CTL----*/"
" pvr2_hdw_cmd_usbstream(0)");
pvr2_hdw_cmd_usbstream(hdw,0);
}
- if (vmsk & PVR2_SUBSYS_DIGITIZER_RUN) {
+ if (vmsk & (1<<PVR2_SUBSYS_B_DIGITIZER_RUN)) {
pvr2_trace(PVR2_TRACE_CTL,
"/*---TRACE_CTL----*/"
" decoder disable");
@@ -814,7 +1152,7 @@ void pvr2_hdw_subsys_bit_chg_no_lock(struct pvr2_hdw *hdw,
" No decoder present");
}
hdw->subsys_enabled_mask &=
- ~PVR2_SUBSYS_DIGITIZER_RUN;
+ ~(1<<PVR2_SUBSYS_B_DIGITIZER_RUN);
}
if (vmsk & PVR2_SUBSYS_CFG_ALL) {
hdw->subsys_enabled_mask &=
@@ -823,7 +1161,7 @@ void pvr2_hdw_subsys_bit_chg_no_lock(struct pvr2_hdw *hdw,
}
vmsk = (nmsk ^ hdw->subsys_enabled_mask) & nmsk;
if (vmsk) {
- if (vmsk & PVR2_SUBSYS_ENC_FIRMWARE) {
+ if (vmsk & (1<<PVR2_SUBSYS_B_ENC_FIRMWARE)) {
pvr2_trace(PVR2_TRACE_CTL,
"/*---TRACE_CTL----*/"
" pvr2_upload_firmware2");
@@ -836,7 +1174,7 @@ void pvr2_hdw_subsys_bit_chg_no_lock(struct pvr2_hdw *hdw,
break;
}
}
- if (vmsk & PVR2_SUBSYS_ENC_CFG) {
+ if (vmsk & (1<<PVR2_SUBSYS_B_ENC_CFG)) {
pvr2_trace(PVR2_TRACE_CTL,
"/*---TRACE_CTL----*/"
" pvr2_encoder_configure");
@@ -849,7 +1187,7 @@ void pvr2_hdw_subsys_bit_chg_no_lock(struct pvr2_hdw *hdw,
continue;
}
}
- if (vmsk & PVR2_SUBSYS_DIGITIZER_RUN) {
+ if (vmsk & (1<<PVR2_SUBSYS_B_DIGITIZER_RUN)) {
pvr2_trace(PVR2_TRACE_CTL,
"/*---TRACE_CTL----*/"
" decoder enable");
@@ -862,15 +1200,15 @@ void pvr2_hdw_subsys_bit_chg_no_lock(struct pvr2_hdw *hdw,
" No decoder present");
}
hdw->subsys_enabled_mask |=
- PVR2_SUBSYS_DIGITIZER_RUN;
+ (1<<PVR2_SUBSYS_B_DIGITIZER_RUN);
}
- if (vmsk & PVR2_SUBSYS_USBSTREAM_RUN) {
+ if (vmsk & (1<<PVR2_SUBSYS_B_USBSTREAM_RUN)) {
pvr2_trace(PVR2_TRACE_CTL,
"/*---TRACE_CTL----*/"
" pvr2_hdw_cmd_usbstream(1)");
pvr2_hdw_cmd_usbstream(hdw,!0);
}
- if (vmsk & PVR2_SUBSYS_ENC_RUN) {
+ if (vmsk & (1<<PVR2_SUBSYS_B_ENC_RUN)) {
pvr2_trace(PVR2_TRACE_CTL,
"/*---TRACE_CTL----*/"
" pvr2_encoder_start");
@@ -945,12 +1283,6 @@ void pvr2_hdw_subsys_stream_bit_chg(struct pvr2_hdw *hdw,
}
-static int pvr2_ctl_get_streaming(struct pvr2_hdw *hdw,int ctl_id)
-{
- return hdw->flag_streaming_enabled != 0;
-}
-
-
int pvr2_hdw_set_streaming_no_lock(struct pvr2_hdw *hdw,int enableFl)
{
if ((!enableFl) == !(hdw->flag_streaming_enabled)) return 0;
@@ -1021,6 +1353,17 @@ static int get_default_tuner_type(struct pvr2_hdw *hdw)
}
+static v4l2_std_id get_default_standard(struct pvr2_hdw *hdw)
+{
+ int unit_number = hdw->unit_number;
+ int tp = 0;
+ if ((unit_number >= 0) && (unit_number < PVR_NUM)) {
+ tp = video_std[unit_number];
+ }
+ return tp;
+}
+
+
static unsigned int get_default_error_tolerance(struct pvr2_hdw *hdw)
{
int unit_number = hdw->unit_number;
@@ -1057,11 +1400,65 @@ static int pvr2_hdw_check_firmware(struct pvr2_hdw *hdw)
return result == 0;
}
+static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw)
+{
+ char buf[40];
+ unsigned int bcnt;
+ v4l2_std_id std1,std2;
+
+ std1 = get_default_standard(hdw);
+
+ bcnt = pvr2_std_id_to_str(buf,sizeof(buf),hdw->std_mask_eeprom);
+ pvr2_trace(PVR2_TRACE_INIT,
+ "Supported video standard(s) reported by eeprom: %.*s",
+ bcnt,buf);
+
+ hdw->std_mask_avail = hdw->std_mask_eeprom;
+
+ std2 = std1 & ~hdw->std_mask_avail;
+ if (std2) {
+ bcnt = pvr2_std_id_to_str(buf,sizeof(buf),std2);
+ pvr2_trace(PVR2_TRACE_INIT,
+ "Expanding supported video standards"
+ " to include: %.*s",
+ bcnt,buf);
+ hdw->std_mask_avail |= std2;
+ }
+
+ pvr2_hdw_internal_set_std_avail(hdw);
+
+ if (std1) {
+ bcnt = pvr2_std_id_to_str(buf,sizeof(buf),std1);
+ pvr2_trace(PVR2_TRACE_INIT,
+ "Initial video standard forced to %.*s",
+ bcnt,buf);
+ hdw->std_mask_cur = std1;
+ hdw->std_dirty = !0;
+ pvr2_hdw_internal_find_stdenum(hdw);
+ return;
+ }
+
+ if (hdw->std_enum_cnt > 1) {
+ // Autoselect the first listed standard
+ hdw->std_enum_cur = 1;
+ hdw->std_mask_cur = hdw->std_defs[hdw->std_enum_cur-1].id;
+ hdw->std_dirty = !0;
+ pvr2_trace(PVR2_TRACE_INIT,
+ "Initial video standard auto-selected to %s",
+ hdw->std_defs[hdw->std_enum_cur-1].name);
+ return;
+ }
+
+ pvr2_trace(PVR2_TRACE_EEPROM,
+ "Unable to select a viable initial video standard");
+}
+
static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
{
int ret;
unsigned int idx;
+ struct pvr2_ctrl *cptr;
int reloadFl = 0;
if (!reloadFl) {
reloadFl = (hdw->usb_intf->cur_altsetting->desc.bNumEndpoints
@@ -1094,7 +1491,11 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
}
if (!pvr2_hdw_dev_ok(hdw)) return;
- pvr2_i2c_core_init(hdw);
+ for (idx = 0; idx < pvr2_client_lists[hdw->hdw_type].cnt; idx++) {
+ request_module(pvr2_client_lists[hdw->hdw_type].lst[idx]);
+ }
+
+ pvr2_hdw_cmd_powerup(hdw);
if (!pvr2_hdw_dev_ok(hdw)) return;
if (pvr2_upload_firmware2(hdw)){
@@ -1103,14 +1504,20 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
return;
}
- for (idx = 0; idx < PVR2_CID_COUNT; idx++) {
- if (control_defs[idx].skip_init) continue;
- pvr2_hdw_set_ctl_value_internal(
- hdw,idx,control_defs[idx].default_value);
+ // This step MUST happen after the earlier powerup step.
+ pvr2_i2c_core_init(hdw);
+ if (!pvr2_hdw_dev_ok(hdw)) return;
+
+ for (idx = 0; idx < CTRL_COUNT; idx++) {
+ cptr = hdw->controls + idx;
+ if (cptr->info->skip_init) continue;
+ if (!cptr->info->set_value) continue;
+ cptr->info->set_value(cptr,~0,cptr->info->default_value);
}
- pvr2_reset_ctl_endpoints(hdw);
- if (!pvr2_hdw_dev_ok(hdw)) return;
+ // Do not use pvr2_reset_ctl_endpoints() here. It is not
+ // thread-safe against the normal pvr2_send_request() mechanism.
+ // (We should make it thread safe).
ret = pvr2_hdw_get_eeprom_addr(hdw);
if (!pvr2_hdw_dev_ok(hdw)) return;
@@ -1123,6 +1530,8 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
if (!pvr2_hdw_dev_ok(hdw)) return;
}
+ pvr2_hdw_setup_std(hdw);
+
if (!get_default_tuner_type(hdw)) {
pvr2_trace(PVR2_TRACE_INIT,
"pvr2_hdw_setup: Tuner type overridden to %d",
@@ -1135,9 +1544,6 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
if (!pvr2_hdw_dev_ok(hdw)) return;
- pvr2_eeprom_set_default_standard(hdw);
- if (!pvr2_hdw_dev_ok(hdw)) return;
-
pvr2_hdw_commit_ctl_internal(hdw);
if (!pvr2_hdw_dev_ok(hdw)) return;
@@ -1241,6 +1647,8 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
unsigned int idx,cnt1,cnt2;
struct pvr2_hdw *hdw;
unsigned int hdw_type;
+ int valid_std_mask;
+ struct pvr2_ctrl *cptr;
__u8 ifnum;
hdw_type = devid - pvr2_device_table;
@@ -1256,8 +1664,62 @@ 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));
+
+ hdw->controls = kmalloc(sizeof(struct pvr2_ctrl) * CTRL_COUNT,
+ GFP_KERNEL);
+ if (!hdw->controls) goto fail;
+ memset(hdw->controls,0,sizeof(struct pvr2_ctrl) * CTRL_COUNT);
hdw->hdw_type = hdw_type;
+ for (idx = 0; idx < 32; idx++) {
+ hdw->std_mask_ptrs[idx] = hdw->std_mask_names[idx];
+ }
+
+ for (idx = 0; idx < CTRL_COUNT; idx++) {
+ cptr = hdw->controls + idx;
+ cptr->hdw = hdw;
+ cptr->info = control_defs+idx;
+ }
+
+ // Initialize video standard enum dynamic control
+ cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDENUM);
+ if (cptr) {
+ memcpy(&hdw->std_info_enum,cptr->info,
+ sizeof(hdw->std_info_enum));
+ cptr->info = &hdw->std_info_enum;
+
+ }
+ // Initialize control data regarding video standard masks
+ valid_std_mask = pvr2_std_get_usable();
+ for (idx = 0; idx < 32; idx++) {
+ if (!(valid_std_mask & (1 << idx))) continue;
+ cnt1 = pvr2_std_id_to_str(
+ hdw->std_mask_names[idx],
+ sizeof(hdw->std_mask_names[idx])-1,
+ 1 << idx);
+ hdw->std_mask_names[idx][cnt1] = 0;
+ }
+ cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDAVAIL);
+ if (cptr) {
+ memcpy(&hdw->std_info_avail,cptr->info,
+ sizeof(hdw->std_info_avail));
+ cptr->info = &hdw->std_info_avail;
+ hdw->std_info_avail.def.type_bitmask.bit_names =
+ hdw->std_mask_ptrs;
+ hdw->std_info_avail.def.type_bitmask.valid_bits =
+ valid_std_mask;
+ }
+ cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDCUR);
+ if (cptr) {
+ memcpy(&hdw->std_info_cur,cptr->info,
+ sizeof(hdw->std_info_cur));
+ cptr->info = &hdw->std_info_cur;
+ hdw->std_info_cur.def.type_bitmask.bit_names =
+ hdw->std_mask_ptrs;
+ hdw->std_info_avail.def.type_bitmask.valid_bits =
+ valid_std_mask;
+ }
+
hdw->eeprom_addr = -1;
hdw->unit_number = -1;
hdw->v4l_minor_number = -1;
@@ -1298,7 +1760,7 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
/* Initialize the mask of subsystems that we will shut down when we
stop streaming. */
hdw->subsys_stream_mask = PVR2_SUBSYS_RUN_ALL;
- hdw->subsys_stream_mask |= PVR2_SUBSYS_ENC_CFG;
+ hdw->subsys_stream_mask |= (1<<PVR2_SUBSYS_B_ENC_CFG);
pvr2_trace(PVR2_TRACE_INIT,"subsys_stream_mask: 0x%lx",
hdw->subsys_stream_mask);
@@ -1319,6 +1781,7 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
if (hdw->ctl_write_urb) usb_free_urb(hdw->ctl_write_urb);
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);
kfree(hdw);
}
return 0;
@@ -1383,6 +1846,9 @@ 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->std_defs) kfree(hdw->std_defs);
+ if (hdw->std_enum_names) kfree(hdw->std_enum_names);
kfree(hdw);
}
@@ -1411,133 +1877,137 @@ void pvr2_hdw_disconnect(struct pvr2_hdw *hdw)
}
-static int pvr2_ctl_set_chanprog_id(struct pvr2_hdw *hdw,int ctl_id,int value)
+// Attempt to autoselect an appropriate value for std_enum_cur given
+// whatever is currently in std_mask_cur
+void pvr2_hdw_internal_find_stdenum(struct pvr2_hdw *hdw)
{
- /* This is a special case; the value to store is to an array, and
- the element to select is determined by PVR_CID_CHANPROG_ID. */
- int id = hdw->controls[PVR2_CID_CHANPROG_ID].value;
- if ((id < 1) || (id > FREQTABLE_SIZE)) return 0;
- hdw->freqTable[id-1] = value;
- if (hdw->controls[PVR2_CID_CHANNEL].value == id) {
- /* If the current channel happens to be the slot we just
- set, then act like the current channel just got changed
- so we'll update that too. */
- hdw->controls[PVR2_CID_CHANNEL].dirty = !0;
+ unsigned int idx;
+ for (idx = 1; idx < hdw->std_enum_cnt; idx++) {
+ if (hdw->std_defs[idx-1].id == hdw->std_mask_cur) {
+ hdw->std_enum_cur = idx;
+ return;
+ }
}
- return 0;
+ hdw->std_enum_cur = 0;
}
-static int pvr2_ctl_get_chanprog_id(struct pvr2_hdw *hdw,int ctl_id)
+// Calculate correct set of enumerated standards based on currently known
+// set of available standards bits.
+void pvr2_hdw_internal_set_std_avail(struct pvr2_hdw *hdw)
{
- /* This is a special case; the value to return is from an array,
- and the element to select is determined by
- PVR_CID_CHANPROG_ID. */
- int id = hdw->controls[PVR2_CID_CHANPROG_ID].value;
- if ((id < 1) || (id > FREQTABLE_SIZE)) return 0;
- return hdw->freqTable[id-1];
-}
+ struct v4l2_standard *newstd;
+ unsigned int std_cnt;
+ unsigned int idx;
+ newstd = pvr2_std_create_enum(&std_cnt,hdw->std_mask_avail);
-/* Retrieve current value for a given control */
-int pvr2_hdw_get_ctl_value(struct pvr2_hdw *hdw,unsigned int ctl_id)
-{
- int ret = 0;
+ if (hdw->std_defs) {
+ kfree(hdw->std_defs);
+ hdw->std_defs = 0;
+ }
+ hdw->std_enum_cnt = 0;
+ if (hdw->std_enum_names) {
+ kfree(hdw->std_enum_names);
+ hdw->std_enum_names = 0;
+ }
- if (ctl_id >= PVR2_CID_COUNT) return 0;
- LOCK_TAKE(hdw->big_lock); do {
- if (control_defs[ctl_id].get_func) {
- ret = control_defs[ctl_id].get_func(hdw,ctl_id);
- break;
- }
- ret = hdw->controls[ctl_id].value;
- } while(0); LOCK_GIVE(hdw->big_lock);
- return ret;
+ if (!std_cnt) {
+ pvr2_trace(
+ PVR2_TRACE_ERROR_LEGS,
+ "WARNING: Failed to identify any viable standards");
+ }
+ hdw->std_enum_names = kmalloc(sizeof(char *)*(std_cnt+1),GFP_KERNEL);
+ hdw->std_enum_names[0] = "none";
+ for (idx = 0; idx < std_cnt; idx++) {
+ hdw->std_enum_names[idx+1] =
+ newstd[idx].name;
+ }
+ // Set up the dynamic control for this standard
+ hdw->std_info_enum.def.type_enum.value_names = hdw->std_enum_names;
+ hdw->std_info_enum.def.type_enum.count = std_cnt+1;
+ hdw->std_defs = newstd;
+ hdw->std_enum_cnt = std_cnt+1;
+ hdw->std_enum_cur = 0;
+ hdw->std_info_cur.def.type_bitmask.valid_bits = hdw->std_mask_avail;
}
-/* Return true if control is writable */
-int pvr2_hdw_get_ctl_rw(struct pvr2_hdw *hdw,unsigned int ctl_id)
+int pvr2_hdw_get_stdenum_value(struct pvr2_hdw *hdw,
+ struct v4l2_standard *std,
+ unsigned int idx)
{
- if (ctl_id >= PVR2_CID_COUNT) return 0;
- if (control_defs[ctl_id].get_func && !control_defs[ctl_id].set_func) {
- return 0;
- }
- return !0;
+ int ret = -EINVAL;
+ if (!idx) return ret;
+ LOCK_TAKE(hdw->big_lock); do {
+ if (idx >= hdw->std_enum_cnt) break;
+ idx--;
+ memcpy(std,hdw->std_defs+idx,sizeof(*std));
+ ret = 0;
+ } while (0); LOCK_GIVE(hdw->big_lock);
+ return ret;
}
-/* Retrieve legal minimum value for a given control */
-int pvr2_hdw_get_ctl_min_value(struct pvr2_hdw *hdw,unsigned int ctl_id)
+/* Get the number of defined controls */
+unsigned int pvr2_hdw_get_ctrl_count(struct pvr2_hdw *hdw)
{
- if (ctl_id >= PVR2_CID_COUNT) return 0;
- return control_defs[ctl_id].min_value;
+ return CTRL_COUNT;
}
-/* Retrieve legal maximum value for a given control */
-int pvr2_hdw_get_ctl_max_value(struct pvr2_hdw *hdw,unsigned int ctl_id)
+/* Retrieve a control handle given its index (0..count-1) */
+struct pvr2_ctrl *pvr2_hdw_get_ctrl_by_index(struct pvr2_hdw *hdw,
+ unsigned int idx)
{
- if (ctl_id >= PVR2_CID_COUNT) return 0;
- return control_defs[ctl_id].max_value;
+ if (idx >= CTRL_COUNT) return 0;
+ return hdw->controls + idx;
}
-/* Set current value for given control - normally this is just stored and
- the hardware isn't updated until the commit function is called. */
-int pvr2_hdw_set_ctl_value_internal(struct pvr2_hdw *hdw,
- unsigned int ctl_id,int value)
+/* Retrieve a control handle given its index (0..count-1) */
+struct pvr2_ctrl *pvr2_hdw_get_ctrl_by_id(struct pvr2_hdw *hdw,
+ unsigned int ctl_id)
{
- if (ctl_id >= PVR2_CID_COUNT) return -EINVAL;
- if (value < control_defs[ctl_id].min_value) return -EINVAL;
- if (value > control_defs[ctl_id].max_value) return -EINVAL;
- if (control_defs[ctl_id].set_func) {
- return control_defs[ctl_id].set_func(hdw,ctl_id,value);
- } else if (control_defs[ctl_id].get_func) {
- /* If there's no "set" function yet there is still a "get"
- function, then treat this as a read-only value. */
- return -EINVAL;
- }
- if ((hdw->controls[ctl_id].value != value) || (ctlchg != 0)) {
- hdw->controls[ctl_id].value = value;
- hdw->controls[ctl_id].dirty = !0;
+ struct pvr2_ctrl *cptr;
+ unsigned int idx;
+ int i;
+
+ /* This could be made a lot more efficient, but for now... */
+ for (idx = 0; idx < CTRL_COUNT; idx++) {
+ cptr = hdw->controls + idx;
+ i = cptr->info->internal_id;
+ if (i && (i == ctl_id)) return cptr;
}
return 0;
}
-/* Set current value for given control - this is just stored; the hardware
- isn't updated until the commit function is called. */
-int pvr2_hdw_set_ctl_value(struct pvr2_hdw *hdw,unsigned int ctl_id,int value)
+/* Given an ID, retrieve the control structure associated with it. */
+struct pvr2_ctrl *pvr2_hdw_get_ctrl_v4l(struct pvr2_hdw *hdw,unsigned int ctl_id)
{
- int ret;
- LOCK_TAKE(hdw->big_lock); do {
- ret = pvr2_hdw_set_ctl_value_internal(hdw,ctl_id,value);
- } while (0); LOCK_GIVE(hdw->big_lock);
- return ret;
-}
-
+ struct pvr2_ctrl *cptr;
+ unsigned int idx;
+ int i;
-/* Retrieve string name for a given control value (returns a null pointer
- for any invalid combinations). */
-const char *pvr2_hdw_get_ctl_value_name(struct pvr2_hdw *hdw,
- unsigned int ctl_id,
- int value)
-{
- struct pvr2_ctl_def *cdef;
- if (ctl_id >= PVR2_CID_COUNT) return 0;
- cdef = control_defs + ctl_id;
- if (! cdef->value_defs_ptr) return 0;
- if (value >= cdef->value_defs_count) return 0;
- return cdef->value_defs_ptr[value];
+ /* This could be made a lot more efficient, but for now... */
+ for (idx = 0; idx < CTRL_COUNT; idx++) {
+ cptr = hdw->controls + idx;
+ i = cptr->info->v4l_id;
+ if (i && (i == ctl_id)) return cptr;
+ }
+ return 0;
}
-/* Retrieve string name for given control */
-const char *pvr2_hdw_get_ctl_name(struct pvr2_hdw *hdw,unsigned int ctl_id)
+static const char *get_ctrl_typename(enum pvr2_ctl_type tp)
{
- if (ctl_id >= PVR2_CID_COUNT) return 0;
- return control_defs[ctl_id].name;
+ switch (tp) {
+ case pvr2_ctl_int: return "integer";
+ case pvr2_ctl_enum: return "enum";
+ case pvr2_ctl_bitmask: return "bitmask";
+ }
+ return "";
}
@@ -1553,61 +2023,33 @@ int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw)
unsigned long saved_subsys_mask = hdw->subsys_enabled_mask;
unsigned long stale_subsys_mask = 0;
unsigned int idx;
+ struct pvr2_ctrl *cptr;
int value;
- const char *ctl_name;
- const char *ctl_value;
int commit_flag = 0;
+ char buf[100];
+ unsigned int bcnt,ccnt;
- /* Let's see if the channel changed and we have to update the
- frequency because of it. This setup means one can tune the
- receiver either by just setting the channel (using the frequency
- table), or by directly programming the frequency. How do we
- resolve the obvious conflict here? The direct frequency takes
- priority; if directly set then we commit that value and force
- the channel to zero which is interpreted to mean "none". If on
- the other hand we see that the channel has been set and it's a
- legal value, then we copy that into the frequency. The metaphor
- here is similar to when you tune your digital radio: You an
- either set a frequency directly or punch up a pre-programmed
- station. Either way a frequency is set, and if you do use a
- preset, then the radio also shows you which preset it is - until
- you override that by directly entering a new frequency. */
- if (hdw->controls[PVR2_CID_FREQUENCY].dirty) {
- /* Frequency has been directly set, so clear out the
- channel. */
- hdw->controls[PVR2_CID_CHANNEL].value = 0;
- } else if (hdw->controls[PVR2_CID_CHANNEL].dirty) {
- int id = hdw->controls[PVR2_CID_CHANNEL].value;
- if ((id > 0) && (id <= FREQTABLE_SIZE)) {
- if (hdw->controls[PVR2_CID_FREQUENCY].value !=
- hdw->freqTable[id-1]) {
- hdw->controls[PVR2_CID_FREQUENCY].value =
- hdw->freqTable[id-1];
- hdw->controls[PVR2_CID_FREQUENCY].dirty = !0;
- }
- }
- }
-
- for (idx = 0; idx < PVR2_CID_COUNT; idx++) {
- if (!hdw->controls[idx].dirty) continue;
+ for (idx = 0; idx < CTRL_COUNT; idx++) {
+ cptr = hdw->controls + idx;
+ if (cptr->info->is_dirty == 0) continue;
+ if (!cptr->info->is_dirty(cptr)) continue;
if (!commit_flag) {
commit_flag = !0;
}
- value = hdw->controls[idx].value;
- ctl_name = control_defs[idx].name;
- if (control_defs[idx].value_defs_ptr) {
- if (value < control_defs[idx].value_defs_count) {
- ctl_value =
- control_defs[idx].value_defs_ptr[value];
- } else {
- ctl_value = "<out of range>";
- }
- } else {
- ctl_value = "<integer>";
- }
+
+ bcnt = scnprintf(buf,sizeof(buf),"\"%s\" <-- ",
+ cptr->info->name);
+ value = 0;
+ cptr->info->get_value(cptr,&value);
+ pvr2_ctrl_value_to_sym_internal(cptr,~0,value,
+ buf+bcnt,
+ sizeof(buf)-bcnt,&ccnt);
+ bcnt += ccnt;
+ bcnt += scnprintf(buf+bcnt,sizeof(buf)-bcnt," <%s>",
+ get_ctrl_typename(cptr->info->type));
pvr2_trace(PVR2_TRACE_CTL,
- "/*--TRACE_COMMIT--*/ \"%s\" <-- %d (%s)",
- ctl_name,value,ctl_value);
+ "/*--TRACE_COMMIT--*/ %.*s",
+ bcnt,buf);
}
if (!commit_flag) {
@@ -1618,43 +2060,40 @@ int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw)
/* When video standard changes, reset the hres and vres values -
but if the user has pending changes there, then let the changes
take priority. */
- if (hdw->controls[PVR2_CID_VIDEOSTANDARD].dirty) {
+ if (hdw->std_dirty) {
/* Rewrite the vertical resolution to be appropriate to the
video standard that has been selected. */
- int nvres = hdw->controls[PVR2_CID_VRES].value;
- switch (hdw->controls[PVR2_CID_VIDEOSTANDARD].value) {
- case PVR2_CVAL_VIDEOSTANDARD_NTSC_M:
- case PVR2_CVAL_VIDEOSTANDARD_PAL_M:
+ int nvres;
+ if (hdw->std_mask_cur & V4L2_STD_525_60) {
nvres = 480;
- break;
- default:
+ } else {
nvres = 576;
}
- if (nvres != hdw->controls[PVR2_CID_VRES].value) {
- hdw->controls[PVR2_CID_VRES].value = nvres;
- hdw->controls[PVR2_CID_VRES].dirty = !0;
+ if (nvres != hdw->res_ver_val) {
+ hdw->res_ver_val = nvres;
+ hdw->res_ver_dirty = !0;
}
- if (!hdw->controls[PVR2_CID_INTERLACE].value) {
- hdw->controls[PVR2_CID_INTERLACE].value = 0;
- hdw->controls[PVR2_CID_INTERLACE].dirty = !0;
+ if (!hdw->interlace_val) {
+ hdw->interlace_val = 0;
+ hdw->interlace_dirty = !0;
}
}
- if (hdw->controls[PVR2_CID_VIDEOSTANDARD].dirty ||
- hdw->controls[PVR2_CID_VRES].dirty ||
- hdw->controls[PVR2_CID_HRES].dirty ||
- hdw->controls[PVR2_CID_INTERLACE].dirty ||
- hdw->controls[PVR2_CID_VBR].dirty ||
- hdw->controls[PVR2_CID_AVERAGEVIDEOBITRATE].dirty ||
- hdw->controls[PVR2_CID_PEAKVIDEOBITRATE].dirty ||
- hdw->controls[PVR2_CID_AUDIOBITRATE].dirty ||
- hdw->controls[PVR2_CID_SRATE].dirty ||
- hdw->controls[PVR2_CID_AUDIOLAYER].dirty ||
- hdw->controls[PVR2_CID_AUDIOCRC].dirty ||
- hdw->controls[PVR2_CID_AUDIOEMPHASIS].dirty) {
+ if (hdw->std_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) {
/* If any of this changes, then the encoder needs to be
reconfigured, and we need to reset the stream. */
- stale_subsys_mask |= PVR2_SUBSYS_ENC_CFG;
+ stale_subsys_mask |= (1<<PVR2_SUBSYS_B_ENC_CFG);
stale_subsys_mask |= hdw->subsys_stream_mask;
}
@@ -1664,8 +2103,10 @@ int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw)
the client drivers in order to keep everything in sync */
pvr2_i2c_core_check_stale(hdw);
- for (idx = 0; idx < PVR2_CID_COUNT; idx++) {
- hdw->controls[idx].dirty = 0;
+ for (idx = 0; idx < CTRL_COUNT; idx++) {
+ cptr = hdw->controls + idx;
+ if (!cptr->info->clear_dirty) continue;
+ cptr->info->clear_dirty(cptr);
}
/* Now execute i2c core update */
@@ -1722,14 +2163,6 @@ void pvr2_hdw_poll_trigger(struct pvr2_hdw *hdw)
}
-/* Find out how many controls there are. Legal ids are numbered from 1
- through this value. */
-unsigned int pvr2_hdw_get_ctl_count(struct pvr2_hdw *hdw)
-{
- return PVR2_CID_COUNT;
-}
-
-
/* Return name for this driver instance */
const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *hdw)
{
@@ -1741,7 +2174,7 @@ const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *hdw)
unsigned int pvr2_hdw_get_signal_status_internal(struct pvr2_hdw *hdw)
{
unsigned int msk = 0;
- switch (hdw->controls[PVR2_CID_INPUT].value) {
+ switch (hdw->input_val) {
case PVR2_CVAL_INPUT_TV:
case PVR2_CVAL_INPUT_RADIO:
if (hdw->decoder_ctrl &&
@@ -1765,42 +2198,6 @@ unsigned int pvr2_hdw_get_signal_status_internal(struct pvr2_hdw *hdw)
}
-static int pvr2_ctl_get_subsys_mask(struct pvr2_hdw *hdw,int ctl_id)
-{
- return hdw->subsys_enabled_mask;
-}
-
-
-static int pvr2_ctl_set_subsys_mask(struct pvr2_hdw *hdw,int ctl_id,int val)
-{
- pvr2_hdw_subsys_bit_chg_no_lock(hdw,~0,val);
- return 0;
-}
-
-
-static int pvr2_ctl_get_subsys_stream_mask(struct pvr2_hdw *hdw,int ctl_id)
-{
- return hdw->subsys_stream_mask;
-}
-
-
-static int pvr2_ctl_set_subsys_stream_mask(struct pvr2_hdw *hdw,int ctl_id,
- int val)
-{
- pvr2_hdw_subsys_stream_bit_chg_no_lock(hdw,~0,val);
- return 0;
-}
-
-
-static int pvr2_ctl_get_hsm(struct pvr2_hdw *hdw,int ctl_id)
-{
- int result = pvr2_hdw_is_hsm(hdw);
- if (result < 0) return PVR2_CVAL_HSM_FAIL;
- if (result) return PVR2_CVAL_HSM_HIGH;
- return PVR2_CVAL_HSM_FULL;
-}
-
-
int pvr2_hdw_is_hsm(struct pvr2_hdw *hdw)
{
int result;
@@ -1816,13 +2213,6 @@ int pvr2_hdw_is_hsm(struct pvr2_hdw *hdw)
}
-static int pvr2_ctl_get_signal(struct pvr2_hdw *hdw,int ctl_id)
-{
- return ((pvr2_hdw_get_signal_status_internal(hdw) & PVR2_SIGNAL_OK) ?
- 1 : 0);
-}
-
-
/* Return bit mask indicating signal status */
unsigned int pvr2_hdw_get_signal_status(struct pvr2_hdw *hdw)
{
@@ -2062,6 +2452,28 @@ int pvr2_send_request_ex(struct pvr2_hdw *hdw,
return -EINVAL;
}
+#if 0
+ printk(KERN_INFO "pvrusb2: REQUEST BEGIN writeCnt=%u readCnt=%u",
+ write_len,read_len);
+ if (probe_fl) {
+ printk(" <probe>");
+ }
+ for (idx = 0; idx < write_len; idx++) {
+ if (idx > 5) {
+ printk(" ...");
+ break;
+ }
+ if (idx) {
+ printk(" ");
+ } else {
+ printk(" [");
+ }
+ printk("%02x",((unsigned char *)write_data)[idx]);
+ }
+ if (write_len) printk("]");
+ printk("\n");
+#endif
+
hdw->cmd_debug_state = 1;
if (write_len) {
hdw->cmd_debug_code = ((unsigned char *)write_data)[0];
@@ -2231,6 +2643,26 @@ int pvr2_send_request_ex(struct pvr2_hdw *hdw,
}
done:
+#if 0
+ printk(KERN_INFO "pvrusb2: REQUEST END status=%d",status);
+ if (status >= 0) {
+ for (idx = 0; idx < read_len; idx++) {
+ if (idx > 5) {
+ printk(" ...");
+ break;
+ }
+ if (idx) {
+ printk(" ");
+ } else {
+ printk(" [");
+ }
+ printk("%02x",((unsigned char *)read_data)[idx]);
+ }
+ if (read_len) printk("]");
+ }
+ printk("\n");
+#endif
+
hdw->cmd_debug_state = 0;
if ((status < 0) && (!probe_fl)) {
pvr2_hdw_render_useless_unlocked(hdw);
@@ -2406,11 +2838,11 @@ int pvr2_hdw_cmd_deep_reset(struct pvr2_hdw *hdw)
}
-int pvr2_hdw_cmd_soft_reset(struct pvr2_hdw *hdw)
+int pvr2_hdw_cmd_powerup(struct pvr2_hdw *hdw)
{
int status;
LOCK_TAKE(hdw->ctl_lock); do {
- pvr2_trace(PVR2_TRACE_INIT,"Requesting uproc soft reset");
+ pvr2_trace(PVR2_TRACE_INIT,"Requesting powerup");
hdw->cmd_buffer[0] = 0xde;
status = pvr2_send_request(hdw,hdw->cmd_buffer,1,0,0);
} while (0); LOCK_GIVE(hdw->ctl_lock);
@@ -2418,6 +2850,27 @@ int pvr2_hdw_cmd_soft_reset(struct pvr2_hdw *hdw)
}
+int pvr2_hdw_cmd_decoder_reset(struct pvr2_hdw *hdw)
+{
+ if (!hdw->decoder_ctrl) {
+ pvr2_trace(PVR2_TRACE_INIT,
+ "Unable to reset decoder: nothing attached");
+ return -ENOTTY;
+ }
+
+ if (!hdw->decoder_ctrl->force_reset) {
+ pvr2_trace(PVR2_TRACE_INIT,
+ "Unable to reset decoder: not implemented");
+ return -ENOTTY;
+ }
+
+ pvr2_trace(PVR2_TRACE_INIT,
+ "Requesting decoder reset");
+ hdw->decoder_ctrl->force_reset(hdw->decoder_ctrl->ctxt);
+ return 0;
+}
+
+
int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl)
{
int status;
@@ -2428,8 +2881,8 @@ int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl)
if (!status) {
hdw->subsys_enabled_mask =
((hdw->subsys_enabled_mask &
- ~PVR2_SUBSYS_USBSTREAM_RUN) |
- (runFl ? PVR2_SUBSYS_USBSTREAM_RUN : 0));
+ ~(1<<PVR2_SUBSYS_B_USBSTREAM_RUN)) |
+ (runFl ? (1<<PVR2_SUBSYS_B_USBSTREAM_RUN) : 0));
}
return status;
}
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.h
index 085afe566..ba70f5d48 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.h
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.h
@@ -21,137 +21,64 @@
#ifndef __PVRUSB2_HDW_H
#define __PVRUSB2_HDW_H
+#include "compat.h"
#include <linux/usb.h>
+#include <linux/videodev2.h>
#include "pvrusb2-io.h"
-
-/* Definition of state variables that we can inspect & change. Numbers are
- assigned from zero counting up with no gaps. */
-#define PVR2_CID_BRIGHTNESS 0
-#define PVR2_CID_CONTRAST 1
-#define PVR2_CID_SATURATION 2
-#define PVR2_CID_HUE 3
-#define PVR2_CID_VOLUME 4
-#define PVR2_CID_BALANCE 5
-#define PVR2_CID_BASS 6
-#define PVR2_CID_TREBLE 7
-#define PVR2_CID_MUTE 8
-#define PVR2_CID_SRATE 9
-#define PVR2_CID_AUDIOBITRATE 10
-#define PVR2_CID_AUDIOCRC 11
-#define PVR2_CID_AUDIOEMPHASIS 12
-#define PVR2_CID_VBR 13
-#define PVR2_CID_AVERAGEVIDEOBITRATE 14
-#define PVR2_CID_PEAKVIDEOBITRATE 15
-#define PVR2_CID_VIDEOSTANDARD 16
-#define PVR2_CID_INPUT 17
-#define PVR2_CID_AUDIOMODE 18
-#define PVR2_CID_FREQUENCY 19 // Units of Hz
-#define PVR2_CID_HRES 20
-#define PVR2_CID_VRES 21
-#define PVR2_CID_INTERLACE 22
-#define PVR2_CID_AUDIOLAYER 23
-#define PVR2_CID_CHANNEL 24
-#define PVR2_CID_CHANPROG_ID 25
-#define PVR2_CID_CHANPROG_FREQ 26
-#define PVR2_CID_SIGNAL_PRESENT 27
-#define PVR2_CID_STREAMING_ENABLED 28
-#define PVR2_CID_HSM 29
-#define PVR2_CID_SUBSYS_MASK 30
-#define PVR2_CID_SUBSYS_STREAM_MASK 31
-
-/* Number of state variables */
-#define PVR2_CID_COUNT 32
-
-/* Legal values for the SRATE state variable */
-#define PVR2_CVAL_SRATE_48 0
-#define PVR2_CVAL_SRATE_44_1 1
-#define PVR2_CVAL_SRATE_MIN PVR2_CVAL_SRATE_48
-#define PVR2_CVAL_SRATE_MAX PVR2_CVAL_SRATE_44_1
-
-/* Legal values for the AUDIOBITRATE state variable */
-#define PVR2_CVAL_AUDIOBITRATE_384 0
-#define PVR2_CVAL_AUDIOBITRATE_320 1
-#define PVR2_CVAL_AUDIOBITRATE_256 2
-#define PVR2_CVAL_AUDIOBITRATE_224 3
-#define PVR2_CVAL_AUDIOBITRATE_192 4
-#define PVR2_CVAL_AUDIOBITRATE_160 5
-#define PVR2_CVAL_AUDIOBITRATE_128 6
-#define PVR2_CVAL_AUDIOBITRATE_112 7
-#define PVR2_CVAL_AUDIOBITRATE_96 8
-#define PVR2_CVAL_AUDIOBITRATE_80 9
-#define PVR2_CVAL_AUDIOBITRATE_64 10
-#define PVR2_CVAL_AUDIOBITRATE_56 11
-#define PVR2_CVAL_AUDIOBITRATE_48 12
-#define PVR2_CVAL_AUDIOBITRATE_32 13
-#define PVR2_CVAL_AUDIOBITRATE_VBR 14
-#define PVR2_CVAL_AUDIOBITRATE_MIN PVR2_CVAL_AUDIOBITRATE_384
-#define PVR2_CVAL_AUDIOBITRATE_MAX PVR2_CVAL_AUDIOBITRATE_VBR
-
-/* Legal values for the AUDIOEMPHASIS state variable */
-#define PVR2_CVAL_AUDIOEMPHASIS_NONE 0
-#define PVR2_CVAL_AUDIOEMPHASIS_50_15 1
-#define PVR2_CVAL_AUDIOEMPHASIS_CCITT 2
-#define PVR2_CVAL_AUDIOEMPHASIS_MIN PVR2_CVAL_AUDIOEMPHASIS_NONE
-#define PVR2_CVAL_AUDIOEMPHASIS_MAX PVR2_CVAL_AUDIOEMPHASIS_CCITT
-
-/* Legal values for the VIDEOSTANDARD state variable */
-#define PVR2_CVAL_VIDEOSTANDARD_NTSC_M 0
-#define PVR2_CVAL_VIDEOSTANDARD_PAL_BG 1
-#define PVR2_CVAL_VIDEOSTANDARD_PAL_I 2
-#define PVR2_CVAL_VIDEOSTANDARD_PAL_DK 3
-#define PVR2_CVAL_VIDEOSTANDARD_PAL_M 4
-#define PVR2_CVAL_VIDEOSTANDARD_SECAM_L 5
-
-#define PVR2_CVAL_VIDEOSTANDARD_MIN PVR2_CVAL_VIDEOSTANDARD_NTSC_M
-#define PVR2_CVAL_VIDEOSTANDARD_MAX PVR2_CVAL_VIDEOSTANDARD_SECAM_L
+#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 */
+#define PVR2_CID_STDENUM 1
+#define PVR2_CID_STDCUR 2
+#define PVR2_CID_STDAVAIL 3
+#define PVR2_CID_INPUT 4
+#define PVR2_CID_AUDIOMODE 5
+#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
#define PVR2_CVAL_INPUT_SVIDEO 1
#define PVR2_CVAL_INPUT_COMPOSITE 2
#define PVR2_CVAL_INPUT_RADIO 3
-#define PVR2_CVAL_INPUT_MIN PVR2_CVAL_INPUT_TV
-#define PVR2_CVAL_INPUT_MAX PVR2_CVAL_INPUT_RADIO
-
-/* Legal values for the AUDIOMODE state variable */
-#define PVR2_CVAL_AUDIOMODE_MONO 0
-#define PVR2_CVAL_AUDIOMODE_STEREO 1
-#define PVR2_CVAL_AUDIOMODE_SAP 2
-#define PVR2_CVAL_AUDIOMODE_LANG1 3
-#define PVR2_CVAL_AUDIOMODE_LANG2 4
-#define PVR2_CVAL_AUDIOMODE_LANG1_LANG2 5
-#define PVR2_CVAL_AUDIOMODE_MIN PVR2_CVAL_AUDIOMODE_MONO
-#define PVR2_CVAL_AUDIOMODE_MAX PVR2_CVAL_AUDIOMODE_LANG1_LANG2
/* Values that pvr2_hdw_get_signal_status() returns */
#define PVR2_SIGNAL_OK 0x0001
#define PVR2_SIGNAL_STEREO 0x0002
#define PVR2_SIGNAL_SAP 0x0004
-/* Legal values for PVR2_CID_HSM */
-#define PVR2_CVAL_HSM_FAIL 0
-#define PVR2_CVAL_HSM_FULL 1
-#define PVR2_CVAL_HSM_HIGH 2
-#define PVR2_CVAL_HSM_MIN PVR2_CVAL_HSM_FAIL
-#define PVR2_CVAL_HSM_MAX PVR2_CVAL_HSM_HIGH
/* 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_ENC_FIRMWARE (1 << 0)
-#define PVR2_SUBSYS_ENC_CFG (1 << 1)
-#define PVR2_SUBSYS_DIGITIZER_RUN (1 << 2)
-#define PVR2_SUBSYS_USBSTREAM_RUN (1 << 3)
-#define PVR2_SUBSYS_ENC_RUN (1 << 4)
+#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 ( \
- PVR2_SUBSYS_ENC_FIRMWARE | \
- PVR2_SUBSYS_ENC_CFG )
+ (1 << PVR2_SUBSYS_B_ENC_FIRMWARE) | \
+ (1 << PVR2_SUBSYS_B_ENC_CFG) )
#define PVR2_SUBSYS_RUN_ALL ( \
- PVR2_SUBSYS_DIGITIZER_RUN | \
- PVR2_SUBSYS_USBSTREAM_RUN | \
- PVR2_SUBSYS_ENC_RUN )
+ (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 )
@@ -215,37 +142,21 @@ unsigned long pvr2_hdw_get_sn(struct pvr2_hdw *);
/* Called when hardware has been unplugged */
void pvr2_hdw_disconnect(struct pvr2_hdw *);
-/* Retrieve current value for a given control */
-int pvr2_hdw_get_ctl_value(struct pvr2_hdw *,unsigned int ctl_id);
-
-/* Return true if control is writable */
-int pvr2_hdw_get_ctl_rw(struct pvr2_hdw *,unsigned int ctl_id);
-
-/* Retrieve legal minimum value for a given control */
-int pvr2_hdw_get_ctl_min_value(struct pvr2_hdw *,unsigned int ctl_id);
-
-/* Retrieve legal maximum value for a given control */
-int pvr2_hdw_get_ctl_max_value(struct pvr2_hdw *,unsigned int ctl_id);
+/* Get the number of defined controls */
+unsigned int pvr2_hdw_get_ctrl_count(struct pvr2_hdw *);
-/* Set current value for given control - this is just stored; the hardware
- isn't updated until the commit function is called. */
-int pvr2_hdw_set_ctl_value(struct pvr2_hdw *,unsigned int ctl_id,int value);
+/* Retrieve a control handle given its index (0..count-1) */
+struct pvr2_ctrl *pvr2_hdw_get_ctrl_by_index(struct pvr2_hdw *,unsigned int);
-/* Retrieve string name for given control */
-const char *pvr2_hdw_get_ctl_name(struct pvr2_hdw *,unsigned int ctl_id);
+/* Retrieve a control handle given its internal ID (if any) */
+struct pvr2_ctrl *pvr2_hdw_get_ctrl_by_id(struct pvr2_hdw *,unsigned int);
-/* Retrieve string name for a given control value (returns a null pointer
- for any invalid combinations). */
-const char *pvr2_hdw_get_ctl_value_name(struct pvr2_hdw *,
- unsigned int ctl_id,int value);
+/* 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);
/* Commit all control changes made up to this point */
int pvr2_hdw_commit_ctl(struct pvr2_hdw *);
-/* Find out how many controls there are. Legal ids are numbered from 0
- through this value - 1. */
-unsigned int pvr2_hdw_get_ctl_count(struct pvr2_hdw *);
-
/* Return name for this driver instance */
const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *);
@@ -267,6 +178,10 @@ int pvr2_hdw_set_stream_type(struct pvr2_hdw *, enum pvr2_config);
/* Get handle to video output stream */
struct pvr2_stream *pvr2_hdw_get_video_stream(struct pvr2_hdw *);
+/* Emit a video standard struct */
+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. */
@@ -359,7 +274,10 @@ void pvr2_hdw_device_reset(struct pvr2_hdw *);
int pvr2_hdw_cmd_deep_reset(struct pvr2_hdw *);
/* Execute simple reset command */
-int pvr2_hdw_cmd_soft_reset(struct pvr2_hdw *);
+int pvr2_hdw_cmd_powerup(struct pvr2_hdw *);
+
+/* Order decoder to reset */
+int pvr2_hdw_cmd_decoder_reset(struct pvr2_hdw *);
/* Stop / start video stream transport */
int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl);
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c
index 2d97653d5..89d0da053 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c
@@ -28,6 +28,10 @@
#include "pvrusb2-tuner.h"
#include "pvrusb2-demod.h"
#include "pvrusb2-video-v4l.h"
+#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
+#include "pvrusb2-cx2584x-v4l.h"
+#include "pvrusb2-wm8775.h"
+#endif
#define trace_i2c(...) pvr2_trace(PVR2_TRACE_I2C,__VA_ARGS__)
@@ -69,18 +73,28 @@ void pvr2_i2c_probe(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp)
return;
}
}
+#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
+ if (id == I2C_DRIVERID_CX25840) {
+ if (pvr2_i2c_cx2584x_v4l_setup(hdw,cp)) {
+ return;
+ }
+ }
+ if (id == I2C_DRIVERID_WM8775) {
+ if (pvr2_i2c_wm8775_setup(hdw,cp)) {
+ return;
+ }
+ }
+#endif
if (id == I2C_DRIVERID_SAA711X) {
if (pvr2_i2c_decoder_v4l_setup(hdw,cp)) {
return;
}
}
-#ifdef PVR2_ENABLE_DRIVERID_TDA9887
if (id == I2C_DRIVERID_TDA9887) {
if (pvr2_i2c_demod_setup(hdw,cp)) {
return;
}
}
-#endif
}
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c
index 7d137a25f..9f81aff2b 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c
@@ -23,44 +23,23 @@
#include "pvrusb2-i2c-cmd-v4l2.h"
#include "pvrusb2-hdw-internal.h"
#include "pvrusb2-debug.h"
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
static void set_standard(struct pvr2_hdw *hdw)
{
- int cvstd = hdw->controls[PVR2_CID_VIDEOSTANDARD].value;
v4l2_std_id vs;
+ vs = hdw->std_mask_cur;
pvr2_trace(PVR2_TRACE_CHIPS,
- "i2c v4l2 set_standard(%d)",cvstd);
-
- switch (cvstd) {
- default:
- case PVR2_CVAL_VIDEOSTANDARD_NTSC_M:
- vs = V4L2_STD_NTSC_M;
- break;
- case PVR2_CVAL_VIDEOSTANDARD_SECAM_L:
- vs = V4L2_STD_SECAM;
- break;
- case PVR2_CVAL_VIDEOSTANDARD_PAL_BG:
- vs = V4L2_STD_PAL_BG;
- break;
- case PVR2_CVAL_VIDEOSTANDARD_PAL_I:
- vs = V4L2_STD_PAL_I;
- break;
- case PVR2_CVAL_VIDEOSTANDARD_PAL_DK:
- vs = V4L2_STD_PAL_DK;
- break;
- case PVR2_CVAL_VIDEOSTANDARD_PAL_M:
- vs = V4L2_STD_PAL_M;
- break;
- }
+ "i2c v4l2 set_standard(0x%llx)",(__u64)vs);
+
pvr2_i2c_core_cmd(hdw,VIDIOC_S_STD,&vs);
}
static int check_standard(struct pvr2_hdw *hdw)
{
- return hdw->controls[PVR2_CID_VIDEOSTANDARD].dirty != 0;
+ return hdw->std_dirty != 0;
}
@@ -76,32 +55,30 @@ static void set_bcsh(struct pvr2_hdw *hdw)
struct v4l2_control ctrl;
pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_bcsh"
" b=%d c=%d s=%d h=%d",
- hdw->controls[PVR2_CID_BRIGHTNESS].value,
- hdw->controls[PVR2_CID_CONTRAST].value,
- hdw->controls[PVR2_CID_SATURATION].value,
- hdw->controls[PVR2_CID_HUE].value);
+ hdw->brightness_val,hdw->contrast_val,
+ hdw->saturation_val,hdw->hue_val);
memset(&ctrl,0,sizeof(ctrl));
ctrl.id = V4L2_CID_BRIGHTNESS;
- ctrl.value = hdw->controls[PVR2_CID_BRIGHTNESS].value;
+ ctrl.value = hdw->brightness_val;
pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
ctrl.id = V4L2_CID_CONTRAST;
- ctrl.value = hdw->controls[PVR2_CID_CONTRAST].value;
+ ctrl.value = hdw->contrast_val;
pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
ctrl.id = V4L2_CID_SATURATION;
- ctrl.value = hdw->controls[PVR2_CID_SATURATION].value;
+ ctrl.value = hdw->saturation_val;
pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
ctrl.id = V4L2_CID_HUE;
- ctrl.value = hdw->controls[PVR2_CID_HUE].value;
+ ctrl.value = hdw->hue_val;
pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
}
static int check_bcsh(struct pvr2_hdw *hdw)
{
- return (hdw->controls[PVR2_CID_BRIGHTNESS].dirty ||
- hdw->controls[PVR2_CID_CONTRAST].dirty ||
- hdw->controls[PVR2_CID_SATURATION].dirty ||
- hdw->controls[PVR2_CID_HUE].dirty);
+ return (hdw->brightness_dirty ||
+ hdw->contrast_dirty ||
+ hdw->saturation_dirty ||
+ hdw->hue_dirty);
}
@@ -118,37 +95,37 @@ static void set_volume(struct pvr2_hdw *hdw)
pvr2_trace(PVR2_TRACE_CHIPS,
"i2c v4l2 set_volume"
"(vol=%d bal=%d bas=%d treb=%d mute=%d)",
- hdw->controls[PVR2_CID_VOLUME].value,
- hdw->controls[PVR2_CID_BALANCE].value,
- hdw->controls[PVR2_CID_BASS].value,
- hdw->controls[PVR2_CID_TREBLE].value,
- hdw->controls[PVR2_CID_MUTE].value);
+ hdw->volume_val,
+ hdw->balance_val,
+ hdw->bass_val,
+ hdw->treble_val,
+ hdw->mute_val);
memset(&ctrl,0,sizeof(ctrl));
ctrl.id = V4L2_CID_AUDIO_MUTE;
- ctrl.value = hdw->controls[PVR2_CID_MUTE].value ? 1 : 0;
+ ctrl.value = hdw->mute_val ? 1 : 0;
pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
ctrl.id = V4L2_CID_AUDIO_VOLUME;
- ctrl.value = hdw->controls[PVR2_CID_VOLUME].value;
+ ctrl.value = hdw->volume_val;
pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
ctrl.id = V4L2_CID_AUDIO_BALANCE;
- ctrl.value = hdw->controls[PVR2_CID_BALANCE].value;
+ ctrl.value = hdw->balance_val;
pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
ctrl.id = V4L2_CID_AUDIO_BASS;
- ctrl.value = hdw->controls[PVR2_CID_BASS].value;
+ ctrl.value = hdw->bass_val;
pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
ctrl.id = V4L2_CID_AUDIO_TREBLE;
- ctrl.value = hdw->controls[PVR2_CID_TREBLE].value;
+ ctrl.value = hdw->treble_val;
pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
}
static int check_volume(struct pvr2_hdw *hdw)
{
- return (hdw->controls[PVR2_CID_VOLUME].dirty ||
- hdw->controls[PVR2_CID_BALANCE].dirty ||
- hdw->controls[PVR2_CID_BASS].dirty ||
- hdw->controls[PVR2_CID_TREBLE].dirty ||
- hdw->controls[PVR2_CID_MUTE].dirty);
+ return (hdw->volume_dirty ||
+ hdw->balance_dirty ||
+ hdw->bass_dirty ||
+ hdw->treble_dirty ||
+ hdw->mute_dirty);
}
@@ -163,7 +140,7 @@ static void set_frequency(struct pvr2_hdw *hdw)
{
unsigned long fv;
struct v4l2_frequency freq;
- fv = hdw->controls[PVR2_CID_FREQUENCY].value;
+ fv = hdw->freqVal;
pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_freq(%lu)",fv);
memset(&freq,0,sizeof(freq));
freq.frequency = fv / 62500;
@@ -175,7 +152,7 @@ static void set_frequency(struct pvr2_hdw *hdw)
static int check_frequency(struct pvr2_hdw *hdw)
{
- return hdw->controls[PVR2_CID_FREQUENCY].dirty != 0;
+ return hdw->freqDirty != 0;
}
@@ -193,8 +170,8 @@ static void set_size(struct pvr2_hdw *hdw)
memset(&fmt,0,sizeof(fmt));
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- fmt.fmt.pix.width = hdw->controls[PVR2_CID_HRES].value;
- fmt.fmt.pix.height = hdw->controls[PVR2_CID_VRES].value;
+ fmt.fmt.pix.width = hdw->res_hor_val;
+ fmt.fmt.pix.height = hdw->res_ver_val;
pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_size(%dx%d)",
fmt.fmt.pix.width,fmt.fmt.pix.height);
@@ -205,8 +182,7 @@ static void set_size(struct pvr2_hdw *hdw)
static int check_size(struct pvr2_hdw *hdw)
{
- return (hdw->controls[PVR2_CID_HRES].dirty ||
- hdw->controls[PVR2_CID_VRES].dirty);
+ return (hdw->res_hor_dirty || hdw->res_ver_dirty);
}
@@ -238,6 +214,13 @@ const struct pvr2_i2c_op pvr2_i2c_op_v4l2_log = {
};
+void pvr2_v4l2_cmd_stream(struct pvr2_i2c_client *cp,int fl)
+{
+ pvr2_i2c_client_cmd(cp,
+ (fl ? VIDIOC_STREAMON : VIDIOC_STREAMOFF),0);
+}
+
+
/*
Stuff for Emacs to see, in order to encourage consistent editing style:
*** Local Variables: ***
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h
index fa0a3af7e..1666a3287 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h
@@ -33,6 +33,8 @@ extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_frequency;
extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_size;
extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_log;
+void pvr2_v4l2_cmd_stream(struct pvr2_i2c_client *,int);
+
#endif /* __PVRUSB2_CMD_V4L2_H */
/*
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
index 8ec637e5e..4f1f4b000 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
@@ -56,7 +56,7 @@ static int pvr2_i2c_write(struct pvr2_hdw *hdw, /* Context */
"Killing an I2C write to %u that is too large"
" (desired=%u limit=%u)",
i2c_addr,
- length,(sizeof(hdw->cmd_buffer) - 3));
+ length,(unsigned int)(sizeof(hdw->cmd_buffer) - 3));
return -ENOTSUPP;
}
@@ -88,7 +88,7 @@ static int pvr2_i2c_write(struct pvr2_hdw *hdw, /* Context */
}
}
#if 0
- trace_i2c("i2c_write(%d) len=%d ret=%d stat=%d",i2c_addr,length,ret,
+ trace_i2c("i2c_write(0x%x) len=%d ret=%d stat=%d",i2c_addr,length,ret,
hdw->cmd_buffer[0]);
#endif
@@ -112,8 +112,22 @@ static int pvr2_i2c_read(struct pvr2_hdw *hdw, /* Context */
#endif
if (!data) dlen = 0;
- if (dlen > (sizeof(hdw->cmd_buffer) - 4)) return -ENOTSUPP;
- if (res && (rlen > (sizeof(hdw->cmd_buffer) - 1))) return -ENOTSUPP;
+ if (dlen > (sizeof(hdw->cmd_buffer) - 4)) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "Killing an I2C read to %u that has wlen too large"
+ " (desired=%u limit=%u)",
+ i2c_addr,
+ dlen,(unsigned int)(sizeof(hdw->cmd_buffer) - 4));
+ return -ENOTSUPP;
+ }
+ if (res && (rlen > (sizeof(hdw->cmd_buffer) - 1))) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "Killing an I2C read to %u that has rlen too large"
+ " (desired=%u limit=%u)",
+ i2c_addr,
+ rlen,(unsigned int)(sizeof(hdw->cmd_buffer) - 1));
+ return -ENOTSUPP;
+ }
LOCK_TAKE(hdw->ctl_lock);
@@ -146,7 +160,7 @@ static int pvr2_i2c_read(struct pvr2_hdw *hdw, /* Context */
}
#if 0
- trace_i2c("i2c_read(%d) wlen=%d rlen=%d ret=%d stat=%d",
+ trace_i2c("i2c_read(0x%x) wlen=%d rlen=%d ret=%d stat=%d",
i2c_addr,dlen,rlen,ret,hdw->cmd_buffer[0]);
#endif
/* Copy back the result */
@@ -164,6 +178,130 @@ static int pvr2_i2c_read(struct pvr2_hdw *hdw, /* Context */
return ret;
}
+/* This is the common low level entry point for doing I2C operations to the
+ hardware. */
+int pvr2_i2c_basic_op(struct pvr2_hdw *hdw,
+ u8 i2c_addr,
+ u8 *wdata,
+ u16 wlen,
+ u8 *rdata,
+ u16 rlen)
+{
+ if (!rdata) rlen = 0;
+ if (!wdata) wlen = 0;
+ if (rlen || !wlen) {
+ return pvr2_i2c_read(hdw,i2c_addr,wdata,wlen,rdata,rlen);
+ } else {
+ return pvr2_i2c_write(hdw,i2c_addr,wdata,wlen);
+ }
+}
+
+#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
+
+/* This is a special entry point that is entered if an I2C operation is
+ attempted to a wm8775 chip on model 24xxx hardware. Autodetect of this
+ part doesn't work, but we know it is really there. So let's look for
+ the autodetect attempt and just return success if we see that. */
+static int i2c_hack_wm8775(struct pvr2_hdw *hdw,
+ u8 i2c_addr,u8 *wdata,u16 wlen,u8 *rdata,u16 rlen)
+{
+ if (!(rlen || wlen)) {
+ // This is a probe attempt. Just let it succeed.
+ return 0;
+ }
+ return pvr2_i2c_basic_op(hdw,i2c_addr,wdata,wlen,rdata,rlen);
+}
+
+/* This is a special entry point that is entered if an I2C operation is
+ attempted to a cx25840 chip on model 24xxx hardware. This chip can
+ sometimes wedge itself. Worse still, when this happens msp3400 can
+ falsely detect this part and then the system gets hosed up after msp3400
+ gets confused and dies. What we want to do here is try to keep msp3400
+ away and also try to notice if the chip is wedged and send a warning to
+ the system log. */
+static int i2c_hack_cx25840(struct pvr2_hdw *hdw,
+ u8 i2c_addr,u8 *wdata,u16 wlen,u8 *rdata,u16 rlen)
+{
+ int ret;
+ unsigned int subaddr;
+ u8 wbuf[2];
+ int state = hdw->i2c_cx25840_hack_state;
+
+ if (!(rlen || wlen)) {
+ // Probe attempt - always just succeed and don't bother the
+ // hardware (this helps to make the state machine further
+ // down somewhat easier).
+ return 0;
+ }
+
+ if (state == 3) {
+ return pvr2_i2c_basic_op(hdw,i2c_addr,wdata,wlen,rdata,rlen);
+ }
+
+ /* We're looking for the exact pattern where the revision register
+ is being read. The cx25840 module will always look at the
+ revision register first. Any other pattern of access therefore
+ has to be a probe attempt from somebody else so we'll reject it.
+ Normally we could just let each client just probe the part
+ anyway, but when the cx25840 is wedged, msp3400 will get a false
+ positive and that just screws things up... */
+
+ if (wlen == 0) {
+ switch (state) {
+ case 1: subaddr = 0x0100; break;
+ case 2: subaddr = 0x0101; break;
+ default: goto fail;
+ }
+ } else if (wlen == 2) {
+ subaddr = (wdata[0] << 8) | wdata[1];
+ switch (subaddr) {
+ case 0x0100: state = 1; break;
+ case 0x0101: state = 2; break;
+ default: goto fail;
+ }
+ } else {
+ goto fail;
+ }
+ if (!rlen) goto success;
+ state = 0;
+ if (rlen != 1) goto fail;
+
+ /* If we get to here then we have a legitimate read for one of the
+ two revision bytes, so pass it through. */
+ wbuf[0] = subaddr >> 8;
+ wbuf[1] = subaddr;
+ ret = pvr2_i2c_basic_op(hdw,i2c_addr,wbuf,2,rdata,rlen);
+
+ if ((ret != 0) || (*rdata == 0x04) || (*rdata == 0x0a)) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "WARNING: Detected a wedged cx25840 chip;"
+ " the device will not work.");
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "WARNING: Try power cycling the pvrusb2 device.");
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "WARNING: Disabling further access to the device"
+ " to prevent other foul-ups.");
+ // This blocks all further communication with the part.
+ hdw->i2c_func[0x44] = 0;
+ pvr2_hdw_render_useless(hdw);
+ goto fail;
+ }
+
+ /* Success! */
+ pvr2_trace(PVR2_TRACE_CHIPS,"cx25840 appears to be OK.");
+ state = 3;
+
+ success:
+ hdw->i2c_cx25840_hack_state = state;
+ return 0;
+
+ fail:
+ hdw->i2c_cx25840_hack_state = state;
+ return -EIO;
+}
+
+#endif /* CONFIG_VIDEO_PVRUSB2_24XXX */
+
/* This is a very, very limited I2C adapter implementation. We can only
support what we actually know will work on the device... */
static int pvr2_i2c_xfer(struct i2c_adapter *i2c_adap,
@@ -171,12 +309,24 @@ static int pvr2_i2c_xfer(struct i2c_adapter *i2c_adap,
int num)
{
int ret = -ENOTSUPP;
+ pvr2_i2c_func funcp = 0;
struct pvr2_hdw *hdw = (struct pvr2_hdw *)(i2c_adap->algo_data);
+ if (!num) {
+ ret = -EINVAL;
+ goto done;
+ }
if ((msgs[0].flags & I2C_M_NOSTART)) {
trace_i2c("i2c refusing I2C_M_NOSTART");
goto done;
}
+ if (msgs[0].addr < PVR2_I2C_FUNC_CNT) {
+ funcp = hdw->i2c_func[msgs[0].addr];
+ }
+ if (!funcp) {
+ ret = -EIO;
+ goto done;
+ }
if (num == 1) {
if (msgs[0].flags & I2C_M_RD) {
@@ -184,8 +334,7 @@ static int pvr2_i2c_xfer(struct i2c_adapter *i2c_adap,
u16 tcnt,bcnt,offs;
if (!msgs[0].len) {
/* Length == 0 read. This is a probe. */
- if (pvr2_i2c_read(hdw,msgs[0].addr,
- 0,0,0,0)) {
+ if (funcp(hdw,msgs[0].addr,0,0,0,0)) {
ret = -EIO;
goto done;
}
@@ -202,9 +351,8 @@ static int pvr2_i2c_xfer(struct i2c_adapter *i2c_adap,
if (bcnt > sizeof(hdw->cmd_buffer)-1) {
bcnt = sizeof(hdw->cmd_buffer)-1;
}
- if (pvr2_i2c_read(hdw,msgs[0].addr,
- 0,0,
- msgs[0].buf+offs,bcnt)) {
+ if (funcp(hdw,msgs[0].addr,0,0,
+ msgs[0].buf+offs,bcnt)) {
ret = -EIO;
goto done;
}
@@ -216,13 +364,19 @@ static int pvr2_i2c_xfer(struct i2c_adapter *i2c_adap,
} else {
/* Simple write */
ret = 1;
- if (pvr2_i2c_write(hdw,msgs[0].addr,
- msgs[0].buf,msgs[0].len)) {
+ if (funcp(hdw,msgs[0].addr,
+ msgs[0].buf,msgs[0].len,0,0)) {
ret = -EIO;
}
goto done;
}
} else if (num == 2) {
+ if (msgs[0].addr != msgs[1].addr) {
+ trace_i2c("i2c refusing 2 phase transfer with"
+ " conflicting target addresses");
+ ret = -ENOTSUPP;
+ goto done;
+ }
if ((!((msgs[0].flags & I2C_M_RD))) &&
(msgs[1].flags & I2C_M_RD)) {
u16 tcnt,bcnt,wcnt,offs;
@@ -238,9 +392,9 @@ static int pvr2_i2c_xfer(struct i2c_adapter *i2c_adap,
if (bcnt > sizeof(hdw->cmd_buffer)-1) {
bcnt = sizeof(hdw->cmd_buffer)-1;
}
- if (pvr2_i2c_read(hdw,msgs[0].addr,
- msgs[0].buf,wcnt,
- msgs[1].buf+offs,bcnt)) {
+ if (funcp(hdw,msgs[0].addr,
+ msgs[0].buf,wcnt,
+ msgs[1].buf+offs,bcnt)) {
ret = -EIO;
goto done;
}
@@ -262,18 +416,29 @@ static int pvr2_i2c_xfer(struct i2c_adapter *i2c_adap,
done:
if (pvrusb2_debug & PVR2_TRACE_I2C_TRAF) {
- unsigned int idx;
+ unsigned int idx,offs,cnt;
for (idx = 0; idx < num; idx++) {
+ cnt = msgs[idx].len;
printk(KERN_INFO
"pvrusb2 i2c xfer %u/%u:"
" addr=0x%x len=%d %s%s",
idx+1,num,
msgs[idx].addr,
- msgs[idx].len,
+ cnt,
(msgs[idx].flags & I2C_M_RD ?
"read" : "write"),
(msgs[idx].flags & I2C_M_NOSTART ?
" nostart" : ""));
+ if ((ret > 0) || !(msgs[idx].flags & I2C_M_RD)) {
+ if (cnt > 8) cnt = 8;
+ printk(" [");
+ for (offs = 0; offs < (cnt>8?8:cnt); offs++) {
+ if (offs) printk(" ");
+ printk("%02x",msgs[idx].buf[offs]);
+ }
+ if (offs < cnt) printk(" ...");
+ printk("]");
+ }
if (idx+1 == num) {
printk(" result=%d",ret);
}
@@ -296,7 +461,7 @@ static int pvr2_i2c_control(struct i2c_adapter *adapter,
static u32 pvr2_i2c_functionality(struct i2c_adapter *adap)
{
- return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C;
+ return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C | I2C_FUNC_SMBUS_BYTE_DATA;
}
static int pvr2_i2c_core_singleton(struct i2c_client *cp,
@@ -322,15 +487,26 @@ static int pvr2_i2c_core_singleton(struct i2c_client *cp,
int pvr2_i2c_client_cmd(struct pvr2_i2c_client *cp,unsigned int cmd,void *arg)
{
+ int stat;
+ if (pvrusb2_debug & PVR2_TRACE_I2C_CMD) {
+ char buf[100];
+ unsigned int cnt;
+ cnt = pvr2_i2c_client_describe(cp,PVR2_I2C_DETAIL_DEBUG,
+ buf,sizeof(buf));
+ pvr2_trace(PVR2_TRACE_I2C_CMD,
+ "i2c COMMAND (code=%u 0x%x) to %.*s",
+ cmd,cmd,cnt,buf);
+ }
+ stat = pvr2_i2c_core_singleton(cp->client,cmd,arg);
if (pvrusb2_debug & PVR2_TRACE_I2C_CMD) {
char buf[100];
unsigned int cnt;
cnt = pvr2_i2c_client_describe(cp,PVR2_I2C_DETAIL_DEBUG,
buf,sizeof(buf));
pvr2_trace(PVR2_TRACE_I2C_CMD,
- "i2c COMMAND to %.*s",cnt,buf);
+ "i2c COMMAND to %.*s (ret=%d)",cnt,buf,stat);
}
- return pvr2_i2c_core_singleton(cp->client,cmd,arg);
+ return stat;
}
int pvr2_i2c_core_cmd(struct pvr2_hdw *hdw,unsigned int cmd,void *arg)
@@ -735,6 +911,24 @@ static void do_i2c_scan(struct pvr2_hdw *hdw)
void pvr2_i2c_core_init(struct pvr2_hdw *hdw)
{
+ unsigned int idx;
+
+ // The default action for all possible I2C addresses is just to do
+ // the transfer normally.
+ for (idx = 0; idx < PVR2_I2C_FUNC_CNT; idx++) {
+ hdw->i2c_func[idx] = pvr2_i2c_basic_op;
+ }
+
+#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
+ // If however we're dealing with new hardware, insert some hacks in
+ // the I2C transfer stack to let things work better.
+ if (hdw->hdw_type == PVR2_HDW_TYPE_24XXX) {
+ hdw->i2c_func[0x1b] = i2c_hack_wm8775;
+ hdw->i2c_func[0x44] = i2c_hack_cx25840;
+ }
+#endif
+
+ // Configure the adapter and set up everything else related to it.
memcpy(&hdw->i2c_adap,&pvr2_i2c_adap_template,sizeof(hdw->i2c_adap));
memcpy(&hdw->i2c_algo,&pvr2_i2c_algo_template,sizeof(hdw->i2c_algo));
strlcpy(hdw->i2c_adap.name,hdw->name,sizeof(hdw->i2c_adap.name));
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-io.c b/linux/drivers/media/video/pvrusb2/pvrusb2-io.c
index a6bc3befe..cb0ca6376 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-io.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-io.c
@@ -26,8 +26,7 @@
#include <linux/string.h>
#include <linux/slab.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
-#include <asm/atomic.h>
-#include <asm/mutex.h>
+#include <linux/mutex.h>
#else
#include <asm/semaphore.h>
#endif
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-ioread.c b/linux/drivers/media/video/pvrusb2/pvrusb2-ioread.c
index f81a0c225..555dbbca8 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-ioread.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-ioread.c
@@ -26,8 +26,7 @@
#include <linux/string.h>
#include <linux/slab.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
-#include <asm/atomic.h>
-#include <asm/mutex.h>
+#include <linux/mutex.h>
#else
#include <asm/semaphore.h>
#endif
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-main.c b/linux/drivers/media/video/pvrusb2/pvrusb2-main.c
index c554671af..245f7a36d 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-main.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-main.c
@@ -29,13 +29,15 @@
#include <linux/moduleparam.h>
#include <linux/smp_lock.h>
#include <linux/usb.h>
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
#include "pvrusb2-hdw.h"
#include "pvrusb2-context.h"
#include "pvrusb2-debug.h"
#include "pvrusb2-v4l2.h"
+#ifdef CONFIG_VIDEO_PVRUSB2_SYSFS
#include "pvrusb2-sysfs.h"
+#endif /* CONFIG_VIDEO_PVRUSB2_SYSFS */
#define DRIVER_AUTHOR "Mike Isely <isely@pobox.com>"
#define DRIVER_DESC "Hauppauge WinTV-PVR-USB2 MPEG2 Encoder/Tuner"
@@ -60,13 +62,17 @@ int pvrusb2_debug = DEFAULT_DEBUG_MASK;
module_param_named(debug,pvrusb2_debug,int,S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(debug, "Debug trace mask");
+#ifdef CONFIG_VIDEO_PVRUSB2_SYSFS
static struct pvr2_sysfs_class *class_ptr = 0;
+#endif /* CONFIG_VIDEO_PVRUSB2_SYSFS */
static void pvr_setup_attach(struct pvr2_context *pvr)
{
/* Create association with v4l layer */
pvr2_v4l2_create(pvr);
+#ifdef CONFIG_VIDEO_PVRUSB2_SYSFS
pvr2_sysfs_create(pvr,class_ptr);
+#endif /* CONFIG_VIDEO_PVRUSB2_SYSFS */
}
static int pvr_probe(struct usb_interface *intf,
@@ -128,15 +134,9 @@ static int __init pvr_init(void)
pvr2_trace(PVR2_TRACE_INIT,"pvr_init");
- /* Auto-load various support modules (with which we may
- indirectly interact) */
- request_module("tuner");
- request_module("tveeprom");
- request_module("msp3400");
- request_module("saa7115");
- request_module("tda9887");
-
+#ifdef CONFIG_VIDEO_PVRUSB2_SYSFS
class_ptr = pvr2_sysfs_class_create();
+#endif /* CONFIG_VIDEO_PVRUSB2_SYSFS */
ret = usb_register(&pvr_driver);
@@ -153,7 +153,9 @@ static void __exit pvr_exit(void)
pvr2_trace(PVR2_TRACE_INIT,"pvr_exit");
+#ifdef CONFIG_VIDEO_PVRUSB2_SYSFS
pvr2_sysfs_class_destroy(class_ptr);
+#endif /* CONFIG_VIDEO_PVRUSB2_SYSFS */
usb_deregister(&pvr_driver);
}
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-std.c b/linux/drivers/media/video/pvrusb2/pvrusb2-std.c
new file mode 100644
index 000000000..64ba223c2
--- /dev/null
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-std.c
@@ -0,0 +1,406 @@
+/*
+ *
+ * $Id$
+ *
+ * Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include "pvrusb2-std.h"
+#include "pvrusb2-debug.h"
+
+struct std_name {
+ const char *name;
+ v4l2_std_id id;
+};
+
+
+#define CSTD_PAL \
+ (V4L2_STD_PAL_B| \
+ V4L2_STD_PAL_B1| \
+ V4L2_STD_PAL_G| \
+ V4L2_STD_PAL_H| \
+ V4L2_STD_PAL_I| \
+ V4L2_STD_PAL_D| \
+ V4L2_STD_PAL_D1| \
+ V4L2_STD_PAL_K| \
+ V4L2_STD_PAL_M| \
+ V4L2_STD_PAL_N| \
+ V4L2_STD_PAL_Nc| \
+ V4L2_STD_PAL_60)
+
+#define CSTD_NTSC \
+ (V4L2_STD_NTSC_M| \
+ V4L2_STD_NTSC_M_JP| \
+ V4L2_STD_NTSC_M_KR| \
+ V4L2_STD_NTSC_443)
+
+#define CSTD_SECAM \
+ (V4L2_STD_SECAM_B| \
+ V4L2_STD_SECAM_D| \
+ V4L2_STD_SECAM_G| \
+ V4L2_STD_SECAM_H| \
+ V4L2_STD_SECAM_K| \
+ V4L2_STD_SECAM_K1| \
+ V4L2_STD_SECAM_L| \
+ V4L2_STD_SECAM_LC)
+
+#define TSTD_B (V4L2_STD_PAL_B|V4L2_STD_SECAM_B)
+#define TSTD_B1 (V4L2_STD_PAL_B1)
+#define TSTD_D (V4L2_STD_PAL_D|V4L2_STD_SECAM_D)
+#define TSTD_D1 (V4L2_STD_PAL_D1)
+#define TSTD_G (V4L2_STD_PAL_G|V4L2_STD_SECAM_G)
+#define TSTD_H (V4L2_STD_PAL_H|V4L2_STD_SECAM_H)
+#define TSTD_I (V4L2_STD_PAL_I)
+#define TSTD_K (V4L2_STD_PAL_K|V4L2_STD_SECAM_K)
+#define TSTD_K1 (V4L2_STD_SECAM_K1)
+#define TSTD_L (V4L2_STD_SECAM_L)
+#define TSTD_M (V4L2_STD_PAL_M|V4L2_STD_NTSC_M)
+#define TSTD_N (V4L2_STD_PAL_N)
+#define TSTD_Nc (V4L2_STD_PAL_Nc)
+#define TSTD_60 (V4L2_STD_PAL_60)
+
+#define CSTD_ALL (CSTD_PAL|CSTD_NTSC|CSTD_SECAM)
+
+/* Mapping of standard bits to color system */
+const static struct std_name std_groups[] = {
+ {"PAL",CSTD_PAL},
+ {"NTSC",CSTD_NTSC},
+ {"SECAM",CSTD_SECAM},
+};
+
+/* Mapping of standard bits to modulation system */
+const static struct std_name std_items[] = {
+ {"B",TSTD_B},
+ {"B1",TSTD_B1},
+ {"D",TSTD_D},
+ {"D1",TSTD_D1},
+ {"G",TSTD_G},
+ {"H",TSTD_H},
+ {"I",TSTD_I},
+ {"K",TSTD_K},
+ {"K1",TSTD_K1},
+ {"L",TSTD_L},
+ {"LC",V4L2_STD_SECAM_LC},
+ {"M",TSTD_M},
+ {"Mj",V4L2_STD_NTSC_M_JP},
+ {"443",V4L2_STD_NTSC_443},
+ {"Mk",V4L2_STD_NTSC_M_KR},
+ {"N",TSTD_N},
+ {"Nc",TSTD_Nc},
+ {"60",TSTD_60},
+};
+
+
+// Search an array of std_name structures and return a pointer to the
+// element with the matching name.
+static const struct std_name *find_std_name(const struct std_name *arrPtr,
+ unsigned int arrSize,
+ const char *bufPtr,
+ unsigned int bufSize)
+{
+ unsigned int idx;
+ const struct std_name *p;
+ for (idx = 0; idx < arrSize; idx++) {
+ p = arrPtr + idx;
+ if (strlen(p->name) != bufSize) continue;
+ if (!memcmp(bufPtr,p->name,bufSize)) return p;
+ }
+ return 0;
+}
+
+
+int pvr2_std_str_to_id(v4l2_std_id *idPtr,const char *bufPtr,
+ unsigned int bufSize)
+{
+ v4l2_std_id id = 0;
+ v4l2_std_id cmsk = 0;
+ v4l2_std_id t;
+ int mMode = 0;
+ unsigned int cnt;
+ char ch;
+ const struct std_name *sp;
+
+ while (bufSize) {
+ if (!mMode) {
+ cnt = 0;
+ while ((cnt < bufSize) && (bufPtr[cnt] != '-')) cnt++;
+ if (cnt >= bufSize) return 0; // No more characters
+ sp = find_std_name(
+ std_groups,
+ sizeof(std_groups)/sizeof(std_groups[0]),
+ bufPtr,cnt);
+ if (!sp) return 0; // Illegal color system name
+ cnt++;
+ bufPtr += cnt;
+ bufSize -= cnt;
+ mMode = !0;
+ cmsk = sp->id;
+ continue;
+ }
+ cnt = 0;
+ while (cnt < bufSize) {
+ ch = bufPtr[cnt];
+ if (ch == ';') {
+ mMode = 0;
+ break;
+ }
+ if (ch == '/') break;
+ cnt++;
+ }
+ sp = find_std_name(std_items,
+ sizeof(std_items)/sizeof(std_items[0]),
+ bufPtr,cnt);
+ if (!sp) return 0; // Illegal modulation system ID
+ t = sp->id & cmsk;
+ if (!t) return 0; // Specific color + modulation system illegal
+ id |= t;
+ if (cnt < bufSize) cnt++;
+ bufPtr += cnt;
+ bufSize -= cnt;
+ }
+
+ if (idPtr) *idPtr = id;
+ return !0;
+}
+
+
+unsigned int pvr2_std_id_to_str(char *bufPtr, unsigned int bufSize,
+ v4l2_std_id id)
+{
+ unsigned int idx1,idx2;
+ const struct std_name *ip,*gp;
+ int gfl,cfl;
+ unsigned int c1,c2;
+ cfl = 0;
+ c1 = 0;
+ for (idx1 = 0;
+ idx1 < sizeof(std_groups)/sizeof(std_groups[0]);
+ idx1++) {
+ gp = std_groups + idx1;
+ gfl = 0;
+ for (idx2 = 0;
+ idx2 < sizeof(std_items)/sizeof(std_items[0]);
+ idx2++) {
+ ip = std_items + idx2;
+ if (!(gp->id & ip->id & id)) continue;
+ if (!gfl) {
+ if (cfl) {
+ c2 = scnprintf(bufPtr,bufSize,";");
+ c1 += c2;
+ bufSize -= c2;
+ bufPtr += c2;
+ }
+ cfl = !0;
+ c2 = scnprintf(bufPtr,bufSize,
+ "%s-",gp->name);
+ gfl = !0;
+ } else {
+ c2 = scnprintf(bufPtr,bufSize,"/");
+ }
+ c1 += c2;
+ bufSize -= c2;
+ bufPtr += c2;
+ c2 = scnprintf(bufPtr,bufSize,
+ ip->name);
+ c1 += c2;
+ bufSize -= c2;
+ bufPtr += c2;
+ }
+ }
+ return c1;
+}
+
+
+// Template data for possible enumerated video standards. Here we group
+// standards which share common frame rates and resolution.
+static struct v4l2_standard generic_standards[] = {
+ {
+ .id = (TSTD_B|TSTD_B1|
+ TSTD_D|TSTD_D1|
+ TSTD_G|
+ TSTD_H|
+ TSTD_I|
+ TSTD_K|TSTD_K1|
+ TSTD_L|
+ V4L2_STD_SECAM_LC |
+ TSTD_N|TSTD_Nc),
+ .frameperiod =
+ {
+ .numerator = 1,
+ .denominator= 25
+ },
+ .framelines = 625,
+ .reserved = {0,0,0,0}
+ }, {
+ .id = (TSTD_M|
+ V4L2_STD_NTSC_M_JP|
+ V4L2_STD_NTSC_M_KR),
+ .frameperiod =
+ {
+ .numerator = 1001,
+ .denominator= 30000
+ },
+ .framelines = 525,
+ .reserved = {0,0,0,0}
+ }, { // This is a total wild guess
+ .id = (TSTD_60),
+ .frameperiod =
+ {
+ .numerator = 1001,
+ .denominator= 30000
+ },
+ .framelines = 525,
+ .reserved = {0,0,0,0}
+ }, { // This is total wild guess
+ .id = V4L2_STD_NTSC_443,
+ .frameperiod =
+ {
+ .numerator = 1001,
+ .denominator= 30000
+ },
+ .framelines = 525,
+ .reserved = {0,0,0,0}
+ }
+};
+
+#define generic_standards_cnt (sizeof(generic_standards)/sizeof(generic_standards[0]))
+
+static struct v4l2_standard *match_std(v4l2_std_id id)
+{
+ unsigned int idx;
+ for (idx = 0; idx < generic_standards_cnt; idx++) {
+ if (generic_standards[idx].id & id) {
+ return generic_standards + idx;
+ }
+ }
+ return 0;
+}
+
+static int pvr2_std_fill(struct v4l2_standard *std,v4l2_std_id id)
+{
+ struct v4l2_standard *template;
+ int idx;
+ unsigned int bcnt;
+ template = match_std(id);
+ if (!template) return 0;
+ idx = std->index;
+ memcpy(std,template,sizeof(*template));
+ std->index = idx;
+ std->id = id;
+ bcnt = pvr2_std_id_to_str(std->name,sizeof(std->name)-1,id);
+ std->name[bcnt] = 0;
+ pvr2_trace(PVR2_TRACE_INIT,"Set up standard idx=%u name=%s",
+ std->index,std->name);
+ return !0;
+}
+
+/* These are special cases of combined standards that we should enumerate
+ separately if the component pieces are present. */
+static v4l2_std_id std_mixes[] = {
+ V4L2_STD_PAL_B | V4L2_STD_PAL_G,
+ V4L2_STD_PAL_D | V4L2_STD_PAL_K,
+ V4L2_STD_SECAM_B | V4L2_STD_SECAM_G,
+ V4L2_STD_SECAM_D | V4L2_STD_SECAM_K,
+};
+
+struct v4l2_standard *pvr2_std_create_enum(unsigned int *countptr,
+ v4l2_std_id id)
+{
+ unsigned int std_cnt = 0;
+ unsigned int idx,bcnt,idx2;
+ v4l2_std_id idmsk,cmsk,fmsk;
+ struct v4l2_standard *stddefs;
+
+ if (pvrusb2_debug & PVR2_TRACE_INIT) {
+ char buf[50];
+ bcnt = pvr2_std_id_to_str(buf,sizeof(buf),id);
+ pvr2_trace(
+ PVR2_TRACE_INIT,"Mapping standards mask=0x%x (%.*s)",
+ (int)id,bcnt,buf);
+ }
+
+ *countptr = 0;
+ std_cnt = 0;
+ fmsk = 0;
+ for (idmsk = 1, cmsk = id; cmsk; idmsk <<= 1) {
+ if (!(idmsk & cmsk)) continue;
+ cmsk &= ~idmsk;
+ if (match_std(idmsk)) {
+ std_cnt++;
+ continue;
+ }
+ fmsk |= idmsk;
+ }
+
+ for (idx2 = 0; idx2 < sizeof(std_mixes)/sizeof(std_mixes[0]); idx2++) {
+ if ((id & std_mixes[idx2]) == std_mixes[idx2]) std_cnt++;
+ }
+
+ if (fmsk) {
+ char buf[50];
+ bcnt = pvr2_std_id_to_str(buf,sizeof(buf),fmsk);
+ pvr2_trace(
+ PVR2_TRACE_ERROR_LEGS,
+ "WARNING:"
+ " Failed to classify the following standard(s): %.*s",
+ bcnt,buf);
+ }
+
+ pvr2_trace(PVR2_TRACE_INIT,"Setting up %u unique standard(s)",
+ std_cnt);
+ if (!std_cnt) return 0; // paranoia
+
+ stddefs = kmalloc(sizeof(struct v4l2_standard) * std_cnt,
+ GFP_KERNEL);
+ memset(stddefs,0,sizeof(struct v4l2_standard) * std_cnt);
+ for (idx = 0; idx < std_cnt; idx++) stddefs[idx].index = idx;
+
+ idx = 0;
+
+ /* Enumerate potential special cases */
+ for (idx2 = 0; ((idx2 < sizeof(std_mixes)/sizeof(std_mixes[0])) &&
+ (idx < std_cnt)); idx2++) {
+ if (!(id & std_mixes[idx2])) continue;
+ if (pvr2_std_fill(stddefs+idx,std_mixes[idx2])) idx++;
+ }
+ /* Now enumerate individual pieces */
+ for (idmsk = 1, cmsk = id; cmsk && (idx < std_cnt); idmsk <<= 1) {
+ if (!(idmsk & cmsk)) continue;
+ cmsk &= ~idmsk;
+ if (!pvr2_std_fill(stddefs+idx,idmsk)) continue;
+ idx++;
+ }
+
+ *countptr = std_cnt;
+ return stddefs;
+}
+
+v4l2_std_id pvr2_std_get_usable(void)
+{
+ return CSTD_ALL;
+}
+
+
+/*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+ *** Local Variables: ***
+ *** mode: c ***
+ *** fill-column: 75 ***
+ *** tab-width: 8 ***
+ *** c-basic-offset: 8 ***
+ *** End: ***
+ */
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-std.h b/linux/drivers/media/video/pvrusb2/pvrusb2-std.h
new file mode 100644
index 000000000..dc9ef5bb3
--- /dev/null
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-std.h
@@ -0,0 +1,61 @@
+/*
+ *
+ * $Id$
+ *
+ * Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#ifndef __PVRUSB2_STD_H
+#define __PVRUSB2_STD_H
+
+#include "compat.h"
+#include <linux/videodev2.h>
+
+// Convert string describing one or more video standards into a mask of V4L
+// standard bits. Return true if conversion succeeds otherwise return
+// false. String is expected to be of the form: C1-x/y;C2-a/b where C1 and
+// C2 are color system names (e.g. "PAL", "NTSC") and x, y, a, and b are
+// modulation schemes (e.g. "M", "B", "G", etc).
+int pvr2_std_str_to_id(v4l2_std_id *idPtr,const char *bufPtr,
+ unsigned int bufSize);
+
+// Convert any arbitrary set of video standard bits into an unambiguous
+// readable string. Return value is the number of bytes consumed in the
+// buffer. The formatted string is of a form that can be parsed by our
+// sibling std_std_to_id() function.
+unsigned int pvr2_std_id_to_str(char *bufPtr, unsigned int bufSize,
+ v4l2_std_id id);
+
+// Create an array of suitable v4l2_standard structures given a bit mask of
+// video standards to support. The array is allocated from the heap, and
+// the number of elements is returned in the first argument.
+struct v4l2_standard *pvr2_std_create_enum(unsigned int *countptr,
+ v4l2_std_id id);
+
+// Return mask of which video standard bits are valid
+v4l2_std_id pvr2_std_get_usable(void);
+
+#endif /* __PVRUSB2_STD_H */
+
+/*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+ *** Local Variables: ***
+ *** mode: c ***
+ *** fill-column: 75 ***
+ *** tab-width: 8 ***
+ *** c-basic-offset: 8 ***
+ *** End: ***
+ */
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/linux/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
index a9710b52c..075882877 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
@@ -19,6 +19,7 @@
*
*/
+#include <linux/config.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <asm/semaphore.h>
@@ -26,49 +27,18 @@
#include "pvrusb2-sysfs.h"
#include "pvrusb2-hdw.h"
#include "pvrusb2-debug.h"
+#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
#include "pvrusb2-debugifc.h"
+#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
#define pvr2_sysfs_trace(...) pvr2_trace(PVR2_TRACE_SYSFS,__VA_ARGS__)
-static char *item_names[PVR2_CID_COUNT] = {
- [PVR2_CID_BRIGHTNESS] = "ctl_brightness",
- [PVR2_CID_CONTRAST] = "ctl_contrast",
- [PVR2_CID_SATURATION] = "ctl_saturation",
- [PVR2_CID_HUE] = "ctl_hue",
- [PVR2_CID_VOLUME] = "ctl_volume",
- [PVR2_CID_BALANCE] = "ctl_balance",
- [PVR2_CID_BASS] = "ctl_bass",
- [PVR2_CID_TREBLE] = "ctl_treble",
- [PVR2_CID_MUTE] = "ctl_mute",
- [PVR2_CID_SRATE] = "ctl_srate",
- [PVR2_CID_AUDIOBITRATE] = "ctl_audio_bitrate",
- [PVR2_CID_AUDIOCRC] = "ctl_audio_crc",
- [PVR2_CID_AUDIOEMPHASIS] = "ctl_audio_emphasis",
- [PVR2_CID_VBR] = "ctl_vbr",
- [PVR2_CID_AVERAGEVIDEOBITRATE] = "ctl_video_average_bitrate",
- [PVR2_CID_PEAKVIDEOBITRATE] = "ctl_video_peak_bitrate",
- [PVR2_CID_VIDEOSTANDARD] = "ctl_video_standard",
- [PVR2_CID_INPUT] = "ctl_input",
- [PVR2_CID_AUDIOMODE] = "ctl_audio_mode",
- [PVR2_CID_FREQUENCY] = "ctl_frequency",
- [PVR2_CID_HRES] = "ctl_resolution_hor",
- [PVR2_CID_VRES] = "ctl_resolution_ver",
- [PVR2_CID_INTERLACE] = "ctl_interlace",
- [PVR2_CID_AUDIOLAYER] = "ctl_audio_layer",
- [PVR2_CID_CHANNEL] = "ctl_channel",
- [PVR2_CID_CHANPROG_ID] = "ctl_freq_table_channel",
- [PVR2_CID_CHANPROG_FREQ] = "ctl_freq_table_value",
- [PVR2_CID_SIGNAL_PRESENT] = "ctl_signal_present",
- [PVR2_CID_STREAMING_ENABLED] = "ctl_streaming_enabled",
- [PVR2_CID_HSM] = "ctl_usb_speed",
- [PVR2_CID_SUBSYS_MASK] = "ctl_debug_subsys_mask",
- [PVR2_CID_SUBSYS_STREAM_MASK] = "ctl_debug_subsys_stream_mask",
-};
-
struct pvr2_sysfs {
struct pvr2_channel channel;
struct class_device *class_dev;
+#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
struct pvr2_sysfs_debugifc *debugifc;
+#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
struct pvr2_sysfs_ctl_item *item_first;
struct pvr2_sysfs_ctl_item *item_last;
struct sysfs_ops kops;
@@ -77,22 +47,27 @@ struct pvr2_sysfs {
struct class_device_attribute attr_unit_number;
};
+#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
struct pvr2_sysfs_debugifc {
struct class_device_attribute attr_debugcmd;
struct class_device_attribute attr_debuginfo;
};
+#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
struct pvr2_sysfs_ctl_item {
struct class_device_attribute attr_name;
struct class_device_attribute attr_min;
struct class_device_attribute attr_max;
struct class_device_attribute attr_enum;
+ struct class_device_attribute attr_bits;
struct class_device_attribute attr_val;
- int attr_id;
+ struct class_device_attribute attr_custom;
+ struct pvr2_ctrl *cptr;
struct pvr2_sysfs *chptr;
struct pvr2_sysfs_ctl_item *item_next;
- struct attribute *attr_gen[5];
+ struct attribute *attr_gen[6];
struct attribute_group grp;
+ char name[80];
};
struct pvr2_sysfs_class {
@@ -101,13 +76,16 @@ struct pvr2_sysfs_class {
static ssize_t show_name(int id,struct class_device *class_dev,char *buf)
{
+ struct pvr2_ctrl *cptr;
struct pvr2_sysfs *sfp;
const char *name;
sfp = (struct pvr2_sysfs *)class_dev->class_data;
if (!sfp) return -EINVAL;
- name = pvr2_hdw_get_ctl_name(sfp->channel.hdw,id);
+ cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
+ if (!cptr) return -EINVAL;
+ name = pvr2_ctrl_get_desc(cptr);
pvr2_sysfs_trace("pvr2_sysfs(%p) show_name(cid=%d) is %s",sfp,id,name);
if (!name) return -EINVAL;
@@ -117,217 +95,173 @@ static ssize_t show_name(int id,struct class_device *class_dev,char *buf)
static ssize_t show_min(int id,struct class_device *class_dev,char *buf)
{
+ struct pvr2_ctrl *cptr;
struct pvr2_sysfs *sfp;
- int val;
+ long val;
sfp = (struct pvr2_sysfs *)class_dev->class_data;
if (!sfp) return -EINVAL;
- val = pvr2_hdw_get_ctl_min_value(sfp->channel.hdw,id);
+ cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
+ if (!cptr) return -EINVAL;
+ val = pvr2_ctrl_get_min(cptr);
- pvr2_sysfs_trace("pvr2_sysfs(%p) show_min(cid=%d) is %d",sfp,id,val);
+ pvr2_sysfs_trace("pvr2_sysfs(%p) show_min(cid=%d) is %ld",sfp,id,val);
- return scnprintf(buf,PAGE_SIZE,"%d\n",val);
+ return scnprintf(buf,PAGE_SIZE,"%ld\n",val);
}
static ssize_t show_max(int id,struct class_device *class_dev,char *buf)
{
+ struct pvr2_ctrl *cptr;
struct pvr2_sysfs *sfp;
- int val;
+ long val;
sfp = (struct pvr2_sysfs *)class_dev->class_data;
if (!sfp) return -EINVAL;
- val = pvr2_hdw_get_ctl_max_value(sfp->channel.hdw,id);
+ cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
+ if (!cptr) return -EINVAL;
+ val = pvr2_ctrl_get_max(cptr);
- pvr2_sysfs_trace("pvr2_sysfs(%p) show_max(cid=%d) is %d",sfp,id,val);
+ pvr2_sysfs_trace("pvr2_sysfs(%p) show_max(cid=%d) is %ld",sfp,id,val);
- return scnprintf(buf,PAGE_SIZE,"%d\n",val);
+ return scnprintf(buf,PAGE_SIZE,"%ld\n",val);
}
-static ssize_t show_val_int(int id,struct class_device *class_dev,char *buf)
+static ssize_t show_val_norm(int id,struct class_device *class_dev,char *buf)
{
+ struct pvr2_ctrl *cptr;
struct pvr2_sysfs *sfp;
- int val;
+ int val,ret;
+ unsigned int cnt = 0;
sfp = (struct pvr2_sysfs *)class_dev->class_data;
if (!sfp) return -EINVAL;
- val = pvr2_hdw_get_ctl_value(sfp->channel.hdw,id);
+ cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
+ if (!cptr) return -EINVAL;
- pvr2_sysfs_trace("pvr2_sysfs(%p) show_val_int(cid=%d) is %d",
- sfp,id,val);
+ ret = pvr2_ctrl_get_value(cptr,&val);
+ if (ret < 0) return ret;
- return scnprintf(buf,PAGE_SIZE,"%d\n",val);
+ ret = pvr2_ctrl_value_to_sym(cptr,~0,val,
+ buf,PAGE_SIZE-1,&cnt);
+
+ pvr2_sysfs_trace("pvr2_sysfs(%p) show_val_norm(cid=%d) is %.*s (%d)",
+ sfp,id,cnt,buf,val);
+ buf[cnt] = '\n';
+ return cnt+1;
}
-static ssize_t show_val_enum(int id,struct class_device *class_dev,char *buf)
+static ssize_t show_val_custom(int id,struct class_device *class_dev,char *buf)
{
+ struct pvr2_ctrl *cptr;
struct pvr2_sysfs *sfp;
- int val;
- const char *name;
+ int val,ret;
+ unsigned int cnt = 0;
sfp = (struct pvr2_sysfs *)class_dev->class_data;
if (!sfp) return -EINVAL;
- val = pvr2_hdw_get_ctl_value(sfp->channel.hdw,id);
+ cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
+ if (!cptr) return -EINVAL;
- name = pvr2_hdw_get_ctl_value_name(sfp->channel.hdw,id,val);
+ ret = pvr2_ctrl_get_value(cptr,&val);
+ if (ret < 0) return ret;
- pvr2_sysfs_trace("pvr2_sysfs(%p) show_val_enum(cid=%d) is %s (%d)",
- sfp,id,name,val);
+ ret = pvr2_ctrl_custom_value_to_sym(cptr,~0,val,
+ buf,PAGE_SIZE-1,&cnt);
- return scnprintf(buf,PAGE_SIZE,"%s\n",name);
+ pvr2_sysfs_trace("pvr2_sysfs(%p) show_val_custom(cid=%d) is %.*s (%d)",
+ sfp,id,cnt,buf,val);
+ buf[cnt] = '\n';
+ return cnt+1;
}
static ssize_t show_enum(int id,struct class_device *class_dev,char *buf)
{
+ struct pvr2_ctrl *cptr;
struct pvr2_sysfs *sfp;
- int minval,maxval,val;
- const char *name;
- ssize_t cnt = 0;
+ long val;
+ unsigned int bcnt,ccnt,ecnt;
sfp = (struct pvr2_sysfs *)class_dev->class_data;
if (!sfp) return -EINVAL;
- minval = pvr2_hdw_get_ctl_min_value(sfp->channel.hdw,id);
- maxval = pvr2_hdw_get_ctl_max_value(sfp->channel.hdw,id);
- for (val = minval; val <= maxval; val++) {
- name = pvr2_hdw_get_ctl_value_name(sfp->channel.hdw,id,val);
- cnt += scnprintf(buf+cnt,PAGE_SIZE-cnt,"%s\n",name);
+ cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
+ if (!cptr) return -EINVAL;
+ ecnt = pvr2_ctrl_get_cnt(cptr);
+ bcnt = 0;
+ for (val = 0; val < ecnt; val++) {
+ pvr2_ctrl_get_valname(cptr,val,buf+bcnt,PAGE_SIZE-bcnt,&ccnt);
+ bcnt += ccnt;
+ if (bcnt >= PAGE_SIZE) break;
+ buf[bcnt] = '\n';
+ bcnt++;
}
pvr2_sysfs_trace("pvr2_sysfs(%p) show_enum(cid=%d)",sfp,id);
- return cnt;
+ return bcnt;
}
-static int store_val_any(int id,struct pvr2_sysfs *sfp,
- const char *buf,unsigned int count)
+static ssize_t show_bits(int id,struct class_device *class_dev,char *buf)
{
- int val,minval,maxval;
- int ch,ret;
- const char *nv;
- unsigned int nl;
- int negfl;
-
- /* Trim leading / trailing whitespace */
- while (count) {
- ch = buf[0];
- if ((ch > 32) && (ch < 127)) break;
- buf++;
- count--;
- }
- while (count) {
- ch = buf[count-1];
- if ((ch > 32) && (ch < 127)) break;
- count--;
- }
-
- /* Is this an enum? Look for a string value */
- minval = pvr2_hdw_get_ctl_min_value(sfp->channel.hdw,id);
- maxval = pvr2_hdw_get_ctl_max_value(sfp->channel.hdw,id);
- for (val = minval; val <= maxval; val++) {
- nv = pvr2_hdw_get_ctl_value_name(sfp->channel.hdw,id,val);
- if ((!nv) && (val == minval)) break; /* Not an enum */
- pvr2_sysfs_trace("pvr2_sysfs(%p) trying ctl_id %d val %d",
- sfp,id,val);
- if (!nv) {
- pvr2_sysfs_trace("pvr2_sysfs(%p) no pointer",sfp);
- continue;
- }
- nl = strlen(nv);
- if (nl != count) {
- pvr2_sysfs_trace("pvr2_sysfs(%p) count mismatch"
- " %d != %d",
- sfp,count,nl);
- continue;
- }
- if (memcmp(buf,nv,nl)) {
- pvr2_sysfs_trace(
- "pvr2_sysfs(%p) name mismatch"
- " >>%.*s<< != >>%.*s<<",
- sfp,nl,buf,nl,nv);
- continue;
- }
- pvr2_sysfs_trace("pvr2_sysfs(%p) store_val_any(cid=%d)"
- " is enum %s",
- sfp,id,nv);
- ret = pvr2_hdw_set_ctl_value(sfp->channel.hdw,id,val);
- pvr2_hdw_commit_ctl(sfp->channel.hdw);
- return 0;
- }
- if (val > minval) {
- pvr2_sysfs_trace(
- "pvr2_sysfs(%p) store_val_any(cid=%d)"
- " unmatched enum >>%.*s<<",
- sfp,id,count,buf);
- }
+ struct pvr2_ctrl *cptr;
+ struct pvr2_sysfs *sfp;
+ int valid_bits,msk;
+ unsigned int bcnt,ccnt;
- /* Try to parse as a number */
- negfl = 0;
- val = 0;
- if (count) {
- if (buf[0] == '-') {
- negfl = !0;
- buf++;
- count--;
- } else if (buf[0] == '+') {
- buf++;
- count--;
- }
- }
- while (count) {
- ch = buf[0];
- if ((ch < '0') || (ch > '9')) break;
- val = val * 10;
- val += (ch - '0');
- buf++;
- count--;
- }
- if (!count) {
- if (negfl) val = -val;
- pvr2_sysfs_trace("pvr2_sysfs(%p) store_val_any(cid=%d)"
- " int is %d",
- sfp,id,val);
-
- ret = pvr2_hdw_set_ctl_value(sfp->channel.hdw,id,val);
- pvr2_hdw_commit_ctl(sfp->channel.hdw);
- return ret;
+ 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;
+ valid_bits = pvr2_ctrl_get_mask(cptr);
+ bcnt = 0;
+ for (msk = 1; valid_bits; msk <<= 1) {
+ if (!(msk & valid_bits)) continue;
+ valid_bits &= ~msk;
+ pvr2_ctrl_get_valname(cptr,msk,buf+bcnt,PAGE_SIZE-bcnt,&ccnt);
+ bcnt += ccnt;
+ if (bcnt >= PAGE_SIZE) break;
+ buf[bcnt] = '\n';
+ bcnt++;
}
-
- return -EINVAL;
+ pvr2_sysfs_trace("pvr2_sysfs(%p) show_bits(cid=%d)",sfp,id);
+ return bcnt;
}
-static int store_val_multi(int id,struct pvr2_sysfs *sfp,
- const char *buf,unsigned int count)
+static int store_val_any(int id,int customfl,struct pvr2_sysfs *sfp,
+ const char *buf,unsigned int count)
{
- unsigned int count2;
+ struct pvr2_ctrl *cptr;
int ret;
+ int mask,val;
- while (count) {
- count2 = 0;
- while ((count2 < count) && (buf[count2] != '\n')) count2++;
- ret = store_val_any(id,sfp,buf,count2);
- if (ret < 0) return ret;
- if (count2 < count) count2++;
- buf += count2;
- count -= count2;
+ cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
+ if (customfl) {
+ ret = pvr2_ctrl_custom_sym_to_value(cptr,buf,count,&mask,&val);
+ } else {
+ ret = pvr2_ctrl_sym_to_value(cptr,buf,count,&mask,&val);
}
- return 0;
+ if (ret < 0) return ret;
+ ret = pvr2_ctrl_set_mask_value(cptr,mask,val);
+ pvr2_hdw_commit_ctl(sfp->channel.hdw);
+ return ret;
}
-static ssize_t store_val_int(int id,struct class_device *class_dev,
+static ssize_t store_val_norm(int id,struct class_device *class_dev,
const char *buf,size_t count)
{
struct pvr2_sysfs *sfp;
int ret;
sfp = (struct pvr2_sysfs *)class_dev->class_data;
- ret = store_val_multi(id,sfp,buf,count);
+ ret = store_val_any(id,0,sfp,buf,count);
if (!ret) ret = count;
return ret;
}
-static ssize_t store_val_enum(int id,struct class_device *class_dev,
- const char *buf,size_t count)
+static ssize_t store_val_custom(int id,struct class_device *class_dev,
+ const char *buf,size_t count)
{
struct pvr2_sysfs *sfp;
int ret;
sfp = (struct pvr2_sysfs *)class_dev->class_data;
- ret = store_val_multi(id,sfp,buf,count);
+ ret = store_val_any(id,1,sfp,buf,count);
if (!ret) ret = count;
return ret;
}
@@ -357,57 +291,61 @@ static ssize_t sf_name##_##ctl_id(struct class_device *class_dev,const char *buf
CREATE_SHOW_INSTANCE(show_name,ctl_id) \
CREATE_SHOW_INSTANCE(show_min,ctl_id) \
CREATE_SHOW_INSTANCE(show_max,ctl_id) \
-CREATE_SHOW_INSTANCE(show_val_int,ctl_id) \
-CREATE_SHOW_INSTANCE(show_val_enum,ctl_id) \
+CREATE_SHOW_INSTANCE(show_val_norm,ctl_id) \
+CREATE_SHOW_INSTANCE(show_val_custom,ctl_id) \
CREATE_SHOW_INSTANCE(show_enum,ctl_id) \
-CREATE_STORE_INSTANCE(store_val_int,ctl_id) \
-CREATE_STORE_INSTANCE(store_val_enum,ctl_id)
+CREATE_SHOW_INSTANCE(show_bits,ctl_id) \
+CREATE_STORE_INSTANCE(store_val_norm,ctl_id) \
+CREATE_STORE_INSTANCE(store_val_custom,ctl_id) \
CREATE_BATCH(0)
- CREATE_BATCH(1)
- CREATE_BATCH(2)
- CREATE_BATCH(3)
- CREATE_BATCH(4)
- CREATE_BATCH(5)
- CREATE_BATCH(6)
- CREATE_BATCH(7)
- CREATE_BATCH(8)
- CREATE_BATCH(9)
- CREATE_BATCH(10)
- CREATE_BATCH(11)
- CREATE_BATCH(12)
- CREATE_BATCH(13)
- CREATE_BATCH(14)
- CREATE_BATCH(15)
- CREATE_BATCH(16)
- CREATE_BATCH(17)
- CREATE_BATCH(18)
- CREATE_BATCH(19)
- CREATE_BATCH(20)
- CREATE_BATCH(21)
- CREATE_BATCH(22)
- CREATE_BATCH(23)
- CREATE_BATCH(24)
- CREATE_BATCH(25)
- CREATE_BATCH(26)
- CREATE_BATCH(27)
- CREATE_BATCH(28)
- CREATE_BATCH(29)
- CREATE_BATCH(30)
- CREATE_BATCH(31)
-
- struct pvr2_sysfs_func_set {
- ssize_t (*show_name)(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 *);
- ssize_t (*show_val_int)(struct class_device *,char *);
- ssize_t (*show_val_enum)(struct class_device *,char *);
- ssize_t (*store_val_int)(struct class_device *,
- const char *,size_t);
- ssize_t (*store_val_enum)(struct class_device *,
- const char *,size_t);
- };
+CREATE_BATCH(1)
+CREATE_BATCH(2)
+CREATE_BATCH(3)
+CREATE_BATCH(4)
+CREATE_BATCH(5)
+CREATE_BATCH(6)
+CREATE_BATCH(7)
+CREATE_BATCH(8)
+CREATE_BATCH(9)
+CREATE_BATCH(10)
+CREATE_BATCH(11)
+CREATE_BATCH(12)
+CREATE_BATCH(13)
+CREATE_BATCH(14)
+CREATE_BATCH(15)
+CREATE_BATCH(16)
+CREATE_BATCH(17)
+CREATE_BATCH(18)
+CREATE_BATCH(19)
+CREATE_BATCH(20)
+CREATE_BATCH(21)
+CREATE_BATCH(22)
+CREATE_BATCH(23)
+CREATE_BATCH(24)
+CREATE_BATCH(25)
+CREATE_BATCH(26)
+CREATE_BATCH(27)
+CREATE_BATCH(28)
+CREATE_BATCH(29)
+CREATE_BATCH(30)
+CREATE_BATCH(31)
+CREATE_BATCH(32)
+CREATE_BATCH(33)
+
+struct pvr2_sysfs_func_set {
+ ssize_t (*show_name)(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 *);
+ ssize_t (*show_bits)(struct class_device *,char *);
+ ssize_t (*show_val_norm)(struct class_device *,char *);
+ ssize_t (*store_val_norm)(struct class_device *,
+ const char *,size_t);
+ ssize_t (*show_val_custom)(struct class_device *,char *);
+ ssize_t (*store_val_custom)(struct class_device *,
+ const char *,size_t);
+};
#define INIT_BATCH(ctl_id) \
[ctl_id] = { \
@@ -415,10 +353,11 @@ CREATE_BATCH(0)
.show_min = show_min_##ctl_id, \
.show_max = show_max_##ctl_id, \
.show_enum = show_enum_##ctl_id, \
- .show_val_int = show_val_int_##ctl_id, \
- .show_val_enum = show_val_enum_##ctl_id, \
- .store_val_int = store_val_int_##ctl_id, \
- .store_val_enum = store_val_enum_##ctl_id, \
+ .show_bits = show_bits_##ctl_id, \
+ .show_val_norm = show_val_norm_##ctl_id, \
+ .store_val_norm = store_val_norm_##ctl_id, \
+ .show_val_custom = show_val_custom_##ctl_id, \
+ .store_val_custom = store_val_custom_##ctl_id, \
} \
static struct pvr2_sysfs_func_set funcs[] = {
@@ -454,6 +393,8 @@ static struct pvr2_sysfs_func_set funcs[] = {
INIT_BATCH(29),
INIT_BATCH(30),
INIT_BATCH(31),
+ INIT_BATCH(32),
+ INIT_BATCH(33),
};
@@ -461,19 +402,23 @@ static void pvr2_sysfs_add_control(struct pvr2_sysfs *sfp,int ctl_id)
{
struct pvr2_sysfs_ctl_item *cip;
struct pvr2_sysfs_func_set *fp;
+ struct pvr2_ctrl *cptr;
+ unsigned int cnt,acnt;
if ((ctl_id < 0) || (ctl_id >= (sizeof(funcs)/sizeof(funcs[0])))) {
return;
}
fp = funcs + ctl_id;
+ cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,ctl_id);
+ if (!cptr) return;
cip = kmalloc(sizeof(*cip),GFP_KERNEL);
if (!cip) return;
memset(cip,0,sizeof(*cip));
pvr2_sysfs_trace("Creating pvr2_sysfs_ctl_item id=%p",cip);
- cip->attr_id = ctl_id;
+ cip->cptr = cptr;
cip->chptr = sfp;
cip->item_next = 0;
@@ -503,38 +448,62 @@ static void pvr2_sysfs_add_control(struct pvr2_sysfs *sfp,int ctl_id)
cip->attr_val.attr.name = "cur_val";
cip->attr_val.attr.mode = S_IRUGO;
+ cip->attr_custom.attr.owner = THIS_MODULE;
+ cip->attr_custom.attr.name = "custom_val";
+ cip->attr_custom.attr.mode = S_IRUGO;
+
cip->attr_enum.attr.owner = THIS_MODULE;
cip->attr_enum.attr.name = "enum_val";
cip->attr_enum.attr.mode = S_IRUGO;
cip->attr_enum.show = fp->show_enum;
- if (pvr2_hdw_get_ctl_rw(sfp->channel.hdw,ctl_id)) {
+ cip->attr_bits.attr.owner = THIS_MODULE;
+ cip->attr_bits.attr.name = "bit_val";
+ cip->attr_bits.attr.mode = S_IRUGO;
+ cip->attr_bits.show = fp->show_bits;
+
+ if (pvr2_ctrl_is_writable(cptr)) {
cip->attr_val.attr.mode |= S_IWUSR|S_IWGRP;
+ cip->attr_custom.attr.mode |= S_IWUSR|S_IWGRP;
}
- cip->attr_gen[0] = &cip->attr_name.attr;
- cip->attr_gen[1] = &cip->attr_val.attr;
- if (pvr2_hdw_get_ctl_value_name(
- sfp->channel.hdw,ctl_id,
- pvr2_hdw_get_ctl_min_value(sfp->channel.hdw,ctl_id))) {
+ acnt = 0;
+ cip->attr_gen[acnt++] = &cip->attr_name.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;
+ if (pvr2_ctrl_has_custom_symbols(cptr)) {
+ cip->attr_gen[acnt++] = &cip->attr_custom.attr;
+ cip->attr_custom.show = fp->show_val_custom;
+ cip->attr_custom.store = fp->store_val_custom;
+ }
+ switch (pvr2_ctrl_get_type(cptr)) {
+ case pvr2_ctl_enum:
// Control is an enumeration
- cip->attr_gen[2] = &cip->attr_enum.attr;
- cip->attr_val.show = fp->show_val_enum;
- cip->attr_val.store = fp->store_val_enum;
- } else {
+ cip->attr_gen[acnt++] = &cip->attr_enum.attr;
+ break;
+ case pvr2_ctl_int:
// Control is an integer
- cip->attr_val.show = fp->show_val_int;
- cip->attr_val.store = fp->store_val_int;
- cip->attr_gen[2] = &cip->attr_min.attr;
- cip->attr_gen[3] = &cip->attr_max.attr;
+ cip->attr_gen[acnt++] = &cip->attr_min.attr;
+ cip->attr_gen[acnt++] = &cip->attr_max.attr;
+ break;
+ case pvr2_ctl_bitmask:
+ // Control is an bitmask
+ cip->attr_gen[acnt++] = &cip->attr_bits.attr;
+ break;
+ default: break;
}
- cip->grp.name = item_names[ctl_id];
+ cnt = scnprintf(cip->name,sizeof(cip->name)-1,"ctl_%s",
+ pvr2_ctrl_get_name(cptr));
+ cip->name[cnt] = 0;
+ cip->grp.name = cip->name;
cip->grp.attrs = cip->attr_gen;
sysfs_create_group(&sfp->class_dev->kobj,&cip->grp);
}
+#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
static ssize_t debuginfo_show(struct class_device *,char *);
static ssize_t debugcmd_show(struct class_device *,char *);
static ssize_t debugcmd_store(struct class_device *,const char *,size_t count);
@@ -569,16 +538,15 @@ static void pvr2_sysfs_tear_down_debugifc(struct pvr2_sysfs *sfp)
kfree(sfp->debugifc);
sfp->debugifc = 0;
}
+#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
static void pvr2_sysfs_add_controls(struct pvr2_sysfs *sfp)
{
- unsigned int ctl_id;
-
- for (ctl_id = 0;
- ctl_id < (sizeof(item_names)/sizeof(item_names[0])); ctl_id++) {
- if (!item_names[ctl_id]) continue;
- pvr2_sysfs_add_control(sfp,ctl_id);
+ unsigned int idx,cnt;
+ cnt = pvr2_hdw_get_ctrl_count(sfp->channel.hdw);
+ for (idx = 0; idx < cnt; idx++) {
+ pvr2_sysfs_add_control(sfp,idx);
}
}
@@ -614,7 +582,9 @@ static void pvr2_sysfs_release(struct class_device *class_dev)
static void class_dev_destroy(struct pvr2_sysfs *sfp)
{
if (!sfp->class_dev) return;
+#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
pvr2_sysfs_tear_down_debugifc(sfp);
+#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
pvr2_sysfs_tear_down_controls(sfp);
class_device_remove_file(sfp->class_dev,&sfp->attr_v4l_minor_number);
class_device_remove_file(sfp->class_dev,&sfp->attr_unit_number);
@@ -690,7 +660,9 @@ static void class_dev_create(struct pvr2_sysfs *sfp,
class_device_create_file(sfp->class_dev,&sfp->attr_unit_number);
pvr2_sysfs_add_controls(sfp);
+#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
pvr2_sysfs_add_debugifc(sfp);
+#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
}
@@ -761,6 +733,7 @@ void pvr2_sysfs_class_destroy(struct pvr2_sysfs_class *clp)
}
+#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
static ssize_t debuginfo_show(struct class_device *class_dev,char *buf)
{
struct pvr2_sysfs *sfp;
@@ -793,6 +766,7 @@ static ssize_t debugcmd_store(struct class_device *class_dev,
if (ret < 0) return ret;
return count;
}
+#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
/*
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-tuner.c b/linux/drivers/media/video/pvrusb2/pvrusb2-tuner.c
index f829c0acc..8bf7cc142 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-tuner.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-tuner.c
@@ -26,7 +26,7 @@
#include "pvrusb2-hdw-internal.h"
#include "pvrusb2-debug.h"
#include "compat.h"
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
#include <media/tuner.h>
#include <media/v4l2-common.h>
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
index dd207fae4..f4284f927 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
@@ -30,17 +30,9 @@
#include "pvrusb2-debug.h"
#include "pvrusb2-v4l2.h"
#include "pvrusb2-ioread.h"
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
#include <media/v4l2-common.h>
-
-#define PVR_WIDTH_DVD 720
-#define PVR_WIDTH_SVCD 480
-#define PVR_WIDTH_VCD 352
-
-#define PVR_HEIGHT_PAL 480
-#define PVR_HEIGHT_NTSC 576
-
struct pvr2_v4l2_dev;
struct pvr2_v4l2_fh;
struct pvr2_v4l2;
@@ -80,22 +72,6 @@ static int video_nr[PVR_NUM] = {[0 ... PVR_NUM-1] = -1};
module_param_array(video_nr, int, NULL, 0444);
MODULE_PARM_DESC(video_nr, "Offset for device's minor");
-#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)
-#define V4L2_CID_PVR_INPUT (V4L2_CID_PRIVATE_BASE+8)
-#define V4L2_CID_PVR_AUDIOMODE (V4L2_CID_PRIVATE_BASE+9)
-#define V4L2_CID_PVR_FREQUENCY (V4L2_CID_PRIVATE_BASE+10)
-#define V4L2_CID_PVR_HRES (V4L2_CID_PRIVATE_BASE+11)
-#define V4L2_CID_PVR_VRES (V4L2_CID_PRIVATE_BASE+12)
-
-#define V4L2_CID_PVR_MAX (V4L2_CID_PRIVATE_BASE+12)
-
struct v4l2_capability pvr_capability ={
.driver = "pvrusb2",
.card = "Hauppauge WinTV pvr-usb2",
@@ -141,69 +117,6 @@ static struct v4l2_tuner pvr_v4l2_tuners[]= {
#endif
};
-struct v4l2_standard pvr_standards[] = {
- [PVR2_CVAL_VIDEOSTANDARD_PAL_BG] = {
- .id = V4L2_STD_PAL_BG,
- .frameperiod =
- {
- .numerator = 1,
- .denominator= 25
- },
- .framelines = 625,
- .reserved = {0,0,0,0}
- },
- [PVR2_CVAL_VIDEOSTANDARD_PAL_I] = {
- .id = V4L2_STD_PAL_I,
- .frameperiod =
- {
- .numerator = 1,
- .denominator= 25
- },
- .framelines = 625,
- .reserved = {0,0,0,0}
- },
- [PVR2_CVAL_VIDEOSTANDARD_PAL_DK] = {
- .id = V4L2_STD_PAL_DK,
- .frameperiod =
- {
- .numerator = 1,
- .denominator= 25
- },
- .framelines = 625,
- .reserved = {0,0,0,0}
- },
- [PVR2_CVAL_VIDEOSTANDARD_SECAM_L] = {
- .id = V4L2_STD_SECAM,
- .frameperiod =
- {
- .numerator = 1,
- .denominator= 25
- },
- .framelines = 625,
- .reserved = {0,0,0,0}
- },
- [PVR2_CVAL_VIDEOSTANDARD_NTSC_M] = {
- .id = V4L2_STD_NTSC_M,
- .frameperiod =
- {
- .numerator = 1001,
- .denominator= 30000
- },
- .framelines = 525,
- .reserved = {0,0,0,0}
- },
- [PVR2_CVAL_VIDEOSTANDARD_PAL_M] = {
- .id = V4L2_STD_PAL_M,
- .frameperiod =
- {
- .numerator = 1001,
- .denominator= 30000
- },
- .framelines = 525,
- .reserved = {0,0,0,0}
- }
-};
-
struct v4l2_fmtdesc pvr_fmtdesc [] = {
{
.index = 0,
@@ -257,84 +170,6 @@ struct v4l2_format pvr_format [] = {
}
};
-static int cnv_cid_v4l2_pvr2(int id)
-{
- switch (id) {
- case V4L2_CID_BRIGHTNESS:
- return PVR2_CID_BRIGHTNESS;
- case V4L2_CID_SATURATION:
- return PVR2_CID_SATURATION;
- case V4L2_CID_CONTRAST:
- return PVR2_CID_CONTRAST;
- case V4L2_CID_HUE:
- return PVR2_CID_HUE;
- case V4L2_CID_AUDIO_VOLUME:
- return PVR2_CID_VOLUME;
- case V4L2_CID_AUDIO_BALANCE:
- return PVR2_CID_BALANCE;
- case V4L2_CID_AUDIO_BASS:
- return PVR2_CID_BASS;
- case V4L2_CID_AUDIO_TREBLE:
- return PVR2_CID_TREBLE;
- case V4L2_CID_AUDIO_MUTE:
- return PVR2_CID_MUTE;
- case V4L2_CID_PVR_SRATE:
- return PVR2_CID_SRATE;
- case V4L2_CID_PVR_AUDIOBITRATE:
- return PVR2_CID_AUDIOBITRATE;
- case V4L2_CID_PVR_AUDIOCRC:
- return PVR2_CID_AUDIOCRC;
- case V4L2_CID_PVR_AUDIOEMPHASIS:
- return PVR2_CID_AUDIOEMPHASIS;
- case V4L2_CID_PVR_VBR:
- return PVR2_CID_VBR;
- case V4L2_CID_PVR_VIDEOBITRATE:
- return PVR2_CID_AVERAGEVIDEOBITRATE;
- case V4L2_CID_PVR_VIDEOPEAK:
- return PVR2_CID_PEAKVIDEOBITRATE;
- case V4L2_CID_PVR_INPUT:
- return PVR2_CID_INPUT;
- case V4L2_CID_PVR_AUDIOMODE:
- return PVR2_CID_AUDIOMODE;
- case V4L2_CID_PVR_FREQUENCY:
- return PVR2_CID_FREQUENCY;
- case V4L2_CID_PVR_HRES:
- return PVR2_CID_HRES;
- case V4L2_CID_PVR_VRES:
- return PVR2_CID_VRES;
- }
- return -1;
-}
-
-#if 0
-static int cnv_cid_pvr2_v4l2(int id)
-{
- switch (id) {
- case PVR2_CID_BRIGHTNESS:
- return V4L2_CID_BRIGHTNESS;
- case PVR2_CID_SATURATION:
- return V4L2_CID_SATURATION;
- case PVR2_CID_CONTRAST:
- return V4L2_CID_CONTRAST;
- case PVR2_CID_HUE:
- return V4L2_CID_HUE;
- case PVR2_CID_VOLUME:
- return V4L2_CID_AUDIO_VOLUME;
- case PVR2_CID_BALANCE:
- return V4L2_CID_AUDIO_BALANCE;
- case PVR2_CID_BASS:
- return V4L2_CID_AUDIO_BASS;
- case PVR2_CID_TREBLE:
- return V4L2_CID_AUDIO_TREBLE;
- case PVR2_CID_MUTE:
- return V4L2_CID_AUDIO_MUTE;
-
- return id + V4L2_CID_PRIVATE_BASE;
- }
- return -1;
-}
-#endif
-
/*
* pvr_ioctl()
*
@@ -402,92 +237,41 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
case VIDIOC_ENUMSTD:
{
-
struct v4l2_standard *vs = (struct v4l2_standard *)arg;
int idx = vs->index;
-
- if ((vs->index < PVR2_CVAL_VIDEOSTANDARD_MIN) ||
- (vs->index > PVR2_CVAL_VIDEOSTANDARD_MAX)) {
- break;
- }
-
- memcpy(vs, &pvr_standards[idx], sizeof(struct v4l2_standard));
- vs->index = idx;
- strlcpy(vs->name,
- pvr2_hdw_get_ctl_value_name(hdw,
- PVR2_CID_VIDEOSTANDARD,
- idx),
- sizeof(vs->name));
-
- ret = 0;
+ ret = pvr2_hdw_get_stdenum_value(hdw,vs,idx+1);
break;
}
case VIDIOC_G_STD:
{
- v4l2_std_id *vs = (v4l2_std_id *)arg;
-
- switch (pvr2_hdw_get_ctl_value(hdw,PVR2_CID_VIDEOSTANDARD)) {
- default:
- case PVR2_CVAL_VIDEOSTANDARD_NTSC_M:
- *vs = V4L2_STD_NTSC_M;
- break;
- case PVR2_CVAL_VIDEOSTANDARD_PAL_M:
- *vs = V4L2_STD_PAL_M;
- break;
- case PVR2_CVAL_VIDEOSTANDARD_SECAM_L:
- *vs = V4L2_STD_SECAM;
- break;
- case PVR2_CVAL_VIDEOSTANDARD_PAL_BG:
- *vs = V4L2_STD_PAL_BG;
- break;
- case PVR2_CVAL_VIDEOSTANDARD_PAL_I:
- *vs = V4L2_STD_PAL_I;
- break;
- case PVR2_CVAL_VIDEOSTANDARD_PAL_DK:
- *vs = V4L2_STD_PAL_DK;
- break;
- }
- ret = 0;
+ int val = 0;
+ ret = pvr2_ctrl_get_value(
+ pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDCUR),&val);
+ *(v4l2_std_id *)arg = val;
break;
}
case VIDIOC_S_STD:
{
- v4l2_std_id *vs = (v4l2_std_id *)arg;
- int val = PVR2_CVAL_VIDEOSTANDARD_NTSC_M;
-
- if (*vs & V4L2_STD_NTSC_M){
- val = PVR2_CVAL_VIDEOSTANDARD_NTSC_M;
- } else if (*vs & V4L2_STD_PAL_BG){
- val = PVR2_CVAL_VIDEOSTANDARD_PAL_BG;
- } else if (*vs & V4L2_STD_PAL_I){
- val = PVR2_CVAL_VIDEOSTANDARD_PAL_I;
- } else if (*vs & V4L2_STD_PAL_DK){
- val = PVR2_CVAL_VIDEOSTANDARD_PAL_DK;
- } else if (*vs & V4L2_STD_SECAM){
- val = PVR2_CVAL_VIDEOSTANDARD_SECAM_L;
- } else if (*vs & V4L2_STD_PAL_M){
- val = PVR2_CVAL_VIDEOSTANDARD_PAL_M;
- }
-
- pvr2_hdw_set_ctl_value(hdw,PVR2_CID_VIDEOSTANDARD,val);
-
+ ret = pvr2_ctrl_set_value(
+ pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDCUR),
+ *(v4l2_std_id *)arg);
break;
}
case VIDIOC_ENUMINPUT:
{
+ struct pvr2_ctrl *cptr;
struct v4l2_input *vi = (struct v4l2_input *)arg;
struct v4l2_input tmp;
+ unsigned int cnt;
- if ((vi->index > PVR2_CVAL_INPUT_MAX) ||
- (vi->index < PVR2_CVAL_INPUT_MIN)) {
- break;
- }
+ cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
memset(&tmp,0,sizeof(tmp));
tmp.index = vi->index;
+ ret = 0;
switch (vi->index) {
case PVR2_CVAL_INPUT_TV:
case PVR2_CVAL_INPUT_RADIO:
@@ -497,12 +281,16 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
case PVR2_CVAL_INPUT_COMPOSITE:
tmp.type = V4L2_INPUT_TYPE_CAMERA;
break;
+ default:
+ ret = -EINVAL;
+ break;
}
+ if (ret < 0) break;
- strlcpy(tmp.name,
- pvr2_hdw_get_ctl_value_name(hdw,PVR2_CID_INPUT,
- vi->index),
- sizeof(tmp.name));
+ cnt = 0;
+ pvr2_ctrl_get_valname(cptr,vi->index,
+ tmp.name,sizeof(tmp.name)-1,&cnt);
+ tmp.name[cnt] = 0;
/* Don't bother with audioset, since this driver currently
always switches the audio whenever the video is
@@ -522,19 +310,22 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
case VIDIOC_G_INPUT:
{
+ struct pvr2_ctrl *cptr;
struct v4l2_input *vi = (struct v4l2_input *)arg;
- vi->index = pvr2_hdw_get_ctl_value(hdw,PVR2_CID_INPUT);
- ret = 0;
+ int val;
+ cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
+ val = 0;
+ ret = pvr2_ctrl_get_value(cptr,&val);
+ vi->index = val;
break;
}
case VIDIOC_S_INPUT:
{
struct v4l2_input *vi = (struct v4l2_input *)arg;
- ret = 0;
- if (pvr2_hdw_set_ctl_value(hdw,PVR2_CID_INPUT,vi->index)) {
- ret = -EINVAL;
- }
+ ret = pvr2_ctrl_set_value(
+ pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT),
+ vi->index);
break;
}
@@ -559,6 +350,7 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
{
struct v4l2_tuner *vt = (struct v4l2_tuner *)arg;
unsigned int status_mask;
+ int val;
if (vt->index !=0) break;
status_mask = pvr2_hdw_get_signal_status(hdw);
@@ -580,83 +372,44 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
vt->signal = 65535;
}
- switch (pvr2_hdw_get_ctl_value(hdw,PVR2_CID_AUDIOMODE)) {
- case PVR2_CVAL_AUDIOMODE_MONO:
- vt->audmode = V4L2_TUNER_MODE_MONO;
- break;
- case PVR2_CVAL_AUDIOMODE_STEREO:
- vt->audmode = V4L2_TUNER_MODE_STEREO;
- break;
- case PVR2_CVAL_AUDIOMODE_LANG1:
- vt->audmode = V4L2_TUNER_MODE_LANG1;
- break;
- case PVR2_CVAL_AUDIOMODE_LANG2:
- vt->audmode = V4L2_TUNER_MODE_LANG2;
- break;
- case PVR2_CVAL_AUDIOMODE_LANG1_LANG2:
- vt->audmode = V4L2_TUNER_MODE_LANG1_LANG2;
- break;
- case PVR2_CVAL_AUDIOMODE_SAP:
- vt->audmode = V4L2_TUNER_MODE_SAP;
- break;
- }
-
- ret = 0;
+ val = 0;
+ ret = pvr2_ctrl_get_value(
+ pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_AUDIOMODE),
+ &val);
+ vt->audmode = val;
break;
}
case VIDIOC_S_TUNER:
{
struct v4l2_tuner *vt=(struct v4l2_tuner *)arg;
- int val = PVR2_CVAL_AUDIOMODE_STEREO;
if (vt->index != 0)
break;
- switch (vt->audmode) {
- case V4L2_TUNER_MODE_MONO:
- val = PVR2_CVAL_AUDIOMODE_MONO;
- break;
- case V4L2_TUNER_MODE_STEREO:
- val = PVR2_CVAL_AUDIOMODE_STEREO;
- break;
- case V4L2_TUNER_MODE_LANG1:
- val = PVR2_CVAL_AUDIOMODE_LANG1;
- break;
- case V4L2_TUNER_MODE_LANG1_LANG2:
- val = PVR2_CVAL_AUDIOMODE_LANG1_LANG2;
- break;
- case V4L2_TUNER_MODE_SAP: // Also LANG2
- val = PVR2_CVAL_AUDIOMODE_SAP;
- break;
- }
-
- pvr2_hdw_set_ctl_value(hdw,PVR2_CID_AUDIOMODE,val);
- ret = 0;
+ ret = pvr2_ctrl_set_value(
+ pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_AUDIOMODE),
+ vt->audmode);
}
case VIDIOC_S_FREQUENCY:
{
const struct v4l2_frequency *vf = (struct v4l2_frequency *)arg;
-
- pvr2_hdw_set_ctl_value(hdw,PVR2_CID_FREQUENCY,
- vf->frequency * 62500);
-
- ret = 0;
+ ret = pvr2_ctrl_set_value(
+ pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_FREQUENCY),
+ vf->frequency * 62500);
break;
}
case VIDIOC_G_FREQUENCY:
{
struct v4l2_frequency *vf = (struct v4l2_frequency *)arg;
- int val;
-
- val = pvr2_hdw_get_ctl_value(hdw,PVR2_CID_FREQUENCY);
-
+ int val = 0;
+ ret = pvr2_ctrl_get_value(
+ pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_FREQUENCY),
+ &val);
val /= 62500;
vf->frequency = val;
-
- ret = 0;
break;
}
@@ -676,18 +429,27 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
case VIDIOC_G_FMT:
{
struct v4l2_format *vf = (struct v4l2_format *)arg;
-
+ int val;
switch(vf->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
memcpy(vf, &pvr_format[PVR_FORMAT_PIX],
sizeof(struct v4l2_format));
- vf->fmt.pix.width =
- pvr2_hdw_get_ctl_value(hdw,PVR2_CID_HRES);
- if (pvr2_hdw_get_ctl_value(hdw,PVR2_CID_INTERLACE)) {
- vf->fmt.pix.width /= 2;
- }
- vf->fmt.pix.height =
- pvr2_hdw_get_ctl_value(hdw,PVR2_CID_VRES);
+ val = 0;
+ pvr2_ctrl_get_value(
+ pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_HRES),
+ &val);
+ 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;
ret = 0;
break;
case V4L2_BUF_TYPE_VBI_CAPTURE:
@@ -713,16 +475,14 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
int w = vf->fmt.pix.width;
int vd_std, hf, hh;
- vd_std = pvr2_hdw_get_ctl_value(hdw,
- PVR2_CID_VIDEOSTANDARD);
- switch (vd_std) {
- case PVR2_CVAL_VIDEOSTANDARD_NTSC_M:
- case PVR2_CVAL_VIDEOSTANDARD_PAL_M:
+ 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;
- break;
- default:
+ } else {
hf=576;
- break;
}
hh = (int) (hf / 2);
@@ -733,16 +493,19 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
vf->fmt.pix.width &= 0xff0;
vf->fmt.pix.height = (h > hh) ? hf : hh;
- if (cmd == VIDIOC_S_FMT){
- pvr2_hdw_set_ctl_value(
- hdw,PVR2_CID_HRES,
+ if (cmd == VIDIOC_S_FMT) {
+ pvr2_ctrl_set_value(
+ pvr2_hdw_get_ctrl_by_id(hdw,
+ PVR2_CID_HRES),
vf->fmt.pix.width);
- pvr2_hdw_set_ctl_value(
- hdw,PVR2_CID_VRES,
+ pvr2_ctrl_set_value(
+ pvr2_hdw_get_ctrl_by_id(hdw,
+ PVR2_CID_VRES),
vf->fmt.pix.height);
- pvr2_hdw_set_ctl_value(
- hdw,PVR2_CID_INTERLACE,
- (vf->fmt.pix.height != hf));
+ 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:
@@ -772,82 +535,75 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
case VIDIOC_QUERYCTRL:
{
+ struct pvr2_ctrl *cptr;
struct v4l2_queryctrl *vc = (struct v4l2_queryctrl *)arg;
- int pvr2_id = cnv_cid_v4l2_pvr2(vc->id);
- if (pvr2_id < 0) {
+ ret = 0;
+ cptr = pvr2_hdw_get_ctrl_v4l(hdw,vc->id);
+ if (!cptr) {
ret = -EINVAL;
break;
}
- if (pvr2_hdw_get_ctl_value_name(hdw,pvr2_id,0)) {
+ strlcpy(vc->name,pvr2_ctrl_get_name(cptr),sizeof(vc->name));
+ vc->default_value = pvr2_ctrl_get_def(cptr);
+ switch (pvr2_ctrl_get_type(cptr)) {
+ case pvr2_ctl_enum:
vc->type = V4L2_CTRL_TYPE_MENU;
- } else {
+ vc->minimum = 0;
+ vc->maximum = pvr2_ctrl_get_cnt(cptr) - 1;
+ vc->step = 1;
+ break;
+ case pvr2_ctl_int:
vc->type = V4L2_CTRL_TYPE_INTEGER;
+ vc->minimum = pvr2_ctrl_get_min(cptr);
+ vc->maximum = pvr2_ctrl_get_max(cptr);
+ vc->step = 1;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
}
- strlcpy(vc->name,pvr2_hdw_get_ctl_name(hdw,pvr2_id),
- sizeof(vc->name));
- vc->minimum = pvr2_hdw_get_ctl_min_value(hdw,pvr2_id);
- vc->maximum = pvr2_hdw_get_ctl_max_value(hdw,pvr2_id);
- vc->step = 1;
- ret = 0;
break;
}
case VIDIOC_QUERYMENU:
{
struct v4l2_querymenu *vm = (struct v4l2_querymenu *)arg;
- int pvr2_id = cnv_cid_v4l2_pvr2(vm->id);
- const char *value_name;
- if (pvr2_id < 0) {
- ret = -EINVAL;
- break;
- }
-
- value_name = pvr2_hdw_get_ctl_value_name(hdw,pvr2_id,
- vm->index);
- if (value_name) {
- strlcpy(vm->name,value_name,sizeof(vm->name));
- ret = 0;
- } else {
- ret = -EINVAL;
- }
-
+ unsigned int cnt = 0;
+ ret = pvr2_ctrl_get_valname(pvr2_hdw_get_ctrl_v4l(hdw,vm->id),
+ vm->index,
+ vm->name,sizeof(vm->name)-1,
+ &cnt);
+ vm->name[cnt] = 0;
break;
}
case VIDIOC_G_CTRL:
{
struct v4l2_control *vc = (struct v4l2_control *)arg;
- int pvr2_id;
-
- pvr2_id = cnv_cid_v4l2_pvr2(vc->id);
- if (pvr2_id < 0) {
- ret = -EINVAL;
- break;
- }
- ret = 0;
- vc->value = pvr2_hdw_get_ctl_value(hdw,pvr2_id);
+ int val = 0;
+ ret = pvr2_ctrl_get_value(pvr2_hdw_get_ctrl_v4l(hdw,vc->id),
+ &val);
+ vc->value = val;
break;
}
case VIDIOC_S_CTRL:
{
struct v4l2_control *vc = (struct v4l2_control *)arg;
- int pvr2_id;
-
- pvr2_id = cnv_cid_v4l2_pvr2(vc->id);
- if (pvr2_id < 0) {
- ret = -EINVAL;
- break;
- }
-
- ret = pvr2_hdw_set_ctl_value(hdw,pvr2_id,vc->value);
+ ret = pvr2_ctrl_set_value(pvr2_hdw_get_ctrl_v4l(hdw,vc->id),
+ vc->value);
break;
}
case VIDIOC_LOG_STATUS:
{
+ int nr = pvr2_hdw_get_unit_number(hdw);
+
+ printk(KERN_INFO "pvrusb2: ================= START STATUS CARD #%d =================\n", nr);
pvr2_hdw_trigger_module_log(hdw);
+ printk(KERN_INFO "pvrusb2: ================== END STATUS CARD #%d ==================\n", nr);
+ ret = 0;
break;
}
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c b/linux/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c
index 97c3e2c38..4127c82f7 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c
@@ -29,11 +29,12 @@
*/
#include "pvrusb2-video-v4l.h"
+#include "pvrusb2-i2c-cmd-v4l2.h"
#include "pvrusb2-hdw-internal.h"
#include "pvrusb2-debug.h"
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
#include <media/v4l2-common.h>
#include <media/saa7115.h>
#include <linux/errno.h>
@@ -53,9 +54,8 @@ static void set_input(struct pvr2_v4l_decoder *ctxt)
struct pvr2_hdw *hdw = ctxt->hdw;
struct v4l2_routing route;
- pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_input(%d)",
- hdw->controls[PVR2_CID_INPUT].value);
- switch(hdw->controls[PVR2_CID_INPUT].value){
+ pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_input(%d)",hdw->input_val);
+ switch(hdw->input_val) {
case PVR2_CVAL_INPUT_TV:
route.input = SAA7115_COMPOSITE4;
break;
@@ -78,7 +78,7 @@ static void set_input(struct pvr2_v4l_decoder *ctxt)
static int check_input(struct pvr2_v4l_decoder *ctxt)
{
struct pvr2_hdw *hdw = ctxt->hdw;
- return hdw->controls[PVR2_CID_INPUT].dirty != 0;
+ return hdw->input_dirty != 0;
}
@@ -88,8 +88,8 @@ static void set_audio(struct pvr2_v4l_decoder *ctxt)
struct pvr2_hdw *hdw = ctxt->hdw;
pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_audio %d",
- hdw->controls[PVR2_CID_SRATE].value);
- switch (hdw->controls[PVR2_CID_SRATE].value) {
+ hdw->srate_val);
+ switch (hdw->srate_val) {
default:
case PVR2_CVAL_SRATE_48:
val = 48000;
@@ -105,7 +105,7 @@ static void set_audio(struct pvr2_v4l_decoder *ctxt)
static int check_audio(struct pvr2_v4l_decoder *ctxt)
{
struct pvr2_hdw *hdw = ctxt->hdw;
- return hdw->controls[PVR2_CID_SRATE].dirty != 0;
+ return hdw->srate_dirty != 0;
}
@@ -176,8 +176,7 @@ static int decoder_detect(struct pvr2_i2c_client *cp)
static void decoder_enable(struct pvr2_v4l_decoder *ctxt,int fl)
{
pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 decoder_enable(%d)",fl);
- pvr2_i2c_client_cmd(ctxt->client,
- (fl ? VIDIOC_STREAMON : VIDIOC_STREAMOFF),0);
+ pvr2_v4l2_cmd_stream(ctxt->client,fl);
}
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-wm8775.c b/linux/drivers/media/video/pvrusb2/pvrusb2-wm8775.c
new file mode 100644
index 000000000..fcad346e3
--- /dev/null
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-wm8775.c
@@ -0,0 +1,170 @@
+/*
+ *
+ * $Id$
+ *
+ * Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/*
+
+ This source file is specifically designed to interface with the
+ wm8775.
+
+*/
+
+#include "pvrusb2-wm8775.h"
+#include "pvrusb2-i2c-cmd-v4l2.h"
+
+
+#include "pvrusb2-hdw-internal.h"
+#include "pvrusb2-debug.h"
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+
+struct pvr2_v4l_wm8775 {
+ struct pvr2_i2c_handler handler;
+ struct pvr2_i2c_client *client;
+ struct pvr2_hdw *hdw;
+ unsigned long stale_mask;
+};
+
+
+static void set_input(struct pvr2_v4l_wm8775 *ctxt)
+{
+ struct v4l2_routing route;
+ struct pvr2_hdw *hdw = ctxt->hdw;
+ int msk = 0;
+
+ memset(&route,0,sizeof(route));
+
+ pvr2_trace(PVR2_TRACE_CHIPS,"i2c wm8775 set_input(val=%d msk=0x%x)",
+ hdw->input_val,msk);
+
+ // Always point to input #1 no matter what
+ route.input = 2;
+ pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_S_AUDIO_ROUTING,&route);
+}
+
+static int check_input(struct pvr2_v4l_wm8775 *ctxt)
+{
+ struct pvr2_hdw *hdw = ctxt->hdw;
+ return hdw->input_dirty != 0;
+}
+
+
+struct pvr2_v4l_wm8775_ops {
+ void (*update)(struct pvr2_v4l_wm8775 *);
+ int (*check)(struct pvr2_v4l_wm8775 *);
+};
+
+
+static const struct pvr2_v4l_wm8775_ops wm8775_ops[] = {
+ { .update = set_input, .check = check_input},
+};
+
+
+static unsigned int wm8775_describe(struct pvr2_v4l_wm8775 *ctxt,
+ char *buf,unsigned int cnt)
+{
+ return scnprintf(buf,cnt,"handler: pvrusb2-wm8775");
+}
+
+
+static void wm8775_detach(struct pvr2_v4l_wm8775 *ctxt)
+{
+ ctxt->client->handler = 0;
+ kfree(ctxt);
+}
+
+
+static int wm8775_check(struct pvr2_v4l_wm8775 *ctxt)
+{
+ unsigned long msk;
+ unsigned int idx;
+
+ for (idx = 0; idx < sizeof(wm8775_ops)/sizeof(wm8775_ops[0]);
+ idx++) {
+ msk = 1 << idx;
+ if (ctxt->stale_mask & msk) continue;
+ if (wm8775_ops[idx].check(ctxt)) {
+ ctxt->stale_mask |= msk;
+ }
+ }
+ return ctxt->stale_mask != 0;
+}
+
+
+static void wm8775_update(struct pvr2_v4l_wm8775 *ctxt)
+{
+ unsigned long msk;
+ unsigned int idx;
+
+ for (idx = 0; idx < sizeof(wm8775_ops)/sizeof(wm8775_ops[0]);
+ idx++) {
+ msk = 1 << idx;
+ if (!(ctxt->stale_mask & msk)) continue;
+ ctxt->stale_mask &= ~msk;
+ wm8775_ops[idx].update(ctxt);
+ }
+}
+
+
+const static struct pvr2_i2c_handler_functions hfuncs = {
+ .detach = (void (*)(void *))wm8775_detach,
+ .check = (int (*)(void *))wm8775_check,
+ .update = (void (*)(void *))wm8775_update,
+ .describe = (unsigned int (*)(void *,char *,unsigned int))wm8775_describe,
+};
+
+
+int pvr2_i2c_wm8775_setup(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp)
+{
+ struct pvr2_v4l_wm8775 *ctxt;
+
+ if (cp->handler) return 0;
+
+ ctxt = kmalloc(sizeof(*ctxt),GFP_KERNEL);
+ if (!ctxt) return 0;
+ memset(ctxt,0,sizeof(*ctxt));
+
+ ctxt->handler.func_data = ctxt;
+ ctxt->handler.func_table = &hfuncs;
+ ctxt->client = cp;
+ ctxt->hdw = hdw;
+ ctxt->stale_mask = (1 << (sizeof(wm8775_ops)/
+ sizeof(wm8775_ops[0]))) - 1;
+ cp->handler = &ctxt->handler;
+ pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x wm8775 V4L2 handler set up",
+ cp->client->addr);
+ return !0;
+}
+
+
+
+
+/*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+ *** Local Variables: ***
+ *** mode: c ***
+ *** fill-column: 70 ***
+ *** tab-width: 8 ***
+ *** c-basic-offset: 8 ***
+ *** End: ***
+ */
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-wm8775.h b/linux/drivers/media/video/pvrusb2/pvrusb2-wm8775.h
new file mode 100644
index 000000000..15ee1e215
--- /dev/null
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-wm8775.h
@@ -0,0 +1,54 @@
+/*
+ *
+ * $Id$
+ *
+ * Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef __PVRUSB2_WM8775_H
+#define __PVRUSB2_WM8775_H
+
+/*
+
+ This module connects the pvrusb2 driver to the I2C chip level
+ driver which performs analog -> digital audio conversion for
+ external audio inputs. This interface is used internally by the
+ driver; higher level code should only interact through the
+ interface provided by pvrusb2-hdw.h.
+
+*/
+
+#include "compat.h"
+
+
+#include "pvrusb2-i2c-core.h"
+
+int pvr2_i2c_wm8775_setup(struct pvr2_hdw *,struct pvr2_i2c_client *);
+
+
+#endif /* __PVRUSB2_WM8775_H */
+
+/*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+ *** Local Variables: ***
+ *** mode: c ***
+ *** fill-column: 70 ***
+ *** tab-width: 8 ***
+ *** c-basic-offset: 8 ***
+ *** End: ***
+ */