aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/pvrusb2
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/pvrusb2')
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-audio.c48
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-context.c3
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-ctrl.c45
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c29
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-debugifc.c4
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-eeprom.c5
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-encoder.c269
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-fx2-cmd.h62
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h38
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw.c524
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw.h47
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c16
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c69
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h3
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-i2c-core.c41
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-i2c-core.h3
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-io.c3
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-ioread.c3
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-std.c32
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-sysfs.c82
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-tuner.c5
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-v4l2.c341
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-video-v4l.c31
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-wm8775.c30
24 files changed, 1149 insertions, 584 deletions
diff --git a/drivers/media/video/pvrusb2/pvrusb2-audio.c b/drivers/media/video/pvrusb2/pvrusb2-audio.c
index 9846c464ec80..379645e481c6 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-audio.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-audio.c
@@ -31,7 +31,6 @@ struct pvr2_msp3400_handler {
struct pvr2_hdw *hdw;
struct pvr2_i2c_client *client;
struct pvr2_i2c_handler i2c_handler;
- struct pvr2_audio_stat astat;
unsigned long stale_mask;
};
@@ -44,13 +43,6 @@ static void set_stereo(struct pvr2_msp3400_handler *ctxt)
pvr2_trace(PVR2_TRACE_CHIPS,"i2c msp3400 v4l2 set_stereo");
- if (hdw->input_val == PVR2_CVAL_INPUT_TV) {
- struct v4l2_tuner vt;
- memset(&vt,0,sizeof(vt));
- 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_SC_IN_DSP_SCART1);
switch (hdw->input_val) {
@@ -78,8 +70,7 @@ 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->input_dirty ||
- hdw->audiomode_dirty);
+ return hdw->input_dirty;
}
@@ -99,8 +90,7 @@ static int msp3400_check(struct pvr2_msp3400_handler *ctxt)
unsigned long msk;
unsigned int idx;
- for (idx = 0; idx < sizeof(msp3400_ops)/sizeof(msp3400_ops[0]);
- idx++) {
+ for (idx = 0; idx < ARRAY_SIZE(msp3400_ops); idx++) {
msk = 1 << idx;
if (ctxt->stale_mask & msk) continue;
if (msp3400_ops[idx].check(ctxt)) {
@@ -116,8 +106,7 @@ static void msp3400_update(struct pvr2_msp3400_handler *ctxt)
unsigned long msk;
unsigned int idx;
- for (idx = 0; idx < sizeof(msp3400_ops)/sizeof(msp3400_ops[0]);
- idx++) {
+ for (idx = 0; idx < ARRAY_SIZE(msp3400_ops); idx++) {
msk = 1 << idx;
if (!(ctxt->stale_mask & msk)) continue;
ctxt->stale_mask &= ~msk;
@@ -126,27 +115,9 @@ static void msp3400_update(struct pvr2_msp3400_handler *ctxt)
}
-/* This reads back the current signal type */
-static int get_audio_status(struct pvr2_msp3400_handler *ctxt)
-{
- struct v4l2_tuner vt;
- int stat;
-
- memset(&vt,0,sizeof(vt));
- stat = pvr2_i2c_client_cmd(ctxt->client,VIDIOC_G_TUNER,&vt);
- if (stat < 0) return stat;
-
- ctxt->hdw->flag_stereo = (vt.audmode & V4L2_TUNER_MODE_STEREO) != 0;
- ctxt->hdw->flag_bilingual =
- (vt.audmode & V4L2_TUNER_MODE_LANG2) != 0;
- return 0;
-}
-
-
static void pvr2_msp3400_detach(struct pvr2_msp3400_handler *ctxt)
{
ctxt->client->handler = NULL;
- ctxt->hdw->audio_stat = NULL;
kfree(ctxt);
}
@@ -158,7 +129,7 @@ static unsigned int pvr2_msp3400_describe(struct pvr2_msp3400_handler *ctxt,
}
-const static struct pvr2_i2c_handler_functions msp3400_funcs = {
+static const struct pvr2_i2c_handler_functions msp3400_funcs = {
.detach = (void (*)(void *))pvr2_msp3400_detach,
.check = (int (*)(void *))msp3400_check,
.update = (void (*)(void *))msp3400_update,
@@ -169,24 +140,17 @@ const static struct pvr2_i2c_handler_functions msp3400_funcs = {
int pvr2_i2c_msp3400_setup(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp)
{
struct pvr2_msp3400_handler *ctxt;
- if (hdw->audio_stat) return 0;
if (cp->handler) return 0;
- ctxt = kmalloc(sizeof(*ctxt),GFP_KERNEL);
+ ctxt = kzalloc(sizeof(*ctxt),GFP_KERNEL);
if (!ctxt) return 0;
- memset(ctxt,0,sizeof(*ctxt));
ctxt->i2c_handler.func_data = ctxt;
ctxt->i2c_handler.func_table = &msp3400_funcs;
ctxt->client = cp;
ctxt->hdw = hdw;
- ctxt->astat.ctxt = ctxt;
- ctxt->astat.status = (int (*)(void *))get_audio_status;
- ctxt->astat.detach = (void (*)(void *))pvr2_msp3400_detach;
- ctxt->stale_mask = (1 << (sizeof(msp3400_ops)/
- sizeof(msp3400_ops[0]))) - 1;
+ ctxt->stale_mask = (1 << ARRAY_SIZE(msp3400_ops)) - 1;
cp->handler = &ctxt->i2c_handler;
- hdw->audio_stat = &ctxt->astat;
pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x msp3400 V4L2 handler set up",
cp->client->addr);
return !0;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-context.c b/drivers/media/video/pvrusb2/pvrusb2-context.c
index cf129746205d..6bbed88d7867 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-context.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-context.c
@@ -83,9 +83,8 @@ struct pvr2_context *pvr2_context_create(
void (*setup_func)(struct pvr2_context *))
{
struct pvr2_context *mp = NULL;
- mp = kmalloc(sizeof(*mp),GFP_KERNEL);
+ mp = kzalloc(sizeof(*mp),GFP_KERNEL);
if (!mp) goto done;
- memset(mp,0,sizeof(*mp));
pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr_main id=%p",mp);
mp->setup_func = setup_func;
mutex_init(&mp->mutex);
diff --git a/drivers/media/video/pvrusb2/pvrusb2-ctrl.c b/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
index c77de859cc8e..f569b00201dd 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
@@ -26,6 +26,27 @@
#include <linux/mutex.h>
+static int pvr2_ctrl_range_check(struct pvr2_ctrl *cptr,int val)
+{
+ if (cptr->info->check_value) {
+ if (!cptr->info->check_value(cptr,val)) return -ERANGE;
+ } else {
+ int lim;
+ lim = cptr->info->def.type_int.min_value;
+ if (cptr->info->get_min_value) {
+ cptr->info->get_min_value(cptr,&lim);
+ }
+ if (val < lim) return -ERANGE;
+ lim = cptr->info->def.type_int.max_value;
+ if (cptr->info->get_max_value) {
+ cptr->info->get_max_value(cptr,&lim);
+ }
+ if (val > lim) return -ERANGE;
+ }
+ return 0;
+}
+
+
/* Set the given control. */
int pvr2_ctrl_set_value(struct pvr2_ctrl *cptr,int val)
{
@@ -43,17 +64,8 @@ int pvr2_ctrl_set_mask_value(struct pvr2_ctrl *cptr,int mask,int val)
if (cptr->info->type == pvr2_ctl_bitmask) {
mask &= cptr->info->def.type_bitmask.valid_bits;
} else if (cptr->info->type == pvr2_ctl_int) {
- int lim;
- lim = cptr->info->def.type_int.min_value;
- if (cptr->info->get_min_value) {
- cptr->info->get_min_value(cptr,&lim);
- }
- if (val < lim) break;
- lim = cptr->info->def.type_int.max_value;
- if (cptr->info->get_max_value) {
- cptr->info->get_max_value(cptr,&lim);
- }
- if (val > lim) break;
+ ret = pvr2_ctrl_range_check(cptr,val);
+ if (ret < 0) break;
} else if (cptr->info->type == pvr2_ctl_enum) {
if (val >= cptr->info->def.type_enum.count) {
break;
@@ -498,16 +510,13 @@ int pvr2_ctrl_sym_to_value(struct pvr2_ctrl *cptr,
LOCK_TAKE(cptr->hdw->big_lock); do {
if (cptr->info->type == pvr2_ctl_int) {
ret = parse_token(ptr,len,valptr,NULL,0);
- if ((ret >= 0) &&
- ((*valptr < cptr->info->def.type_int.min_value) ||
- (*valptr > cptr->info->def.type_int.max_value))) {
- ret = -ERANGE;
+ if (ret >= 0) {
+ ret = pvr2_ctrl_range_check(cptr,*valptr);
}
if (maskptr) *maskptr = ~0;
} else if (cptr->info->type == pvr2_ctl_bool) {
- ret = parse_token(
- ptr,len,valptr,boolNames,
- sizeof(boolNames)/sizeof(boolNames[0]));
+ ret = parse_token(ptr,len,valptr,boolNames,
+ ARRAY_SIZE(boolNames));
if (ret == 1) {
*valptr = *valptr ? !0 : 0;
} else if (ret == 0) {
diff --git a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
index 848fb233d808..e8a9252c7df6 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
@@ -63,6 +63,7 @@ static void set_input(struct pvr2_v4l_cx2584x *ctxt)
vid_input = CX25840_COMPOSITE7;
aud_input = CX25840_AUDIO8;
break;
+ case PVR2_CVAL_INPUT_RADIO: // Treat same as composite
case PVR2_CVAL_INPUT_COMPOSITE:
vid_input = CX25840_COMPOSITE3;
aud_input = CX25840_AUDIO_SERIAL;
@@ -71,7 +72,6 @@ static void set_input(struct pvr2_v4l_cx2584x *ctxt)
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;
@@ -150,8 +150,7 @@ 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++) {
+ for (idx = 0; idx < ARRAY_SIZE(decoder_ops); idx++) {
msk = 1 << idx;
if (ctxt->stale_mask & msk) continue;
if (decoder_ops[idx].check(ctxt)) {
@@ -167,8 +166,7 @@ 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++) {
+ for (idx = 0; idx < ARRAY_SIZE(decoder_ops); idx++) {
msk = 1 << idx;
if (!(ctxt->stale_mask & msk)) continue;
ctxt->stale_mask &= ~msk;
@@ -199,18 +197,6 @@ static int decoder_detect(struct pvr2_i2c_client *cp)
}
-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)
{
@@ -226,7 +212,7 @@ static void decoder_reset(struct pvr2_v4l_cx2584x *ctxt)
}
-const static struct pvr2_i2c_handler_functions hfuncs = {
+static const struct pvr2_i2c_handler_functions hfuncs = {
.detach = (void (*)(void *))decoder_detach,
.check = (int (*)(void *))decoder_check,
.update = (void (*)(void *))decoder_update,
@@ -243,21 +229,18 @@ int pvr2_i2c_cx2584x_v4l_setup(struct pvr2_hdw *hdw,
if (cp->handler) return 0;
if (!decoder_detect(cp)) return 0;
- ctxt = kmalloc(sizeof(*ctxt),GFP_KERNEL);
+ ctxt = kzalloc(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;
+ ctxt->stale_mask = (1 << ARRAY_SIZE(decoder_ops)) - 1;
hdw->decoder_ctrl = &ctxt->ctrl;
cp->handler = &ctxt->handler;
{
diff --git a/drivers/media/video/pvrusb2/pvrusb2-debugifc.c b/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
index f985f00d885a..e9da9bb8f8de 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
@@ -152,7 +152,7 @@ static unsigned long debugifc_find_mask(const char *buf,unsigned int count)
{
struct debugifc_mask_item *mip;
unsigned int idx;
- for (idx = 0; idx < sizeof(mask_items)/sizeof(mask_items[0]); idx++) {
+ for (idx = 0; idx < ARRAY_SIZE(mask_items); idx++) {
mip = mask_items + idx;
if (debugifc_match_keyword(buf,count,mip->name)) {
return mip->msk;
@@ -169,7 +169,7 @@ static int debugifc_print_mask(char *buf,unsigned int sz,
unsigned int idx;
int bcnt = 0;
int ccnt;
- for (idx = 0; idx < sizeof(mask_items)/sizeof(mask_items[0]); idx++) {
+ for (idx = 0; idx < ARRAY_SIZE(mask_items); idx++) {
mip = mask_items + idx;
if (!(mip->msk & msk)) continue;
ccnt = scnprintf(buf,sz,"%s%c%s",
diff --git a/drivers/media/video/pvrusb2/pvrusb2-eeprom.c b/drivers/media/video/pvrusb2/pvrusb2-eeprom.c
index 6cff8e75f426..45cbca0143ca 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-eeprom.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-eeprom.c
@@ -102,9 +102,8 @@ static u8 *pvr2_eeprom_fetch(struct pvr2_hdw *hdw)
}
msg[1].len = pcnt;
msg[1].buf = eeprom+tcnt;
- if ((ret = i2c_transfer(
- &hdw->i2c_adap,
- msg,sizeof(msg)/sizeof(msg[0]))) != 2) {
+ if ((ret = i2c_transfer(&hdw->i2c_adap,
+ msg,ARRAY_SIZE(msg))) != 2) {
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
"eeprom fetch set offs err=%d",ret);
kfree(eeprom);
diff --git a/drivers/media/video/pvrusb2/pvrusb2-encoder.c b/drivers/media/video/pvrusb2/pvrusb2-encoder.c
index c94f97b79392..5669c8ca9ca3 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-encoder.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-encoder.c
@@ -26,6 +26,7 @@
#include "pvrusb2-encoder.h"
#include "pvrusb2-hdw-internal.h"
#include "pvrusb2-debug.h"
+#include "pvrusb2-fx2-cmd.h"
@@ -34,34 +35,41 @@
#define IVTV_MBOX_DRIVER_DONE 0x00000002
#define IVTV_MBOX_DRIVER_BUSY 0x00000001
+#define MBOX_BASE 0x44
+
static int pvr2_encoder_write_words(struct pvr2_hdw *hdw,
+ unsigned int offs,
const u32 *data, unsigned int dlen)
{
- unsigned int idx;
+ unsigned int idx,addr;
+ unsigned int bAddr;
int ret;
- unsigned int offs = 0;
unsigned int chunkCnt;
/*
Format: First byte must be 0x01. Remaining 32 bit words are
- spread out into chunks of 7 bytes each, little-endian ordered,
- offset at zero within each 2 blank bytes following and a
- single byte that is 0x44 plus the offset of the word. Repeat
- request for additional words, with offset adjusted
- accordingly.
+ spread out into chunks of 7 bytes each, with the first 4 bytes
+ being the data word (little endian), and the next 3 bytes
+ being the address where that data word is to be written (big
+ endian). Repeat request for additional words, with offset
+ adjusted accordingly.
*/
while (dlen) {
chunkCnt = 8;
if (chunkCnt > dlen) chunkCnt = dlen;
memset(hdw->cmd_buffer,0,sizeof(hdw->cmd_buffer));
- hdw->cmd_buffer[0] = 0x01;
+ bAddr = 0;
+ hdw->cmd_buffer[bAddr++] = FX2CMD_MEM_WRITE_DWORD;
for (idx = 0; idx < chunkCnt; idx++) {
- hdw->cmd_buffer[1+(idx*7)+6] = 0x44 + idx + offs;
- PVR2_DECOMPOSE_LE(hdw->cmd_buffer, 1+(idx*7),
- data[idx]);
+ addr = idx + offs;
+ hdw->cmd_buffer[bAddr+6] = (addr & 0xffu);
+ hdw->cmd_buffer[bAddr+5] = ((addr>>8) & 0xffu);
+ hdw->cmd_buffer[bAddr+4] = ((addr>>16) & 0xffu);
+ PVR2_DECOMPOSE_LE(hdw->cmd_buffer, bAddr,data[idx]);
+ bAddr += 7;
}
ret = pvr2_send_request(hdw,
hdw->cmd_buffer,1+(chunkCnt*7),
@@ -76,33 +84,42 @@ static int pvr2_encoder_write_words(struct pvr2_hdw *hdw,
}
-static int pvr2_encoder_read_words(struct pvr2_hdw *hdw,int statusFl,
+static int pvr2_encoder_read_words(struct pvr2_hdw *hdw,
+ unsigned int offs,
u32 *data, unsigned int dlen)
{
unsigned int idx;
int ret;
- unsigned int offs = 0;
unsigned int chunkCnt;
/*
Format: First byte must be 0x02 (status check) or 0x28 (read
back block of 32 bit words). Next 6 bytes must be zero,
- followed by a single byte of 0x44+offset for portion to be
- read. Returned data is packed set of 32 bits words that were
- read.
+ followed by a single byte of MBOX_BASE+offset for portion to
+ be read. Returned data is packed set of 32 bits words that
+ were read.
*/
while (dlen) {
chunkCnt = 16;
if (chunkCnt > dlen) chunkCnt = dlen;
- memset(hdw->cmd_buffer,0,sizeof(hdw->cmd_buffer));
- hdw->cmd_buffer[0] = statusFl ? 0x02 : 0x28;
- hdw->cmd_buffer[7] = 0x44 + offs;
+ if (chunkCnt < 16) chunkCnt = 1;
+ hdw->cmd_buffer[0] =
+ ((chunkCnt == 1) ?
+ FX2CMD_MEM_READ_DWORD : FX2CMD_MEM_READ_64BYTES);
+ hdw->cmd_buffer[1] = 0;
+ hdw->cmd_buffer[2] = 0;
+ hdw->cmd_buffer[3] = 0;
+ hdw->cmd_buffer[4] = 0;
+ hdw->cmd_buffer[5] = ((offs>>16) & 0xffu);
+ hdw->cmd_buffer[6] = ((offs>>8) & 0xffu);
+ hdw->cmd_buffer[7] = (offs & 0xffu);
ret = pvr2_send_request(hdw,
hdw->cmd_buffer,8,
- hdw->cmd_buffer,chunkCnt * 4);
+ hdw->cmd_buffer,
+ (chunkCnt == 1 ? 4 : 16 * 4));
if (ret) return ret;
for (idx = 0; idx < chunkCnt; idx++) {
@@ -129,6 +146,8 @@ static int pvr2_encoder_cmd(void *ctxt,
u32 *argp)
{
unsigned int poll_count;
+ unsigned int try_count = 0;
+ int retry_flag;
int ret = 0;
unsigned int idx;
/* These sizes look to be limited by the FX2 firmware implementation */
@@ -140,14 +159,15 @@ static int pvr2_encoder_cmd(void *ctxt,
/*
The encoder seems to speak entirely using blocks 32 bit words.
- In ivtv driver terms, this is a mailbox which we populate with
- data and watch what the hardware does with it. The first word
- is a set of flags used to control the transaction, the second
- word is the command to execute, the third byte is zero (ivtv
- driver suggests that this is some kind of return value), and
- the fourth byte is a specified timeout (windows driver always
- uses 0x00060000 except for one case when it is zero). All
- successive words are the argument words for the command.
+ In ivtv driver terms, this is a mailbox at MBOX_BASE which we
+ populate with data and watch what the hardware does with it.
+ The first word is a set of flags used to control the
+ transaction, the second word is the command to execute, the
+ third byte is zero (ivtv driver suggests that this is some
+ kind of return value), and the fourth byte is a specified
+ timeout (windows driver always uses 0x00060000 except for one
+ case when it is zero). All successive words are the argument
+ words for the command.
First, write out the entire set of words, with the first word
being zero.
@@ -156,44 +176,42 @@ static int pvr2_encoder_cmd(void *ctxt,
IVTV_MBOX_DRIVER_DONE | IVTV_DRIVER_BUSY this time (which
probably means "go").
- Next, read back 16 words as status. Check the first word,
+ Next, read back the return count words. Check the first word,
which should have IVTV_MBOX_FIRMWARE_DONE set. If however
that bit is not set, then the command isn't done so repeat the
- read.
-
- Next, read back 32 words and compare with the original
- arugments. Hopefully they will match.
+ read until it is set.
Finally, write out just the first word again, but set it to
0x0 this time (which probably means "idle").
*/
- if (arg_cnt_send > (sizeof(wrData)/sizeof(wrData[0]))-4) {
+ if (arg_cnt_send > (ARRAY_SIZE(wrData) - 4)) {
pvr2_trace(
PVR2_TRACE_ERROR_LEGS,
"Failed to write cx23416 command"
" - too many input arguments"
- " (was given %u limit %u)",
- arg_cnt_send,
- (unsigned int)(sizeof(wrData)/sizeof(wrData[0])) - 4);
+ " (was given %u limit %lu)",
+ arg_cnt_send, (long unsigned) ARRAY_SIZE(wrData) - 4);
return -EINVAL;
}
- if (arg_cnt_recv > (sizeof(rdData)/sizeof(rdData[0]))-4) {
+ if (arg_cnt_recv > (ARRAY_SIZE(rdData) - 4)) {
pvr2_trace(
PVR2_TRACE_ERROR_LEGS,
"Failed to write cx23416 command"
" - too many return arguments"
- " (was given %u limit %u)",
- arg_cnt_recv,
- (unsigned int)(sizeof(rdData)/sizeof(rdData[0])) - 4);
+ " (was given %u limit %lu)",
+ arg_cnt_recv, (long unsigned) ARRAY_SIZE(rdData) - 4);
return -EINVAL;
}
LOCK_TAKE(hdw->ctl_lock); do {
+ retry_flag = 0;
+ try_count++;
+ ret = 0;
wrData[0] = 0;
wrData[1] = cmd;
wrData[2] = 0;
@@ -201,59 +219,74 @@ static int pvr2_encoder_cmd(void *ctxt,
for (idx = 0; idx < arg_cnt_send; idx++) {
wrData[idx+4] = argp[idx];
}
- for (; idx < (sizeof(wrData)/sizeof(wrData[0]))-4; idx++) {
+ for (; idx < ARRAY_SIZE(wrData) - 4; idx++) {
wrData[idx+4] = 0;
}
- ret = pvr2_encoder_write_words(hdw,wrData,idx);
+ ret = pvr2_encoder_write_words(hdw,MBOX_BASE,wrData,idx);
if (ret) break;
wrData[0] = IVTV_MBOX_DRIVER_DONE|IVTV_MBOX_DRIVER_BUSY;
- ret = pvr2_encoder_write_words(hdw,wrData,1);
+ ret = pvr2_encoder_write_words(hdw,MBOX_BASE,wrData,1);
if (ret) break;
poll_count = 0;
while (1) {
- if (poll_count < 10000000) poll_count++;
- ret = pvr2_encoder_read_words(hdw,!0,rdData,1);
- if (ret) break;
+ poll_count++;
+ ret = pvr2_encoder_read_words(hdw,MBOX_BASE,rdData,
+ arg_cnt_recv+4);
+ if (ret) {
+ break;
+ }
if (rdData[0] & IVTV_MBOX_FIRMWARE_DONE) {
break;
}
- if (poll_count == 100) {
+ if (rdData[0] && (poll_count < 1000)) continue;
+ if (!rdData[0]) {
+ retry_flag = !0;
pvr2_trace(
PVR2_TRACE_ERROR_LEGS,
- "***WARNING*** device's encoder"
- " appears to be stuck"
- " (status=0%08x)",rdData[0]);
+ "Encoder timed out waiting for us"
+ "; arranging to retry");
+ } else {
pvr2_trace(
PVR2_TRACE_ERROR_LEGS,
- "Encoder command: 0x%02x",cmd);
- for (idx = 4; idx < arg_cnt_send; idx++) {
- pvr2_trace(
- PVR2_TRACE_ERROR_LEGS,
- "Encoder arg%d: 0x%08x",
- idx-3,wrData[idx]);
- }
+ "***WARNING*** device's encoder"
+ " appears to be stuck"
+ " (status=0x%08x)",rdData[0]);
+ }
+ pvr2_trace(
+ PVR2_TRACE_ERROR_LEGS,
+ "Encoder command: 0x%02x",cmd);
+ for (idx = 4; idx < arg_cnt_send; idx++) {
pvr2_trace(
PVR2_TRACE_ERROR_LEGS,
- "Giving up waiting."
- " It is likely that"
- " this is a bad idea...");
- ret = -EBUSY;
- break;
+ "Encoder arg%d: 0x%08x",
+ idx-3,wrData[idx]);
}
+ ret = -EBUSY;
+ break;
+ }
+ if (retry_flag) {
+ if (try_count < 20) continue;
+ pvr2_trace(
+ PVR2_TRACE_ERROR_LEGS,
+ "Too many retries...");
+ ret = -EBUSY;
+ }
+ if (ret) {
+ pvr2_trace(
+ PVR2_TRACE_ERROR_LEGS,
+ "Giving up on command."
+ " It is likely that"
+ " this is a bad idea...");
+ break;
}
- if (ret) break;
wrData[0] = 0x7;
- ret = pvr2_encoder_read_words(
- hdw,0,rdData,
- sizeof(rdData)/sizeof(rdData[0]));
- if (ret) break;
for (idx = 0; idx < arg_cnt_recv; idx++) {
argp[idx] = rdData[idx+4];
}
wrData[0] = 0x0;
- ret = pvr2_encoder_write_words(hdw,wrData,1);
+ ret = pvr2_encoder_write_words(hdw,MBOX_BASE,wrData,1);
if (ret) break;
} while(0); LOCK_GIVE(hdw->ctl_lock);
@@ -269,13 +302,13 @@ static int pvr2_encoder_vcmd(struct pvr2_hdw *hdw, int cmd,
unsigned int idx;
u32 data[12];
- if (args > sizeof(data)/sizeof(data[0])) {
+ if (args > ARRAY_SIZE(data)) {
pvr2_trace(
PVR2_TRACE_ERROR_LEGS,
"Failed to write cx23416 command"
" - too many arguments"
- " (was given %u limit %u)",
- args,(unsigned int)(sizeof(data)/sizeof(data[0])));
+ " (was given %u limit %lu)",
+ args, (long unsigned) ARRAY_SIZE(data));
return -EINVAL;
}
@@ -288,6 +321,73 @@ static int pvr2_encoder_vcmd(struct pvr2_hdw *hdw, int cmd,
return pvr2_encoder_cmd(hdw,cmd,args,0,data);
}
+
+/* This implements some extra setup for the encoder that seems to be
+ specific to the PVR USB2 hardware. */
+static int pvr2_encoder_prep_config(struct pvr2_hdw *hdw)
+{
+ int ret = 0;
+ int encMisc3Arg = 0;
+
+#if 0
+ /* This inexplicable bit happens in the Hauppage windows
+ driver (for both 24xxx and 29xxx devices). However I
+ currently see no difference in behavior with or without
+ this stuff. Leave this here as a note of its existence,
+ but don't use it. */
+ LOCK_TAKE(hdw->ctl_lock); do {
+ u32 dat[1];
+ dat[0] = 0x80000640;
+ pvr2_encoder_write_words(hdw,0x01fe,dat,1);
+ pvr2_encoder_write_words(hdw,0x023e,dat,1);
+ } while(0); LOCK_GIVE(hdw->ctl_lock);
+#endif
+
+ /* Mike Isely <isely@pobox.com> 26-Jan-2006 The windows driver
+ sends the following list of ENC_MISC commands (for both
+ 24xxx and 29xxx devices). Meanings are not entirely clear,
+ however without the ENC_MISC(3,1) command then we risk
+ random perpetual video corruption whenever the video input
+ breaks up for a moment (like when switching channels). */
+
+
+#if 0
+ /* This ENC_MISC(5,0) command seems to hurt 29xxx sync
+ performance on channel changes, but is not a problem on
+ 24xxx devices. */
+ ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 5,0,0,0);
+#endif
+
+ /* This ENC_MISC(3,encMisc3Arg) command is critical - without
+ it there will eventually be video corruption. Also, the
+ 29xxx case is strange - the Windows driver is passing 1
+ regardless of device type but if we have 1 for 29xxx device
+ the video turns sluggish. */
+ switch (hdw->hdw_type) {
+ case PVR2_HDW_TYPE_24XXX: encMisc3Arg = 1; break;
+ case PVR2_HDW_TYPE_29XXX: encMisc3Arg = 0; break;
+ default: break;
+ }
+ ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 3,
+ encMisc3Arg,0,0);
+
+ ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 8,0,0,0);
+
+#if 0
+ /* This ENC_MISC(4,1) command is poisonous, so it is commented
+ out. But I'm leaving it here anyway to document its
+ existence in the Windows driver. The effect of this
+ command is that apps displaying the stream become sluggish
+ with stuttering video. */
+ ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 4,1,0,0);
+#endif
+
+ ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 0,3,0,0);
+ ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4,15,0,0,0);
+
+ return ret;
+}
+
int pvr2_encoder_configure(struct pvr2_hdw *hdw)
{
int ret;
@@ -302,6 +402,8 @@ int pvr2_encoder_configure(struct pvr2_hdw *hdw)
ret = 0;
+ ret |= pvr2_encoder_prep_config(hdw);
+
if (!ret) ret = pvr2_encoder_vcmd(
hdw,CX2341X_ENC_SET_NUM_VSYNC_LINES, 2,
0xf0, 0xf0);
@@ -360,15 +462,22 @@ int pvr2_encoder_start(struct pvr2_hdw *hdw)
pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000481);
pvr2_hdw_gpio_chg_out(hdw,0xffffffff,0x00000000);
- if (hdw->config == pvr2_config_vbi) {
+ pvr2_encoder_vcmd(hdw,CX2341X_ENC_MUTE_VIDEO,1,
+ hdw->input_val == PVR2_CVAL_INPUT_RADIO ? 1 : 0);
+
+ switch (hdw->config) {
+ case pvr2_config_vbi:
status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,
0x01,0x14);
- } else if (hdw->config == pvr2_config_mpeg) {
+ break;
+ case pvr2_config_mpeg:
status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,
0,0x13);
- } else {
+ break;
+ default: /* Unhandled cases for now */
status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,
0,0x13);
+ break;
}
if (!status) {
hdw->subsys_enabled_mask |= (1<<PVR2_SUBSYS_B_ENC_RUN);
@@ -383,15 +492,19 @@ int pvr2_encoder_stop(struct pvr2_hdw *hdw)
/* mask all interrupts */
pvr2_write_register(hdw, 0x0048, 0xffffffff);
- if (hdw->config == pvr2_config_vbi) {
+ switch (hdw->config) {
+ case pvr2_config_vbi:
status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,
0x01,0x01,0x14);
- } else if (hdw->config == pvr2_config_mpeg) {
+ break;
+ case pvr2_config_mpeg:
status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,
0x01,0,0x13);
- } else {
+ break;
+ default: /* Unhandled cases for now */
status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,
0x01,0,0x13);
+ break;
}
/* change some GPIO data */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-fx2-cmd.h b/drivers/media/video/pvrusb2/pvrusb2-fx2-cmd.h
new file mode 100644
index 000000000000..ffbc6d096108
--- /dev/null
+++ b/drivers/media/video/pvrusb2/pvrusb2-fx2-cmd.h
@@ -0,0 +1,62 @@
+/*
+ *
+ * $Id$
+ *
+ * Copyright (C) 2007 Michael Krufky <mkrufky@linuxtv.org>
+ *
+ * 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_FX2_CMD_H_
+#define _PVRUSB2_FX2_CMD_H_
+
+#define FX2CMD_MEM_WRITE_DWORD 0x01
+#define FX2CMD_MEM_READ_DWORD 0x02
+
+#define FX2CMD_MEM_READ_64BYTES 0x28
+
+#define FX2CMD_REG_WRITE 0x04
+#define FX2CMD_REG_READ 0x05
+#define FX2CMD_MEMSEL 0x06
+
+#define FX2CMD_I2C_WRITE 0x08
+#define FX2CMD_I2C_READ 0x09
+
+#define FX2CMD_GET_USB_SPEED 0x0b
+
+#define FX2CMD_STREAMING_ON 0x36
+#define FX2CMD_STREAMING_OFF 0x37
+
+#define FX2CMD_FWPOST1 0x52
+
+#define FX2CMD_POWER_OFF 0xdc
+#define FX2CMD_POWER_ON 0xde
+
+#define FX2CMD_DEEP_RESET 0xdd
+
+#define FX2CMD_GET_EEPROM_ADDR 0xeb
+#define FX2CMD_GET_IR_CODE 0xec
+
+#endif /* _PVRUSB2_FX2_CMD_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/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
index 34b08fbcc6ea..ce66ab8ff2d8 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
@@ -60,6 +60,7 @@ struct pvr2_decoder;
typedef int (*pvr2_ctlf_is_dirty)(struct pvr2_ctrl *);
typedef void (*pvr2_ctlf_clear_dirty)(struct pvr2_ctrl *);
+typedef int (*pvr2_ctlf_check_value)(struct pvr2_ctrl *,int);
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,
@@ -83,6 +84,7 @@ struct pvr2_ctl_info {
pvr2_ctlf_get_value get_min_value; /* Get minimum allowed value */
pvr2_ctlf_get_value get_max_value; /* Get maximum allowed value */
pvr2_ctlf_set_value set_value; /* Set its value */
+ pvr2_ctlf_check_value check_value; /* Check that value is valid */
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 */
@@ -135,17 +137,10 @@ struct pvr2_ctrl {
};
-struct pvr2_audio_stat {
- void *ctxt;
- void (*detach)(void *);
- int (*status)(void *);
-};
-
struct pvr2_decoder_ctrl {
void *ctxt;
void (*detach)(void *);
void (*enable)(void *,int);
- int (*tuned)(void *);
void (*force_reset)(void *);
};
@@ -212,7 +207,6 @@ 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 */
struct mutex ctl_lock_mutex;
@@ -258,9 +252,17 @@ struct pvr2_hdw {
/* Tuner / frequency control stuff */
unsigned int tuner_type;
int tuner_updated;
- unsigned int freqVal;
+ unsigned int freqValTelevision; /* Current freq for tv mode */
+ unsigned int freqValRadio; /* Current freq for radio mode */
+ unsigned int freqSlotTelevision; /* Current slot for tv mode */
+ unsigned int freqSlotRadio; /* Current slot for radio mode */
+ unsigned int freqSelector; /* 0=radio 1=television */
int freqDirty;
+ /* Current tuner info - this information is polled from the I2C bus */
+ struct v4l2_tuner tuner_signal_info;
+ int tuner_signal_stale;
+
/* Video standard handling */
v4l2_std_id std_mask_eeprom; // Hardware supported selections
v4l2_std_id std_mask_avail; // Which standards we may select from
@@ -281,20 +283,19 @@ struct pvr2_hdw {
int unit_number; /* ID for driver instance */
unsigned long serial_number; /* ID for hardware itself */
- /* Minor number used by v4l logic (yes, this is a hack, as there should
- be no v4l junk here). Probably a better way to do this. */
- int v4l_minor_number;
+ char bus_info[32]; /* Bus location info */
+
+ /* Minor numbers used by v4l logic (yes, this is a hack, as there
+ should be no v4l junk here). Probably a better way to do this. */
+ int v4l_minor_number_video;
+ int v4l_minor_number_vbi;
+ int v4l_minor_number_radio;
/* Location of eeprom or a negative number if none */
int eeprom_addr;
enum pvr2_config config;
- /* Information about what audio signal we're hearing */
- int flag_stereo;
- int flag_bilingual;
- struct pvr2_audio_stat *audio_stat;
-
/* Control state needed for cx2341x module */
struct cx2341x_mpeg_params enc_cur_state;
struct cx2341x_mpeg_params enc_ctl_state;
@@ -327,6 +328,9 @@ struct pvr2_hdw {
unsigned int control_cnt;
};
+/* This function gets the current frequency */
+unsigned long pvr2_hdw_get_cur_freq(struct pvr2_hdw *);
+
#endif /* __PVRUSB2_HDW_INTERNAL_H */
/*
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
index d2004965187b..acf651e01f94 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
@@ -36,6 +36,10 @@
#include "pvrusb2-hdw-internal.h"
#include "pvrusb2-encoder.h"
#include "pvrusb2-debug.h"
+#include "pvrusb2-fx2-cmd.h"
+
+#define TV_MIN_FREQ 55250000L
+#define TV_MAX_FREQ 850000000L
struct usb_device_id pvr2_device_table[] = {
[PVR2_HDW_TYPE_29XXX] = { USB_DEVICE(0x2040, 0x2900) },
@@ -71,12 +75,10 @@ static const char *pvr2_client_29xxx[] = {
static struct pvr2_string_table pvr2_client_lists[] = {
[PVR2_HDW_TYPE_29XXX] = {
- pvr2_client_29xxx,
- sizeof(pvr2_client_29xxx)/sizeof(pvr2_client_29xxx[0]),
+ pvr2_client_29xxx, ARRAY_SIZE(pvr2_client_29xxx)
},
[PVR2_HDW_TYPE_24XXX] = {
- pvr2_client_24xxx,
- sizeof(pvr2_client_24xxx)/sizeof(pvr2_client_24xxx[0]),
+ pvr2_client_24xxx, ARRAY_SIZE(pvr2_client_24xxx)
},
};
@@ -160,9 +162,6 @@ static const struct pvr2_mpeg_ids mpeg_ids[] = {
.strid = "video_gop_closure",
.id = V4L2_CID_MPEG_VIDEO_GOP_CLOSURE,
},{
- .strid = "video_pulldown",
- .id = V4L2_CID_MPEG_VIDEO_PULLDOWN,
- },{
.strid = "video_bitrate_mode",
.id = V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
},{
@@ -212,7 +211,7 @@ static const struct pvr2_mpeg_ids mpeg_ids[] = {
.id = V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM,
}
};
-#define MPEGDEF_COUNT (sizeof(mpeg_ids)/sizeof(mpeg_ids[0]))
+#define MPEGDEF_COUNT ARRAY_SIZE(mpeg_ids)
static const char *control_values_srate[] = {
@@ -255,10 +254,10 @@ static const char *control_values_subsystem[] = {
[PVR2_SUBSYS_B_ENC_RUN] = "enc_run",
};
+static void pvr2_hdw_set_cur_freq(struct pvr2_hdw *,unsigned long);
static int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl);
static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw);
static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw);
-static unsigned int pvr2_hdw_get_signal_status_internal(struct pvr2_hdw *hdw);
static void pvr2_hdw_internal_find_stdenum(struct pvr2_hdw *hdw);
static void pvr2_hdw_internal_set_std_avail(struct pvr2_hdw *hdw);
static void pvr2_hdw_render_useless_unlocked(struct pvr2_hdw *hdw);
@@ -272,8 +271,6 @@ static int pvr2_send_request_ex(struct pvr2_hdw *hdw,
unsigned int timeout,int probe_fl,
void *write_data,unsigned int write_len,
void *read_data,unsigned int read_len);
-static int pvr2_write_u16(struct pvr2_hdw *hdw, u16 data, int res);
-static int pvr2_write_u8(struct pvr2_hdw *hdw, u8 data, int res);
static int ctrl_channelfreq_get(struct pvr2_ctrl *cptr,int *vp)
{
@@ -289,8 +286,21 @@ static int ctrl_channelfreq_get(struct pvr2_ctrl *cptr,int *vp)
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;
+ unsigned int slotId = hdw->freqProgSlot;
+ if ((slotId > 0) && (slotId <= FREQTABLE_SIZE)) {
+ hdw->freqTable[slotId-1] = v;
+ /* Handle side effects correctly - if we're tuned to this
+ slot, then forgot the slot id relation since the stored
+ frequency has been changed. */
+ if (hdw->freqSelector) {
+ if (hdw->freqSlotRadio == slotId) {
+ hdw->freqSlotRadio = 0;
+ }
+ } else {
+ if (hdw->freqSlotTelevision == slotId) {
+ hdw->freqSlotTelevision = 0;
+ }
+ }
}
return 0;
}
@@ -312,28 +322,32 @@ static int ctrl_channelprog_set(struct pvr2_ctrl *cptr,int m,int v)
static int ctrl_channel_get(struct pvr2_ctrl *cptr,int *vp)
{
- *vp = cptr->hdw->freqSlot;
+ struct pvr2_hdw *hdw = cptr->hdw;
+ *vp = hdw->freqSelector ? hdw->freqSlotRadio : hdw->freqSlotTelevision;
return 0;
}
-static int ctrl_channel_set(struct pvr2_ctrl *cptr,int m,int v)
+static int ctrl_channel_set(struct pvr2_ctrl *cptr,int m,int slotId)
{
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;
+ if ((slotId < 0) || (slotId > FREQTABLE_SIZE)) return 0;
+ if (slotId > 0) {
+ freq = hdw->freqTable[slotId-1];
+ if (!freq) return 0;
+ pvr2_hdw_set_cur_freq(hdw,freq);
+ }
+ if (hdw->freqSelector) {
+ hdw->freqSlotRadio = slotId;
+ } else {
+ hdw->freqSlotTelevision = slotId;
}
return 0;
}
static int ctrl_freq_get(struct pvr2_ctrl *cptr,int *vp)
{
- *vp = cptr->hdw->freqVal;
+ *vp = pvr2_hdw_get_cur_freq(cptr->hdw);
return 0;
}
@@ -349,10 +363,7 @@ static void ctrl_freq_clear_dirty(struct pvr2_ctrl *cptr)
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;
+ pvr2_hdw_set_cur_freq(cptr->hdw,v);
return 0;
}
@@ -378,6 +389,89 @@ static int ctrl_vres_min_get(struct pvr2_ctrl *cptr,int *vp)
return 0;
}
+static int ctrl_get_input(struct pvr2_ctrl *cptr,int *vp)
+{
+ *vp = cptr->hdw->input_val;
+ return 0;
+}
+
+static int ctrl_set_input(struct pvr2_ctrl *cptr,int m,int v)
+{
+ struct pvr2_hdw *hdw = cptr->hdw;
+
+ if (hdw->input_val != v) {
+ hdw->input_val = v;
+ hdw->input_dirty = !0;
+ }
+
+ /* Handle side effects - if we switch to a mode that needs the RF
+ tuner, then select the right frequency choice as well and mark
+ it dirty. */
+ if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
+ hdw->freqSelector = 0;
+ hdw->freqDirty = !0;
+ } else if (hdw->input_val == PVR2_CVAL_INPUT_TV) {
+ hdw->freqSelector = 1;
+ hdw->freqDirty = !0;
+ }
+ return 0;
+}
+
+static int ctrl_isdirty_input(struct pvr2_ctrl *cptr)
+{
+ return cptr->hdw->input_dirty != 0;
+}
+
+static void ctrl_cleardirty_input(struct pvr2_ctrl *cptr)
+{
+ cptr->hdw->input_dirty = 0;
+}
+
+
+static int ctrl_freq_max_get(struct pvr2_ctrl *cptr, int *vp)
+{
+ unsigned long fv;
+ struct pvr2_hdw *hdw = cptr->hdw;
+ if (hdw->tuner_signal_stale) {
+ pvr2_i2c_core_status_poll(hdw);
+ }
+ fv = hdw->tuner_signal_info.rangehigh;
+ if (!fv) {
+ /* Safety fallback */
+ *vp = TV_MAX_FREQ;
+ return 0;
+ }
+ if (hdw->tuner_signal_info.capability & V4L2_TUNER_CAP_LOW) {
+ fv = (fv * 125) / 2;
+ } else {
+ fv = fv * 62500;
+ }
+ *vp = fv;
+ return 0;
+}
+
+static int ctrl_freq_min_get(struct pvr2_ctrl *cptr, int *vp)
+{
+ unsigned long fv;
+ struct pvr2_hdw *hdw = cptr->hdw;
+ if (hdw->tuner_signal_stale) {
+ pvr2_i2c_core_status_poll(hdw);
+ }
+ fv = hdw->tuner_signal_info.rangelow;
+ if (!fv) {
+ /* Safety fallback */
+ *vp = TV_MIN_FREQ;
+ return 0;
+ }
+ if (hdw->tuner_signal_info.capability & V4L2_TUNER_CAP_LOW) {
+ fv = (fv * 125) / 2;
+ } else {
+ fv = fv * 62500;
+ }
+ *vp = fv;
+ return 0;
+}
+
static int ctrl_cx2341x_is_dirty(struct pvr2_ctrl *cptr)
{
return cptr->hdw->enc_stale != 0;
@@ -534,8 +628,32 @@ static void ctrl_stdcur_clear_dirty(struct pvr2_ctrl *cptr)
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);
+ struct pvr2_hdw *hdw = cptr->hdw;
+ pvr2_i2c_core_status_poll(hdw);
+ *vp = hdw->tuner_signal_info.signal;
+ return 0;
+}
+
+static int ctrl_audio_modes_present_get(struct pvr2_ctrl *cptr,int *vp)
+{
+ int val = 0;
+ unsigned int subchan;
+ struct pvr2_hdw *hdw = cptr->hdw;
+ pvr2_i2c_core_status_poll(hdw);
+ subchan = hdw->tuner_signal_info.rxsubchans;
+ if (subchan & V4L2_TUNER_SUB_MONO) {
+ val |= (1 << V4L2_TUNER_MODE_MONO);
+ }
+ if (subchan & V4L2_TUNER_SUB_STEREO) {
+ val |= (1 << V4L2_TUNER_MODE_STEREO);
+ }
+ if (subchan & V4L2_TUNER_SUB_LANG1) {
+ val |= (1 << V4L2_TUNER_MODE_LANG1);
+ }
+ if (subchan & V4L2_TUNER_SUB_LANG2) {
+ val |= (1 << V4L2_TUNER_MODE_LANG2);
+ }
+ *vp = val;
return 0;
}
@@ -604,7 +722,7 @@ static void ctrl_stdenumcur_clear_dirty(struct pvr2_ctrl *cptr)
#define DEFENUM(tab) \
.type = pvr2_ctl_enum, \
- .def.type_enum.count = (sizeof(tab)/sizeof((tab)[0])), \
+ .def.type_enum.count = ARRAY_SIZE(tab), \
.def.type_enum.value_names = tab
#define DEFBOOL \
@@ -641,15 +759,11 @@ VCREATE_FUNCS(balance)
VCREATE_FUNCS(bass)
VCREATE_FUNCS(treble)
VCREATE_FUNCS(mute)
-VCREATE_FUNCS(input)
VCREATE_FUNCS(audiomode)
VCREATE_FUNCS(res_hor)
VCREATE_FUNCS(res_ver)
VCREATE_FUNCS(srate)
-#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[] = {
{
@@ -684,7 +798,7 @@ static const struct pvr2_ctl_info control_defs[] = {
.v4l_id = V4L2_CID_AUDIO_VOLUME,
.desc = "Volume",
.name = "volume",
- .default_value = 65535,
+ .default_value = 62000,
DEFREF(volume),
DEFINT(0,65535),
},{
@@ -758,12 +872,16 @@ static const struct pvr2_ctl_info control_defs[] = {
.desc = "Tuner Frequency (Hz)",
.name = "frequency",
.internal_id = PVR2_CID_FREQUENCY,
- .default_value = 175250000L,
+ .default_value = 0,
.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),
+ DEFINT(0,0),
+ /* Hook in check for input value (tv/radio) and adjust
+ max/min values accordingly */
+ .get_max_value = ctrl_freq_max_get,
+ .get_min_value = ctrl_freq_min_get,
},{
.desc = "Channel",
.name = "channel",
@@ -775,7 +893,11 @@ static const struct pvr2_ctl_info control_defs[] = {
.name = "freq_table_value",
.set_value = ctrl_channelfreq_set,
.get_value = ctrl_channelfreq_get,
- DEFINT(MIN_FREQ,MAX_FREQ),
+ DEFINT(0,0),
+ /* Hook in check for input value (tv/radio) and adjust
+ max/min values accordingly */
+ .get_max_value = ctrl_freq_max_get,
+ .get_min_value = ctrl_freq_min_get,
},{
.desc = "Channel Program ID",
.name = "freq_table_channel",
@@ -796,7 +918,20 @@ static const struct pvr2_ctl_info control_defs[] = {
.desc = "Signal Present",
.name = "signal_present",
.get_value = ctrl_signal_get,
- DEFBOOL,
+ DEFINT(0,65535),
+ },{
+ .desc = "Audio Modes Present",
+ .name = "audio_modes_present",
+ .get_value = ctrl_audio_modes_present_get,
+ /* For this type we "borrow" the V4L2_TUNER_MODE enum from
+ v4l. Nothing outside of this module cares about this,
+ but I reuse it in order to also reuse the
+ control_values_audiomode string table. */
+ DEFMASK(((1 << V4L2_TUNER_MODE_MONO)|
+ (1 << V4L2_TUNER_MODE_STEREO)|
+ (1 << V4L2_TUNER_MODE_LANG1)|
+ (1 << V4L2_TUNER_MODE_LANG2)),
+ control_values_audiomode),
},{
.desc = "Video Standards Available Mask",
.name = "video_standard_mask_available",
@@ -846,7 +981,7 @@ static const struct pvr2_ctl_info control_defs[] = {
}
};
-#define CTRLDEF_COUNT (sizeof(control_defs)/sizeof(control_defs[0]))
+#define CTRLDEF_COUNT ARRAY_SIZE(control_defs)
const char *pvr2_config_get_name(enum pvr2_config cfg)
@@ -855,7 +990,8 @@ const char *pvr2_config_get_name(enum pvr2_config cfg)
case pvr2_config_empty: return "empty";
case pvr2_config_mpeg: return "mpeg";
case pvr2_config_vbi: return "vbi";
- case pvr2_config_radio: return "radio";
+ case pvr2_config_pcm: return "pcm";
+ case pvr2_config_rawvideo: return "raw video";
}
return "<unknown>";
}
@@ -872,6 +1008,47 @@ unsigned long pvr2_hdw_get_sn(struct pvr2_hdw *hdw)
return hdw->serial_number;
}
+
+const char *pvr2_hdw_get_bus_info(struct pvr2_hdw *hdw)
+{
+ return hdw->bus_info;
+}
+
+
+unsigned long pvr2_hdw_get_cur_freq(struct pvr2_hdw *hdw)
+{
+ return hdw->freqSelector ? hdw->freqValTelevision : hdw->freqValRadio;
+}
+
+/* Set the currently tuned frequency and account for all possible
+ driver-core side effects of this action. */
+void pvr2_hdw_set_cur_freq(struct pvr2_hdw *hdw,unsigned long val)
+{
+ if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
+ if (hdw->freqSelector) {
+ /* Swing over to radio frequency selection */
+ hdw->freqSelector = 0;
+ hdw->freqDirty = !0;
+ }
+ if (hdw->freqValRadio != val) {
+ hdw->freqValRadio = val;
+ hdw->freqSlotRadio = 0;
+ hdw->freqDirty = !0;
+ }
+ } else {
+ if (!(hdw->freqSelector)) {
+ /* Swing over to television frequency selection */
+ hdw->freqSelector = 1;
+ hdw->freqDirty = !0;
+ }
+ if (hdw->freqValTelevision != val) {
+ hdw->freqValTelevision = val;
+ hdw->freqSlotTelevision = 0;
+ hdw->freqDirty = !0;
+ }
+ }
+}
+
int pvr2_hdw_get_unit_number(struct pvr2_hdw *hdw)
{
return hdw->unit_number;
@@ -960,12 +1137,10 @@ static int pvr2_upload_firmware1(struct pvr2_hdw *hdw)
};
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]),
+ fw_files_29xxx, ARRAY_SIZE(fw_files_29xxx)
},
[PVR2_HDW_TYPE_24XXX] = {
- fw_files_24xxx,
- sizeof(fw_files_24xxx)/sizeof(fw_files_24xxx[0]),
+ fw_files_24xxx, ARRAY_SIZE(fw_files_24xxx)
},
};
hdw->fw1_state = FW1_STATE_FAILED; // default result
@@ -1041,7 +1216,7 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
{
const struct firmware *fw_entry = NULL;
void *fw_ptr;
- unsigned int pipe, fw_len, fw_done;
+ unsigned int pipe, fw_len, fw_done, bcnt, icnt;
int actual_length;
int ret = 0;
int fwidx;
@@ -1052,8 +1227,7 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
trace_firmware("pvr2_upload_firmware2");
ret = pvr2_locate_firmware(hdw,&fw_entry,"encoder",
- sizeof(fw_files)/sizeof(fw_files[0]),
- fw_files);
+ ARRAY_SIZE(fw_files), fw_files);
if (ret < 0) return ret;
fwidx = ret;
ret = 0;
@@ -1079,8 +1253,13 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
ret |= pvr2_write_register(hdw, 0xaa04, 0x00057810); /*unknown*/
ret |= pvr2_write_register(hdw, 0xaa10, 0x00148500); /*unknown*/
ret |= pvr2_write_register(hdw, 0xaa18, 0x00840000); /*unknown*/
- ret |= pvr2_write_u8(hdw, 0x52, 0);
- ret |= pvr2_write_u16(hdw, 0x0600, 0);
+ LOCK_TAKE(hdw->ctl_lock); do {
+ hdw->cmd_buffer[0] = FX2CMD_FWPOST1;
+ ret |= pvr2_send_request(hdw,hdw->cmd_buffer,1,NULL,0);
+ hdw->cmd_buffer[0] = FX2CMD_MEMSEL;
+ hdw->cmd_buffer[1] = 0;
+ ret |= pvr2_send_request(hdw,hdw->cmd_buffer,2,NULL,0);
+ } while (0); LOCK_GIVE(hdw->ctl_lock);
if (ret) {
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
@@ -1093,11 +1272,11 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
fw_len = fw_entry->size;
- if (fw_len % FIRMWARE_CHUNK_SIZE) {
+ if (fw_len % sizeof(u32)) {
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
"size of %s firmware"
- " must be a multiple of 8192B",
- fw_files[fwidx]);
+ " must be a multiple of %zu bytes",
+ fw_files[fwidx],sizeof(u32));
release_firmware(fw_entry);
return -1;
}
@@ -1112,18 +1291,21 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
pipe = usb_sndbulkpipe(hdw->usb_dev, PVR2_FIRMWARE_ENDPOINT);
- for (fw_done = 0 ; (fw_done < fw_len) && !ret ;
- fw_done += FIRMWARE_CHUNK_SIZE ) {
- int i;
- memcpy(fw_ptr, fw_entry->data + fw_done, FIRMWARE_CHUNK_SIZE);
- /* Usbsnoop log shows that we must swap bytes... */
- for (i = 0; i < FIRMWARE_CHUNK_SIZE/4 ; i++)
- ((u32 *)fw_ptr)[i] = ___swab32(((u32 *)fw_ptr)[i]);
-
- ret |= usb_bulk_msg(hdw->usb_dev, pipe, fw_ptr,
- FIRMWARE_CHUNK_SIZE,
+ fw_done = 0;
+ for (fw_done = 0; fw_done < fw_len;) {
+ bcnt = fw_len - fw_done;
+ if (bcnt > FIRMWARE_CHUNK_SIZE) bcnt = FIRMWARE_CHUNK_SIZE;
+ memcpy(fw_ptr, fw_entry->data + fw_done, bcnt);
+ /* Usbsnoop log shows that we must swap bytes... */
+ for (icnt = 0; icnt < bcnt/4 ; icnt++)
+ ((u32 *)fw_ptr)[icnt] =
+ ___swab32(((u32 *)fw_ptr)[icnt]);
+
+ ret |= usb_bulk_msg(hdw->usb_dev, pipe, fw_ptr,bcnt,
&actual_length, HZ);
- ret |= (actual_length != FIRMWARE_CHUNK_SIZE);
+ ret |= (actual_length != bcnt);
+ if (ret) break;
+ fw_done += bcnt;
}
trace_firmware("upload of %s : %i / %i ",
@@ -1142,7 +1324,11 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
ret |= pvr2_write_register(hdw, 0x9054, 0xffffffff); /*reset hw blocks*/
ret |= pvr2_write_register(hdw, 0x9058, 0xffffffe8); /*VPU ctrl*/
- ret |= pvr2_write_u16(hdw, 0x0600, 0);
+ LOCK_TAKE(hdw->ctl_lock); do {
+ hdw->cmd_buffer[0] = FX2CMD_MEMSEL;
+ hdw->cmd_buffer[1] = 0;
+ ret |= pvr2_send_request(hdw,hdw->cmd_buffer,2,NULL,0);
+ } while (0); LOCK_GIVE(hdw->ctl_lock);
if (ret) {
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
@@ -1479,7 +1665,7 @@ static int pvr2_hdw_check_firmware(struct pvr2_hdw *hdw)
firmware needs be loaded. */
int result;
LOCK_TAKE(hdw->ctl_lock); do {
- hdw->cmd_buffer[0] = 0xeb;
+ hdw->cmd_buffer[0] = FX2CMD_GET_EEPROM_ADDR;
result = pvr2_send_request_ex(hdw,HZ*1,!0,
hdw->cmd_buffer,1,
hdw->cmd_buffer,1);
@@ -1611,6 +1797,16 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
cptr->info->set_value(cptr,~0,cptr->info->default_value);
}
+ /* Set up special default values for the television and radio
+ frequencies here. It's not really important what these defaults
+ are, but I set them to something usable in the Chicago area just
+ to make driver testing a little easier. */
+
+ /* US Broadcast channel 7 (175.25 MHz) */
+ hdw->freqValTelevision = 175250000L;
+ /* 104.3 MHz, a usable FM station for my area */
+ hdw->freqValRadio = 104300000L;
+
// 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).
@@ -1750,26 +1946,24 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
struct pvr2_ctl_info *ciptr;
hdw_type = devid - pvr2_device_table;
- if (hdw_type >=
- sizeof(pvr2_device_names)/sizeof(pvr2_device_names[0])) {
+ if (hdw_type >= ARRAY_SIZE(pvr2_device_names)) {
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
"Bogus device type of %u reported",hdw_type);
return NULL;
}
- hdw = kmalloc(sizeof(*hdw),GFP_KERNEL);
+ hdw = kzalloc(sizeof(*hdw),GFP_KERNEL);
pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_create: hdw=%p, type \"%s\"",
hdw,pvr2_device_names[hdw_type]);
if (!hdw) goto fail;
- memset(hdw,0,sizeof(*hdw));
+ hdw->tuner_signal_stale = !0;
cx2341x_fill_defaults(&hdw->enc_ctl_state);
hdw->control_cnt = CTRLDEF_COUNT;
hdw->control_cnt += MPEGDEF_COUNT;
- hdw->controls = kmalloc(sizeof(struct pvr2_ctrl) * hdw->control_cnt,
+ hdw->controls = kzalloc(sizeof(struct pvr2_ctrl) * hdw->control_cnt,
GFP_KERNEL);
if (!hdw->controls) goto fail;
- memset(hdw->controls,0,sizeof(struct pvr2_ctrl) * hdw->control_cnt);
hdw->hdw_type = hdw_type;
for (idx = 0; idx < hdw->control_cnt; idx++) {
cptr = hdw->controls + idx;
@@ -1783,11 +1977,9 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
cptr->info = control_defs+idx;
}
/* Define and configure additional controls from cx2341x module. */
- hdw->mpeg_ctrl_info = kmalloc(
+ hdw->mpeg_ctrl_info = kzalloc(
sizeof(*(hdw->mpeg_ctrl_info)) * MPEGDEF_COUNT, GFP_KERNEL);
if (!hdw->mpeg_ctrl_info) goto fail;
- memset(hdw->mpeg_ctrl_info,0,
- sizeof(*(hdw->mpeg_ctrl_info)) * MPEGDEF_COUNT);
for (idx = 0; idx < MPEGDEF_COUNT; idx++) {
cptr = hdw->controls + idx + CTRLDEF_COUNT;
ciptr = &(hdw->mpeg_ctrl_info[idx].info);
@@ -1872,7 +2064,9 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
hdw->eeprom_addr = -1;
hdw->unit_number = -1;
- hdw->v4l_minor_number = -1;
+ hdw->v4l_minor_number_video = -1;
+ hdw->v4l_minor_number_vbi = -1;
+ hdw->v4l_minor_number_radio = -1;
hdw->ctl_write_buffer = kmalloc(PVR2_CTL_BUFFSIZE,GFP_KERNEL);
if (!hdw->ctl_write_buffer) goto fail;
hdw->ctl_read_buffer = kmalloc(PVR2_CTL_BUFFSIZE,GFP_KERNEL);
@@ -1918,6 +2112,11 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
hdw->usb_intf = intf;
hdw->usb_dev = interface_to_usbdev(intf);
+ scnprintf(hdw->bus_info,sizeof(hdw->bus_info),
+ "usb %s address %d",
+ hdw->usb_dev->dev.bus_id,
+ hdw->usb_dev->devnum);
+
ifnum = hdw->usb_intf->cur_altsetting->desc.bInterfaceNumber;
usb_set_interface(hdw->usb_dev,ifnum,0);
@@ -1929,10 +2128,10 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
if (hdw) {
usb_free_urb(hdw->ctl_read_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);
- if (hdw->mpeg_ctrl_info) kfree(hdw->mpeg_ctrl_info);
+ kfree(hdw->ctl_read_buffer);
+ kfree(hdw->ctl_write_buffer);
+ kfree(hdw->controls);
+ kfree(hdw->mpeg_ctrl_info);
kfree(hdw);
}
return NULL;
@@ -1982,9 +2181,6 @@ void pvr2_hdw_destroy(struct pvr2_hdw *hdw)
pvr2_stream_destroy(hdw->vid_stream);
hdw->vid_stream = NULL;
}
- if (hdw->audio_stat) {
- hdw->audio_stat->detach(hdw->audio_stat->ctxt);
- }
if (hdw->decoder_ctrl) {
hdw->decoder_ctrl->detach(hdw->decoder_ctrl->ctxt);
}
@@ -1997,10 +2193,10 @@ void pvr2_hdw_destroy(struct pvr2_hdw *hdw)
unit_pointers[hdw->unit_number] = NULL;
}
} while (0); up(&pvr2_unit_sem);
- if (hdw->controls) kfree(hdw->controls);
- if (hdw->mpeg_ctrl_info) kfree(hdw->mpeg_ctrl_info);
- if (hdw->std_defs) kfree(hdw->std_defs);
- if (hdw->std_enum_names) kfree(hdw->std_enum_names);
+ kfree(hdw->controls);
+ kfree(hdw->mpeg_ctrl_info);
+ kfree(hdw->std_defs);
+ kfree(hdw->std_enum_names);
kfree(hdw);
}
@@ -2210,10 +2406,9 @@ static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw)
cptr = hdw->controls + idx;
if (cptr->info->is_dirty == 0) continue;
if (!cptr->info->is_dirty(cptr)) continue;
- if (!commit_flag) {
- commit_flag = !0;
- }
+ commit_flag = !0;
+ if (!(pvrusb2_debug & PVR2_TRACE_CTL)) continue;
bcnt = scnprintf(buf,sizeof(buf),"\"%s\" <-- ",
cptr->info->name);
value = 0;
@@ -2263,6 +2458,13 @@ static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw)
stale_subsys_mask |= (1<<PVR2_SUBSYS_B_ENC_CFG);
}
+ if (hdw->input_dirty) {
+ /* pk: If input changes to or from radio, then the encoder
+ needs to be restarted (for ENC_MUTE_VIDEO to work) */
+ stale_subsys_mask |= (1<<PVR2_SUBSYS_B_ENC_RUN);
+ }
+
+
if (hdw->srate_dirty) {
/* Write new sample rate into control structure since
* the master copy is stale. We must track srate
@@ -2343,39 +2545,11 @@ const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *hdw)
}
-/* Return bit mask indicating signal status */
-static unsigned int pvr2_hdw_get_signal_status_internal(struct pvr2_hdw *hdw)
-{
- unsigned int msk = 0;
- switch (hdw->input_val) {
- case PVR2_CVAL_INPUT_TV:
- case PVR2_CVAL_INPUT_RADIO:
- if (hdw->decoder_ctrl &&
- hdw->decoder_ctrl->tuned(hdw->decoder_ctrl->ctxt)) {
- msk |= PVR2_SIGNAL_OK;
- if (hdw->audio_stat &&
- hdw->audio_stat->status(hdw->audio_stat->ctxt)) {
- if (hdw->flag_stereo) {
- msk |= PVR2_SIGNAL_STEREO;
- }
- if (hdw->flag_bilingual) {
- msk |= PVR2_SIGNAL_SAP;
- }
- }
- }
- break;
- default:
- msk |= PVR2_SIGNAL_OK | PVR2_SIGNAL_STEREO;
- }
- return msk;
-}
-
-
int pvr2_hdw_is_hsm(struct pvr2_hdw *hdw)
{
int result;
LOCK_TAKE(hdw->ctl_lock); do {
- hdw->cmd_buffer[0] = 0x0b;
+ hdw->cmd_buffer[0] = FX2CMD_GET_USB_SPEED;
result = pvr2_send_request(hdw,
hdw->cmd_buffer,1,
hdw->cmd_buffer,1);
@@ -2386,14 +2560,25 @@ int pvr2_hdw_is_hsm(struct pvr2_hdw *hdw)
}
-/* Return bit mask indicating signal status */
-unsigned int pvr2_hdw_get_signal_status(struct pvr2_hdw *hdw)
+/* Execute poll of tuner status */
+void pvr2_hdw_execute_tuner_poll(struct pvr2_hdw *hdw)
+{
+ LOCK_TAKE(hdw->big_lock); do {
+ pvr2_i2c_core_status_poll(hdw);
+ } while (0); LOCK_GIVE(hdw->big_lock);
+}
+
+
+/* Return information about the tuner */
+int pvr2_hdw_get_tuner_status(struct pvr2_hdw *hdw,struct v4l2_tuner *vtp)
{
- unsigned int msk = 0;
LOCK_TAKE(hdw->big_lock); do {
- msk = pvr2_hdw_get_signal_status_internal(hdw);
+ if (hdw->tuner_signal_stale) {
+ pvr2_i2c_core_status_poll(hdw);
+ }
+ memcpy(vtp,&hdw->tuner_signal_info,sizeof(struct v4l2_tuner));
} while (0); LOCK_GIVE(hdw->big_lock);
- return msk;
+ return 0;
}
@@ -2442,14 +2627,12 @@ void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *hdw, int enable_flag)
pvr2_trace(PVR2_TRACE_FIRMWARE,
"Preparing to suck out CPU firmware");
hdw->fw_size = 0x2000;
- hdw->fw_buffer = kmalloc(hdw->fw_size,GFP_KERNEL);
+ hdw->fw_buffer = kzalloc(hdw->fw_size,GFP_KERNEL);
if (!hdw->fw_buffer) {
hdw->fw_size = 0;
break;
}
- memset(hdw->fw_buffer,0,hdw->fw_size);
-
/* We have to hold the CPU during firmware upload. */
pvr2_hdw_cpureset_assert(hdw,1);
@@ -2513,16 +2696,28 @@ int pvr2_hdw_cpufw_get(struct pvr2_hdw *hdw,unsigned int offs,
}
-int pvr2_hdw_v4l_get_minor_number(struct pvr2_hdw *hdw)
+int pvr2_hdw_v4l_get_minor_number(struct pvr2_hdw *hdw,
+ enum pvr2_v4l_type index)
{
- return hdw->v4l_minor_number;
+ switch (index) {
+ case pvr2_v4l_type_video: return hdw->v4l_minor_number_video;
+ case pvr2_v4l_type_vbi: return hdw->v4l_minor_number_vbi;
+ case pvr2_v4l_type_radio: return hdw->v4l_minor_number_radio;
+ default: return -1;
+ }
}
-/* Store the v4l minor device number */
-void pvr2_hdw_v4l_store_minor_number(struct pvr2_hdw *hdw,int v)
+/* Store a v4l minor device number */
+void pvr2_hdw_v4l_store_minor_number(struct pvr2_hdw *hdw,
+ enum pvr2_v4l_type index,int v)
{
- hdw->v4l_minor_number = v;
+ switch (index) {
+ case pvr2_v4l_type_video: hdw->v4l_minor_number_video = v;
+ case pvr2_v4l_type_vbi: hdw->v4l_minor_number_vbi = v;
+ case pvr2_v4l_type_radio: hdw->v4l_minor_number_radio = v;
+ default: break;
+ }
}
@@ -2804,7 +2999,7 @@ int pvr2_write_register(struct pvr2_hdw *hdw, u16 reg, u32 data)
LOCK_TAKE(hdw->ctl_lock);
- hdw->cmd_buffer[0] = 0x04; /* write register prefix */
+ hdw->cmd_buffer[0] = FX2CMD_REG_WRITE; /* write register prefix */
PVR2_DECOMPOSE_LE(hdw->cmd_buffer,1,data);
hdw->cmd_buffer[5] = 0;
hdw->cmd_buffer[6] = (reg >> 8) & 0xff;
@@ -2825,7 +3020,7 @@ static int pvr2_read_register(struct pvr2_hdw *hdw, u16 reg, u32 *data)
LOCK_TAKE(hdw->ctl_lock);
- hdw->cmd_buffer[0] = 0x05; /* read register prefix */
+ hdw->cmd_buffer[0] = FX2CMD_REG_READ; /* read register prefix */
hdw->cmd_buffer[1] = 0;
hdw->cmd_buffer[2] = 0;
hdw->cmd_buffer[3] = 0;
@@ -2843,39 +3038,6 @@ static int pvr2_read_register(struct pvr2_hdw *hdw, u16 reg, u32 *data)
}
-static int pvr2_write_u16(struct pvr2_hdw *hdw, u16 data, int res)
-{
- int ret;
-
- LOCK_TAKE(hdw->ctl_lock);
-
- hdw->cmd_buffer[0] = (data >> 8) & 0xff;
- hdw->cmd_buffer[1] = data & 0xff;
-
- ret = pvr2_send_request(hdw, hdw->cmd_buffer, 2, hdw->cmd_buffer, res);
-
- LOCK_GIVE(hdw->ctl_lock);
-
- return ret;
-}
-
-
-static int pvr2_write_u8(struct pvr2_hdw *hdw, u8 data, int res)
-{
- int ret;
-
- LOCK_TAKE(hdw->ctl_lock);
-
- hdw->cmd_buffer[0] = data;
-
- ret = pvr2_send_request(hdw, hdw->cmd_buffer, 1, hdw->cmd_buffer, res);
-
- LOCK_GIVE(hdw->ctl_lock);
-
- return ret;
-}
-
-
static void pvr2_hdw_render_useless_unlocked(struct pvr2_hdw *hdw)
{
if (!hdw->flag_ok) return;
@@ -2949,7 +3111,7 @@ int pvr2_hdw_cmd_deep_reset(struct pvr2_hdw *hdw)
LOCK_TAKE(hdw->ctl_lock); do {
pvr2_trace(PVR2_TRACE_INIT,"Requesting uproc hard reset");
hdw->flag_ok = !0;
- hdw->cmd_buffer[0] = 0xdd;
+ hdw->cmd_buffer[0] = FX2CMD_DEEP_RESET;
status = pvr2_send_request(hdw,hdw->cmd_buffer,1,NULL,0);
} while (0); LOCK_GIVE(hdw->ctl_lock);
return status;
@@ -2961,7 +3123,7 @@ int pvr2_hdw_cmd_powerup(struct pvr2_hdw *hdw)
int status;
LOCK_TAKE(hdw->ctl_lock); do {
pvr2_trace(PVR2_TRACE_INIT,"Requesting powerup");
- hdw->cmd_buffer[0] = 0xde;
+ hdw->cmd_buffer[0] = FX2CMD_POWER_ON;
status = pvr2_send_request(hdw,hdw->cmd_buffer,1,NULL,0);
} while (0); LOCK_GIVE(hdw->ctl_lock);
return status;
@@ -2994,7 +3156,8 @@ static int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl)
{
int status;
LOCK_TAKE(hdw->ctl_lock); do {
- hdw->cmd_buffer[0] = (runFl ? 0x36 : 0x37);
+ hdw->cmd_buffer[0] =
+ (runFl ? FX2CMD_STREAMING_ON : FX2CMD_STREAMING_OFF);
status = pvr2_send_request(hdw,hdw->cmd_buffer,1,NULL,0);
} while (0); LOCK_GIVE(hdw->ctl_lock);
if (!status) {
@@ -3093,7 +3256,7 @@ static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw)
{
int result;
LOCK_TAKE(hdw->ctl_lock); do {
- hdw->cmd_buffer[0] = 0xeb;
+ hdw->cmd_buffer[0] = FX2CMD_GET_EEPROM_ADDR;
result = pvr2_send_request(hdw,
hdw->cmd_buffer,1,
hdw->cmd_buffer,1);
@@ -3105,8 +3268,8 @@ static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw)
int pvr2_hdw_register_access(struct pvr2_hdw *hdw,
- u32 chip_id,unsigned long reg_id,
- int setFl,u32 *val_ptr)
+ u32 match_type, u32 match_chip, u64 reg_id,
+ int setFl,u64 *val_ptr)
{
#ifdef CONFIG_VIDEO_ADV_DEBUG
struct list_head *item;
@@ -3115,16 +3278,23 @@ int pvr2_hdw_register_access(struct pvr2_hdw *hdw,
int stat = 0;
int okFl = 0;
- req.i2c_id = chip_id;
+ if (!capable(CAP_SYS_ADMIN)) return -EPERM;
+
+ req.match_type = match_type;
+ req.match_chip = match_chip;
req.reg = reg_id;
if (setFl) req.val = *val_ptr;
mutex_lock(&hdw->i2c_list_lock); do {
list_for_each(item,&hdw->i2c_clients) {
cp = list_entry(item,struct pvr2_i2c_client,list);
- if (cp->client->driver->id != chip_id) continue;
+ if (!v4l2_chip_match_i2c_client(
+ cp->client,
+ req.match_type, req.match_chip)) {
+ continue;
+ }
stat = pvr2_i2c_client_cmd(
- cp,(setFl ? VIDIOC_INT_S_REGISTER :
- VIDIOC_INT_G_REGISTER),&req);
+ cp,(setFl ? VIDIOC_DBG_S_REGISTER :
+ VIDIOC_DBG_G_REGISTER),&req);
if (!setFl) *val_ptr = req.val;
okFl = !0;
break;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/drivers/media/video/pvrusb2/pvrusb2-hdw.h
index 29979bb2a768..4dba8d006324 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.h
@@ -44,12 +44,6 @@
#define PVR2_CVAL_INPUT_COMPOSITE 2
#define PVR2_CVAL_INPUT_RADIO 3
-/* Values that pvr2_hdw_get_signal_status() returns */
-#define PVR2_SIGNAL_OK 0x0001
-#define PVR2_SIGNAL_STEREO 0x0002
-#define PVR2_SIGNAL_SAP 0x0004
-
-
/* 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
@@ -72,10 +66,17 @@
PVR2_SUBSYS_RUN_ALL )
enum pvr2_config {
- pvr2_config_empty,
- pvr2_config_mpeg,
- pvr2_config_vbi,
- pvr2_config_radio,
+ pvr2_config_empty, /* No configuration */
+ pvr2_config_mpeg, /* Encoded / compressed video */
+ pvr2_config_vbi, /* Standard vbi info */
+ pvr2_config_pcm, /* Audio raw pcm stream */
+ pvr2_config_rawvideo, /* Video raw frames */
+};
+
+enum pvr2_v4l_type {
+ pvr2_v4l_type_video,
+ pvr2_v4l_type_vbi,
+ pvr2_v4l_type_radio,
};
const char *pvr2_config_get_name(enum pvr2_config);
@@ -123,6 +124,9 @@ struct usb_device *pvr2_hdw_get_dev(struct pvr2_hdw *);
/* Retrieve serial number of device */
unsigned long pvr2_hdw_get_sn(struct pvr2_hdw *);
+/* Retrieve bus location info of device */
+const char *pvr2_hdw_get_bus_info(struct pvr2_hdw *);
+
/* Called when hardware has been unplugged */
void pvr2_hdw_disconnect(struct pvr2_hdw *);
@@ -148,8 +152,11 @@ int pvr2_hdw_commit_ctl(struct pvr2_hdw *);
/* Return name for this driver instance */
const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *);
-/* Return PVR2_SIGNAL_XXXX bit mask indicating signal status */
-unsigned int pvr2_hdw_get_signal_status(struct pvr2_hdw *);
+/* Mark tuner status stale so that it will be re-fetched */
+void pvr2_hdw_execute_tuner_poll(struct pvr2_hdw *);
+
+/* Return information about the tuner */
+int pvr2_hdw_get_tuner_status(struct pvr2_hdw *,struct v4l2_tuner *);
/* Query device and see if it thinks it is on a high-speed USB link */
int pvr2_hdw_is_hsm(struct pvr2_hdw *);
@@ -205,20 +212,22 @@ int pvr2_hdw_cpufw_get_enabled(struct pvr2_hdw *);
int pvr2_hdw_cpufw_get(struct pvr2_hdw *,unsigned int offs,
char *buf,unsigned int cnt);
-/* Retrieve previously stored v4l minor device number */
-int pvr2_hdw_v4l_get_minor_number(struct pvr2_hdw *);
+/* Retrieve a previously stored v4l minor device number */
+int pvr2_hdw_v4l_get_minor_number(struct pvr2_hdw *,enum pvr2_v4l_type index);
-/* Store the v4l minor device number */
-void pvr2_hdw_v4l_store_minor_number(struct pvr2_hdw *,int);
+/* Store a v4l minor device number */
+void pvr2_hdw_v4l_store_minor_number(struct pvr2_hdw *,
+ enum pvr2_v4l_type index,int);
/* Direct read/write access to chip's registers:
- chip_id - unique id of chip (e.g. I2C_DRIVERD_xxxx)
+ match_type - how to interpret match_chip (e.g. driver ID, i2c address)
+ match_chip - chip match value (e.g. I2C_DRIVERD_xxxx)
reg_id - register number to access
setFl - true to set the register, false to read it
val_ptr - storage location for source / result. */
int pvr2_hdw_register_access(struct pvr2_hdw *,
- u32 chip_id,unsigned long reg_id,
- int setFl,u32 *val_ptr);
+ u32 match_type, u32 match_chip,u64 reg_id,
+ int setFl,u64 *val_ptr);
/* The following entry points are all lower level things you normally don't
want to worry about. */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c
index 05121666b9ba..49773764383b 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c
@@ -33,15 +33,17 @@
#define trace_i2c(...) pvr2_trace(PVR2_TRACE_I2C,__VA_ARGS__)
#define OP_STANDARD 0
-#define OP_BCSH 1
-#define OP_VOLUME 2
-#define OP_FREQ 3
-#define OP_AUDIORATE 4
-#define OP_SIZE 5
-#define OP_LOG 6
+#define OP_AUDIOMODE 1
+#define OP_BCSH 2
+#define OP_VOLUME 3
+#define OP_FREQ 4
+#define OP_AUDIORATE 5
+#define OP_SIZE 6
+#define OP_LOG 7
static const struct pvr2_i2c_op * const ops[] = {
[OP_STANDARD] = &pvr2_i2c_op_v4l2_standard,
+ [OP_AUDIOMODE] = &pvr2_i2c_op_v4l2_audiomode,
[OP_BCSH] = &pvr2_i2c_op_v4l2_bcsh,
[OP_VOLUME] = &pvr2_i2c_op_v4l2_volume,
[OP_FREQ] = &pvr2_i2c_op_v4l2_frequency,
@@ -54,11 +56,13 @@ void pvr2_i2c_probe(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp)
int id;
id = cp->client->driver->id;
cp->ctl_mask = ((1 << OP_STANDARD) |
+ (1 << OP_AUDIOMODE) |
(1 << OP_BCSH) |
(1 << OP_VOLUME) |
(1 << OP_FREQ) |
(1 << OP_SIZE) |
(1 << OP_LOG));
+ cp->status_poll = pvr2_v4l2_cmd_status_poll;
if (id == I2C_DRIVERID_MSP3400) {
if (pvr2_i2c_msp3400_setup(hdw,cp)) {
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c
index 05ea17afe903..c650e02ccd00 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c
@@ -24,22 +24,26 @@
#include "pvrusb2-hdw-internal.h"
#include "pvrusb2-debug.h"
#include <linux/videodev2.h>
-
+#include <media/v4l2-common.h>
static void set_standard(struct pvr2_hdw *hdw)
{
- v4l2_std_id vs;
- vs = hdw->std_mask_cur;
- pvr2_trace(PVR2_TRACE_CHIPS,
- "i2c v4l2 set_standard(0x%llx)",(long long unsigned)vs);
-
- pvr2_i2c_core_cmd(hdw,VIDIOC_S_STD,&vs);
+ pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_standard");
+
+ if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
+ pvr2_i2c_core_cmd(hdw,AUDC_SET_RADIO,NULL);
+ } else {
+ v4l2_std_id vs;
+ vs = hdw->std_mask_cur;
+ pvr2_i2c_core_cmd(hdw,VIDIOC_S_STD,&vs);
+ }
+ hdw->tuner_signal_stale = !0;
}
static int check_standard(struct pvr2_hdw *hdw)
{
- return hdw->std_dirty != 0;
+ return (hdw->input_dirty != 0) || (hdw->std_dirty != 0);
}
@@ -136,16 +140,53 @@ const struct pvr2_i2c_op pvr2_i2c_op_v4l2_volume = {
};
+static void set_audiomode(struct pvr2_hdw *hdw)
+{
+ struct v4l2_tuner vt;
+ memset(&vt,0,sizeof(vt));
+ vt.audmode = hdw->audiomode_val;
+ pvr2_i2c_core_cmd(hdw,VIDIOC_S_TUNER,&vt);
+}
+
+
+static int check_audiomode(struct pvr2_hdw *hdw)
+{
+ return (hdw->input_dirty ||
+ hdw->audiomode_dirty);
+}
+
+
+const struct pvr2_i2c_op pvr2_i2c_op_v4l2_audiomode = {
+ .check = check_audiomode,
+ .update = set_audiomode,
+ .name = "v4l2_audiomode",
+};
+
+
static void set_frequency(struct pvr2_hdw *hdw)
{
unsigned long fv;
struct v4l2_frequency freq;
- fv = hdw->freqVal;
+ fv = pvr2_hdw_get_cur_freq(hdw);
pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_freq(%lu)",fv);
+ if (hdw->tuner_signal_stale) {
+ pvr2_i2c_core_status_poll(hdw);
+ }
memset(&freq,0,sizeof(freq));
- freq.frequency = fv / 62500;
+ if (hdw->tuner_signal_info.capability & V4L2_TUNER_CAP_LOW) {
+ // ((fv * 1000) / 62500)
+ freq.frequency = (fv * 2) / 125;
+ } else {
+ freq.frequency = fv / 62500;
+ }
+ /* tuner-core currently doesn't seem to care about this, but
+ let's set it anyway for completeness. */
+ if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
+ freq.type = V4L2_TUNER_RADIO;
+ } else {
+ freq.type = V4L2_TUNER_ANALOG_TV;
+ }
freq.tuner = 0;
- freq.type = V4L2_TUNER_ANALOG_TV;
pvr2_i2c_core_cmd(hdw,VIDIOC_S_FREQUENCY,&freq);
}
@@ -221,6 +262,12 @@ void pvr2_v4l2_cmd_stream(struct pvr2_i2c_client *cp,int fl)
}
+void pvr2_v4l2_cmd_status_poll(struct pvr2_i2c_client *cp)
+{
+ pvr2_i2c_client_cmd(cp,VIDIOC_G_TUNER,&cp->hdw->tuner_signal_info);
+}
+
+
/*
Stuff for Emacs to see, in order to encourage consistent editing style:
*** Local Variables: ***
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h b/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h
index ecabddba1ec5..c838df6167f9 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h
@@ -26,13 +26,16 @@
#include "pvrusb2-i2c-core.h"
extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_standard;
+extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_radio;
extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_bcsh;
extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_volume;
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_audiomode;
extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_log;
void pvr2_v4l2_cmd_stream(struct pvr2_i2c_client *,int);
+void pvr2_v4l2_cmd_status_poll(struct pvr2_i2c_client *);
#endif /* __PVRUSB2_CMD_V4L2_H */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
index 62a7cfca837d..58fc3c730fe1 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
@@ -22,6 +22,7 @@
#include "pvrusb2-i2c-core.h"
#include "pvrusb2-hdw-internal.h"
#include "pvrusb2-debug.h"
+#include "pvrusb2-fx2-cmd.h"
#define trace_i2c(...) pvr2_trace(PVR2_TRACE_I2C,__VA_ARGS__)
@@ -66,7 +67,7 @@ static int pvr2_i2c_write(struct pvr2_hdw *hdw, /* Context */
memset(hdw->cmd_buffer, 0, sizeof(hdw->cmd_buffer));
/* Set up command buffer for an I2C write */
- hdw->cmd_buffer[0] = 0x08; /* write prefix */
+ hdw->cmd_buffer[0] = FX2CMD_I2C_WRITE; /* write prefix */
hdw->cmd_buffer[1] = i2c_addr; /* i2c addr of chip */
hdw->cmd_buffer[2] = length; /* length of what follows */
if (length) memcpy(hdw->cmd_buffer + 3, data, length);
@@ -128,7 +129,7 @@ static int pvr2_i2c_read(struct pvr2_hdw *hdw, /* Context */
memset(hdw->cmd_buffer, 0, sizeof(hdw->cmd_buffer));
/* Set up command buffer for an I2C write followed by a read */
- hdw->cmd_buffer[0] = 0x09; /* read prefix */
+ hdw->cmd_buffer[0] = FX2CMD_I2C_READ; /* read prefix */
hdw->cmd_buffer[1] = dlen; /* arg length */
hdw->cmd_buffer[2] = rlen; /* answer length. Device will send one
more byte (status). */
@@ -221,7 +222,7 @@ static int i2c_24xxx_ir(struct pvr2_hdw *hdw,
/* Issue a command to the FX2 to read the IR receiver. */
LOCK_TAKE(hdw->ctl_lock); do {
- hdw->cmd_buffer[0] = 0xec;
+ hdw->cmd_buffer[0] = FX2CMD_GET_IR_CODE;
stat = pvr2_send_request(hdw,
hdw->cmd_buffer,1,
hdw->cmd_buffer,4);
@@ -590,6 +591,33 @@ static int handler_check(struct pvr2_i2c_client *cp)
#define BUFSIZE 500
+
+void pvr2_i2c_core_status_poll(struct pvr2_hdw *hdw)
+{
+ struct list_head *item;
+ struct pvr2_i2c_client *cp;
+ mutex_lock(&hdw->i2c_list_lock); do {
+ struct v4l2_tuner *vtp = &hdw->tuner_signal_info;
+ memset(vtp,0,sizeof(*vtp));
+ list_for_each(item,&hdw->i2c_clients) {
+ cp = list_entry(item,struct pvr2_i2c_client,list);
+ if (!cp->detected_flag) continue;
+ if (!cp->status_poll) continue;
+ cp->status_poll(cp);
+ }
+ hdw->tuner_signal_stale = 0;
+ pvr2_trace(PVR2_TRACE_CHIPS,"i2c status poll"
+ " type=%u strength=%u audio=0x%x cap=0x%x"
+ " low=%u hi=%u",
+ vtp->type,
+ vtp->signal,vtp->rxsubchans,vtp->capability,
+ vtp->rangelow,vtp->rangehigh);
+ } while (0); mutex_unlock(&hdw->i2c_list_lock);
+}
+
+
+/* Issue various I2C operations to bring chip-level drivers into sync with
+ state stored in this driver. */
void pvr2_i2c_core_sync(struct pvr2_hdw *hdw)
{
unsigned long msk;
@@ -870,12 +898,12 @@ static int pvr2_i2c_attach_inform(struct i2c_client *client)
struct pvr2_hdw *hdw = (struct pvr2_hdw *)(client->adapter->algo_data);
struct pvr2_i2c_client *cp;
int fl = !(hdw->i2c_pend_types & PVR2_I2C_PEND_ALL);
- cp = kmalloc(sizeof(*cp),GFP_KERNEL);
+ cp = kzalloc(sizeof(*cp),GFP_KERNEL);
trace_i2c("i2c_attach [client=%s @ 0x%x ctxt=%p]",
client->name,
client->addr,cp);
if (!cp) return -ENOMEM;
- memset(cp,0,sizeof(*cp));
+ cp->hdw = hdw;
INIT_LIST_HEAD(&cp->list);
cp->client = client;
mutex_lock(&hdw->i2c_list_lock); do {
@@ -948,8 +976,7 @@ static void do_i2c_scan(struct pvr2_hdw *hdw)
printk("%s: i2c scan beginning\n",hdw->name);
for (i = 0; i < 128; i++) {
msg[0].addr = i;
- rc = i2c_transfer(&hdw->i2c_adap,msg,
- sizeof(msg)/sizeof(msg[0]));
+ rc = i2c_transfer(&hdw->i2c_adap,msg, ARRAY_SIZE(msg));
if (rc != 1) continue;
printk("%s: i2c scan: found device @ 0x%x\n",hdw->name,i);
}
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h
index 6d7e25247576..bd0807b905bb 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h
@@ -35,10 +35,12 @@ struct pvr2_i2c_client {
struct i2c_client *client;
struct pvr2_i2c_handler *handler;
struct list_head list;
+ struct pvr2_hdw *hdw;
int detected_flag;
int recv_enable;
unsigned long pend_mask;
unsigned long ctl_mask;
+ void (*status_poll)(struct pvr2_i2c_client *);
};
struct pvr2_i2c_handler {
@@ -67,6 +69,7 @@ int pvr2_i2c_core_cmd(struct pvr2_hdw *,unsigned int cmd,void *arg);
int pvr2_i2c_core_check_stale(struct pvr2_hdw *);
void pvr2_i2c_core_sync(struct pvr2_hdw *);
+void pvr2_i2c_core_status_poll(struct pvr2_hdw *);
unsigned int pvr2_i2c_report(struct pvr2_hdw *,char *buf,unsigned int maxlen);
#define PVR2_I2C_DETAIL_DEBUG 0x0001
#define PVR2_I2C_DETAIL_HANDLER 0x0002
diff --git a/drivers/media/video/pvrusb2/pvrusb2-io.c b/drivers/media/video/pvrusb2/pvrusb2-io.c
index 57fb32033543..ce3c8982ffe0 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-io.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-io.c
@@ -474,9 +474,8 @@ static void buffer_complete(struct urb *urb)
struct pvr2_stream *pvr2_stream_create(void)
{
struct pvr2_stream *sp;
- sp = kmalloc(sizeof(*sp),GFP_KERNEL);
+ sp = kzalloc(sizeof(*sp),GFP_KERNEL);
if (!sp) return sp;
- memset(sp,0,sizeof(*sp));
pvr2_trace(PVR2_TRACE_INIT,"pvr2_stream_create: sp=%p",sp);
pvr2_stream_init(sp);
return sp;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-ioread.c b/drivers/media/video/pvrusb2/pvrusb2-ioread.c
index b71f9a961f8a..f782418afa45 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-ioread.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-ioread.c
@@ -87,10 +87,9 @@ static void pvr2_ioread_done(struct pvr2_ioread *cp)
struct pvr2_ioread *pvr2_ioread_create(void)
{
struct pvr2_ioread *cp;
- cp = kmalloc(sizeof(*cp),GFP_KERNEL);
+ cp = kzalloc(sizeof(*cp),GFP_KERNEL);
if (!cp) return NULL;
pvr2_trace(PVR2_TRACE_STRUCT,"pvr2_ioread_create id=%p",cp);
- memset(cp,0,sizeof(*cp));
if (pvr2_ioread_init(cp) < 0) {
kfree(cp);
return NULL;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-std.c b/drivers/media/video/pvrusb2/pvrusb2-std.c
index f95c598ff627..81de26ba41d9 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-std.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-std.c
@@ -78,14 +78,14 @@ struct std_name {
#define CSTD_ALL (CSTD_PAL|CSTD_NTSC|CSTD_SECAM)
/* Mapping of standard bits to color system */
-const static struct std_name std_groups[] = {
+static const 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[] = {
+static const struct std_name std_items[] = {
{"B",TSTD_B},
{"B1",TSTD_B1},
{"D",TSTD_D},
@@ -141,10 +141,8 @@ int pvr2_std_str_to_id(v4l2_std_id *idPtr,const char *bufPtr,
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);
+ sp = find_std_name(std_groups, ARRAY_SIZE(std_groups),
+ bufPtr,cnt);
if (!sp) return 0; // Illegal color system name
cnt++;
bufPtr += cnt;
@@ -163,8 +161,7 @@ int pvr2_std_str_to_id(v4l2_std_id *idPtr,const char *bufPtr,
if (ch == '/') break;
cnt++;
}
- sp = find_std_name(std_items,
- sizeof(std_items)/sizeof(std_items[0]),
+ sp = find_std_name(std_items, ARRAY_SIZE(std_items),
bufPtr,cnt);
if (!sp) return 0; // Illegal modulation system ID
t = sp->id & cmsk;
@@ -189,14 +186,10 @@ unsigned int pvr2_std_id_to_str(char *bufPtr, unsigned int bufSize,
unsigned int c1,c2;
cfl = 0;
c1 = 0;
- for (idx1 = 0;
- idx1 < sizeof(std_groups)/sizeof(std_groups[0]);
- idx1++) {
+ for (idx1 = 0; idx1 < ARRAY_SIZE(std_groups); idx1++) {
gp = std_groups + idx1;
gfl = 0;
- for (idx2 = 0;
- idx2 < sizeof(std_items)/sizeof(std_items[0]);
- idx2++) {
+ for (idx2 = 0; idx2 < ARRAY_SIZE(std_items); idx2++) {
ip = std_items + idx2;
if (!(gp->id & ip->id & id)) continue;
if (!gfl) {
@@ -279,7 +272,7 @@ static struct v4l2_standard generic_standards[] = {
}
};
-#define generic_standards_cnt (sizeof(generic_standards)/sizeof(generic_standards[0]))
+#define generic_standards_cnt ARRAY_SIZE(generic_standards)
static struct v4l2_standard *match_std(v4l2_std_id id)
{
@@ -348,7 +341,7 @@ struct v4l2_standard *pvr2_std_create_enum(unsigned int *countptr,
fmsk |= idmsk;
}
- for (idx2 = 0; idx2 < sizeof(std_mixes)/sizeof(std_mixes[0]); idx2++) {
+ for (idx2 = 0; idx2 < ARRAY_SIZE(std_mixes); idx2++) {
if ((id & std_mixes[idx2]) == std_mixes[idx2]) std_cnt++;
}
@@ -366,16 +359,15 @@ struct v4l2_standard *pvr2_std_create_enum(unsigned int *countptr,
std_cnt);
if (!std_cnt) return NULL; // paranoia
- stddefs = kmalloc(sizeof(struct v4l2_standard) * std_cnt,
+ stddefs = kzalloc(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++) {
+ for (idx2 = 0; (idx2 < ARRAY_SIZE(std_mixes)) && (idx < std_cnt);
+ idx2++) {
if (!(id & std_mixes[idx2])) continue;
if (pvr2_std_fill(stddefs+idx,std_mixes[idx2])) idx++;
}
diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
index c294f46db9b9..a741c556a39a 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
@@ -40,9 +40,13 @@ struct pvr2_sysfs {
struct pvr2_sysfs_ctl_item *item_first;
struct pvr2_sysfs_ctl_item *item_last;
struct class_device_attribute attr_v4l_minor_number;
+ struct class_device_attribute attr_v4l_radio_minor_number;
struct class_device_attribute attr_unit_number;
+ struct class_device_attribute attr_bus_info;
int v4l_minor_number_created_ok;
+ int v4l_radio_minor_number_created_ok;
int unit_number_created_ok;
+ int bus_info_created_ok;
};
#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
@@ -491,7 +495,7 @@ static void pvr2_sysfs_add_control(struct pvr2_sysfs *sfp,int ctl_id)
unsigned int cnt,acnt;
int ret;
- if ((ctl_id < 0) || (ctl_id >= (sizeof(funcs)/sizeof(funcs[0])))) {
+ if ((ctl_id < 0) || (ctl_id >= ARRAY_SIZE(funcs))) {
return;
}
@@ -499,9 +503,8 @@ static void pvr2_sysfs_add_control(struct pvr2_sysfs *sfp,int ctl_id)
cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,ctl_id);
if (!cptr) return;
- cip = kmalloc(sizeof(*cip),GFP_KERNEL);
+ cip = kzalloc(sizeof(*cip),GFP_KERNEL);
if (!cip) return;
- memset(cip,0,sizeof(*cip));
pvr2_sysfs_trace("Creating pvr2_sysfs_ctl_item id=%p",cip);
cip->cptr = cptr;
@@ -611,9 +614,8 @@ static void pvr2_sysfs_add_debugifc(struct pvr2_sysfs *sfp)
struct pvr2_sysfs_debugifc *dip;
int ret;
- dip = kmalloc(sizeof(*dip),GFP_KERNEL);
+ dip = kzalloc(sizeof(*dip),GFP_KERNEL);
if (!dip) return;
- memset(dip,0,sizeof(*dip));
dip->attr_debugcmd.attr.owner = THIS_MODULE;
dip->attr_debugcmd.attr.name = "debugcmd";
dip->attr_debugcmd.attr.mode = S_IRUGO|S_IWUSR|S_IWGRP;
@@ -705,10 +707,18 @@ static void class_dev_destroy(struct pvr2_sysfs *sfp)
pvr2_sysfs_tear_down_debugifc(sfp);
#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
pvr2_sysfs_tear_down_controls(sfp);
+ if (sfp->bus_info_created_ok) {
+ class_device_remove_file(sfp->class_dev,
+ &sfp->attr_bus_info);
+ }
if (sfp->v4l_minor_number_created_ok) {
class_device_remove_file(sfp->class_dev,
&sfp->attr_v4l_minor_number);
}
+ if (sfp->v4l_radio_minor_number_created_ok) {
+ class_device_remove_file(sfp->class_dev,
+ &sfp->attr_v4l_radio_minor_number);
+ }
if (sfp->unit_number_created_ok) {
class_device_remove_file(sfp->class_dev,
&sfp->attr_unit_number);
@@ -726,7 +736,30 @@ static ssize_t v4l_minor_number_show(struct class_device *class_dev,char *buf)
sfp = (struct pvr2_sysfs *)class_dev->class_data;
if (!sfp) return -EINVAL;
return scnprintf(buf,PAGE_SIZE,"%d\n",
- pvr2_hdw_v4l_get_minor_number(sfp->channel.hdw));
+ pvr2_hdw_v4l_get_minor_number(sfp->channel.hdw,
+ pvr2_v4l_type_video));
+}
+
+
+static ssize_t bus_info_show(struct class_device *class_dev,char *buf)
+{
+ struct pvr2_sysfs *sfp;
+ sfp = (struct pvr2_sysfs *)class_dev->class_data;
+ if (!sfp) return -EINVAL;
+ return scnprintf(buf,PAGE_SIZE,"%s\n",
+ pvr2_hdw_get_bus_info(sfp->channel.hdw));
+}
+
+
+static ssize_t v4l_radio_minor_number_show(struct class_device *class_dev,
+ char *buf)
+{
+ struct pvr2_sysfs *sfp;
+ sfp = (struct pvr2_sysfs *)class_dev->class_data;
+ if (!sfp) return -EINVAL;
+ return scnprintf(buf,PAGE_SIZE,"%d\n",
+ pvr2_hdw_v4l_get_minor_number(sfp->channel.hdw,
+ pvr2_v4l_type_radio));
}
@@ -749,9 +782,8 @@ static void class_dev_create(struct pvr2_sysfs *sfp,
usb_dev = pvr2_hdw_get_dev(sfp->channel.hdw);
if (!usb_dev) return;
- class_dev = kmalloc(sizeof(*class_dev),GFP_KERNEL);
+ class_dev = kzalloc(sizeof(*class_dev),GFP_KERNEL);
if (!class_dev) return;
- memset(class_dev,0,sizeof(*class_dev));
pvr2_sysfs_trace("Creating class_dev id=%p",class_dev);
@@ -793,6 +825,20 @@ static void class_dev_create(struct pvr2_sysfs *sfp,
sfp->v4l_minor_number_created_ok = !0;
}
+ sfp->attr_v4l_radio_minor_number.attr.owner = THIS_MODULE;
+ sfp->attr_v4l_radio_minor_number.attr.name = "v4l_radio_minor_number";
+ sfp->attr_v4l_radio_minor_number.attr.mode = S_IRUGO;
+ sfp->attr_v4l_radio_minor_number.show = v4l_radio_minor_number_show;
+ sfp->attr_v4l_radio_minor_number.store = NULL;
+ ret = class_device_create_file(sfp->class_dev,
+ &sfp->attr_v4l_radio_minor_number);
+ if (ret < 0) {
+ printk(KERN_WARNING "%s: class_device_create_file error: %d\n",
+ __FUNCTION__, ret);
+ } else {
+ sfp->v4l_radio_minor_number_created_ok = !0;
+ }
+
sfp->attr_unit_number.attr.owner = THIS_MODULE;
sfp->attr_unit_number.attr.name = "unit_number";
sfp->attr_unit_number.attr.mode = S_IRUGO;
@@ -806,6 +852,20 @@ static void class_dev_create(struct pvr2_sysfs *sfp,
sfp->unit_number_created_ok = !0;
}
+ sfp->attr_bus_info.attr.owner = THIS_MODULE;
+ sfp->attr_bus_info.attr.name = "bus_info_str";
+ sfp->attr_bus_info.attr.mode = S_IRUGO;
+ sfp->attr_bus_info.show = bus_info_show;
+ sfp->attr_bus_info.store = NULL;
+ ret = class_device_create_file(sfp->class_dev,
+ &sfp->attr_bus_info);
+ if (ret < 0) {
+ printk(KERN_WARNING "%s: class_device_create_file error: %d\n",
+ __FUNCTION__, ret);
+ } else {
+ sfp->bus_info_created_ok = !0;
+ }
+
pvr2_sysfs_add_controls(sfp);
#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
pvr2_sysfs_add_debugifc(sfp);
@@ -829,9 +889,8 @@ struct pvr2_sysfs *pvr2_sysfs_create(struct pvr2_context *mp,
struct pvr2_sysfs_class *class_ptr)
{
struct pvr2_sysfs *sfp;
- sfp = kmalloc(sizeof(*sfp),GFP_KERNEL);
+ sfp = kzalloc(sizeof(*sfp),GFP_KERNEL);
if (!sfp) return sfp;
- memset(sfp,0,sizeof(*sfp));
pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr2_sysfs id=%p",sfp);
pvr2_channel_init(&sfp->channel,mp);
sfp->channel.check_func = pvr2_sysfs_internal_check;
@@ -852,9 +911,8 @@ static int pvr2_sysfs_hotplug(struct class_device *cd,char **envp,
struct pvr2_sysfs_class *pvr2_sysfs_class_create(void)
{
struct pvr2_sysfs_class *clp;
- clp = kmalloc(sizeof(*clp),GFP_KERNEL);
+ clp = kzalloc(sizeof(*clp),GFP_KERNEL);
if (!clp) return clp;
- memset(clp,0,sizeof(*clp));
pvr2_sysfs_trace("Creating pvr2_sysfs_class id=%p",clp);
clp->class.name = "pvrusb2";
clp->class.class_release = pvr2_sysfs_class_release;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-tuner.c b/drivers/media/video/pvrusb2/pvrusb2-tuner.c
index af9f246f8d3f..05e65ce2e3a9 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-tuner.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-tuner.c
@@ -80,7 +80,7 @@ static unsigned int pvr2_tuner_describe(struct pvr2_tuner_handler *ctxt,char *bu
}
-const static struct pvr2_i2c_handler_functions tuner_funcs = {
+static const struct pvr2_i2c_handler_functions tuner_funcs = {
.detach = (void (*)(void *))pvr2_tuner_detach,
.check = (int (*)(void *))tuner_check,
.update = (void (*)(void *))tuner_update,
@@ -93,9 +93,8 @@ int pvr2_i2c_tuner_setup(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp)
struct pvr2_tuner_handler *ctxt;
if (cp->handler) return 0;
- ctxt = kmalloc(sizeof(*ctxt),GFP_KERNEL);
+ ctxt = kzalloc(sizeof(*ctxt),GFP_KERNEL);
if (!ctxt) return 0;
- memset(ctxt,0,sizeof(*ctxt));
ctxt->i2c_handler.func_data = ctxt;
ctxt->i2c_handler.func_table = &tuner_funcs;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
index 6cf17080eb49..4563b3df8a0d 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
@@ -40,7 +40,10 @@ struct pvr2_v4l2_dev {
struct video_device devbase; /* MUST be first! */
struct pvr2_v4l2 *v4lp;
struct pvr2_context_stream *stream;
- enum pvr2_config config;
+ /* Information about this device: */
+ enum pvr2_config config; /* Expected stream format */
+ int v4l_type; /* V4L defined type for this device node */
+ enum pvr2_v4l_type minor_type; /* pvr2-understood minor device type */
};
struct pvr2_v4l2_fh {
@@ -54,6 +57,7 @@ struct pvr2_v4l2_fh {
struct pvr2_v4l2_fh *vprev;
wait_queue_head_t wait_data;
int fw_mode_flag;
+ int prev_input_val;
};
struct pvr2_v4l2 {
@@ -63,13 +67,22 @@ struct pvr2_v4l2 {
struct v4l2_prio_state prio;
- /* streams */
- struct pvr2_v4l2_dev *vdev;
+ /* streams - Note that these must be separately, individually,
+ * allocated pointers. This is because the v4l core is going to
+ * manage their deletion - separately, individually... */
+ struct pvr2_v4l2_dev *dev_video;
+ struct pvr2_v4l2_dev *dev_radio;
};
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");
+MODULE_PARM_DESC(video_nr, "Offset for device's video dev minor");
+static int radio_nr[PVR_NUM] = {[0 ... PVR_NUM-1] = -1};
+module_param_array(radio_nr, int, NULL, 0444);
+MODULE_PARM_DESC(radio_nr, "Offset for device's radio dev minor");
+static int vbi_nr[PVR_NUM] = {[0 ... PVR_NUM-1] = -1};
+module_param_array(vbi_nr, int, NULL, 0444);
+MODULE_PARM_DESC(vbi_nr, "Offset for device's vbi dev minor");
static struct v4l2_capability pvr_capability ={
.driver = "pvrusb2",
@@ -77,30 +90,11 @@ static struct v4l2_capability pvr_capability ={
.bus_info = "usb",
.version = KERNEL_VERSION(0,8,0),
.capabilities = (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VBI_CAPTURE |
- V4L2_CAP_TUNER | V4L2_CAP_AUDIO |
+ V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_RADIO |
V4L2_CAP_READWRITE),
.reserved = {0,0,0,0}
};
-static struct v4l2_tuner pvr_v4l2_tuners[]= {
- {
- .index = 0,
- .name = "TV Tuner",
- .type = V4L2_TUNER_ANALOG_TV,
- .capability = (V4L2_TUNER_CAP_NORM |
- V4L2_TUNER_CAP_STEREO |
- V4L2_TUNER_CAP_LANG1 |
- V4L2_TUNER_CAP_LANG2),
- .rangelow = 0,
- .rangehigh = 0,
- .rxsubchans = V4L2_TUNER_SUB_STEREO,
- .audmode = V4L2_TUNER_MODE_STEREO,
- .signal = 0,
- .afc = 0,
- .reserved = {0,0,0,0}
- }
-};
-
static struct v4l2_fmtdesc pvr_fmtdesc [] = {
{
.index = 0,
@@ -154,6 +148,18 @@ static struct v4l2_format pvr_format [] = {
}
};
+
+static const char *get_v4l_name(int v4l_type)
+{
+ switch (v4l_type) {
+ case VFL_TYPE_GRABBER: return "video";
+ case VFL_TYPE_RADIO: return "radio";
+ case VFL_TYPE_VBI: return "vbi";
+ default: return "?";
+ }
+}
+
+
/*
* pvr_ioctl()
*
@@ -197,6 +203,8 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
struct v4l2_capability *cap = arg;
memcpy(cap, &pvr_capability, sizeof(struct v4l2_capability));
+ strlcpy(cap->bus_info,pvr2_hdw_get_bus_info(hdw),
+ sizeof(cap->bus_info));
ret = 0;
break;
@@ -315,13 +323,39 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
case VIDIOC_ENUMAUDIO:
{
+ /* pkt: FIXME: We are returning one "fake" input here
+ which could very well be called "whatever_we_like".
+ This is for apps that want to see an audio input
+ just to feel comfortable, as well as to test if
+ it can do stereo or sth. There is actually no guarantee
+ that the actual audio input cannot change behind the app's
+ back, but most applications should not mind that either.
+
+ Hopefully, mplayer people will work with us on this (this
+ whole mess is to support mplayer pvr://), or Hans will come
+ up with a more standard way to say "we have inputs but we
+ don 't want you to change them independent of video" which
+ will sort this mess.
+ */
+ struct v4l2_audio *vin = arg;
ret = -EINVAL;
+ if (vin->index > 0) break;
+ strncpy(vin->name, "PVRUSB2 Audio",14);
+ vin->capability = V4L2_AUDCAP_STEREO;
+ ret = 0;
+ break;
break;
}
case VIDIOC_G_AUDIO:
{
- ret = -EINVAL;
+ /* pkt: FIXME: see above comment (VIDIOC_ENUMAUDIO) */
+ struct v4l2_audio *vin = arg;
+ memset(vin,0,sizeof(*vin));
+ vin->index = 0;
+ strncpy(vin->name, "PVRUSB2 Audio",14);
+ vin->capability = V4L2_AUDCAP_STEREO;
+ ret = 0;
break;
}
@@ -333,34 +367,11 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
case VIDIOC_G_TUNER:
{
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);
+ if (vt->index != 0) break; /* Only answer for the 1st tuner */
- memcpy(vt, &pvr_v4l2_tuners[vt->index],
- sizeof(struct v4l2_tuner));
-
- vt->signal = 0;
- if (status_mask & PVR2_SIGNAL_OK) {
- if (status_mask & PVR2_SIGNAL_STEREO) {
- vt->rxsubchans = V4L2_TUNER_SUB_STEREO;
- } else {
- vt->rxsubchans = V4L2_TUNER_SUB_MONO;
- }
- if (status_mask & PVR2_SIGNAL_SAP) {
- vt->rxsubchans |= (V4L2_TUNER_SUB_LANG1 |
- V4L2_TUNER_SUB_LANG2);
- }
- vt->signal = 65535;
- }
-
- val = 0;
- ret = pvr2_ctrl_get_value(
- pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_AUDIOMODE),
- &val);
- vt->audmode = val;
+ pvr2_hdw_execute_tuner_poll(hdw);
+ ret = pvr2_hdw_get_tuner_status(hdw,vt);
break;
}
@@ -374,14 +385,40 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
ret = pvr2_ctrl_set_value(
pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_AUDIOMODE),
vt->audmode);
+ break;
}
case VIDIOC_S_FREQUENCY:
{
const struct v4l2_frequency *vf = (struct v4l2_frequency *)arg;
+ unsigned long fv;
+ struct v4l2_tuner vt;
+ int cur_input;
+ struct pvr2_ctrl *ctrlp;
+ ret = pvr2_hdw_get_tuner_status(hdw,&vt);
+ if (ret != 0) break;
+ ctrlp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
+ ret = pvr2_ctrl_get_value(ctrlp,&cur_input);
+ if (ret != 0) break;
+ if (vf->type == V4L2_TUNER_RADIO) {
+ if (cur_input != PVR2_CVAL_INPUT_RADIO) {
+ pvr2_ctrl_set_value(ctrlp,
+ PVR2_CVAL_INPUT_RADIO);
+ }
+ } else {
+ if (cur_input == PVR2_CVAL_INPUT_RADIO) {
+ pvr2_ctrl_set_value(ctrlp,
+ PVR2_CVAL_INPUT_TV);
+ }
+ }
+ fv = vf->frequency;
+ if (vt.capability & V4L2_TUNER_CAP_LOW) {
+ fv = (fv * 125) / 2;
+ } else {
+ fv = fv * 62500;
+ }
ret = pvr2_ctrl_set_value(
- pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_FREQUENCY),
- vf->frequency * 62500);
+ pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_FREQUENCY),fv);
break;
}
@@ -389,10 +426,27 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
{
struct v4l2_frequency *vf = (struct v4l2_frequency *)arg;
int val = 0;
+ int cur_input;
+ struct v4l2_tuner vt;
+ ret = pvr2_hdw_get_tuner_status(hdw,&vt);
+ if (ret != 0) break;
ret = pvr2_ctrl_get_value(
pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_FREQUENCY),
&val);
- val /= 62500;
+ if (ret != 0) break;
+ pvr2_ctrl_get_value(
+ pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT),
+ &cur_input);
+ if (cur_input == PVR2_CVAL_INPUT_RADIO) {
+ vf->type = V4L2_TUNER_RADIO;
+ } else {
+ vf->type = V4L2_TUNER_ANALOG_TV;
+ }
+ if (vt.capability & V4L2_TUNER_CAP_LOW) {
+ val = (val * 2) / 125;
+ } else {
+ val /= 62500;
+ }
vf->frequency = val;
break;
}
@@ -449,7 +503,7 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
ret = 0;
switch(vf->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
- int lmin,lmax;
+ int lmin,lmax,ldef;
struct pvr2_ctrl *hcp,*vcp;
int h = vf->fmt.pix.height;
int w = vf->fmt.pix.width;
@@ -458,14 +512,20 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
lmin = pvr2_ctrl_get_min(hcp);
lmax = pvr2_ctrl_get_max(hcp);
- if (w < lmin) {
+ ldef = pvr2_ctrl_get_def(hcp);
+ if (w == -1) {
+ w = ldef;
+ } else if (w < lmin) {
w = lmin;
} else if (w > lmax) {
w = lmax;
}
lmin = pvr2_ctrl_get_min(vcp);
lmax = pvr2_ctrl_get_max(vcp);
- if (h < lmin) {
+ ldef = pvr2_ctrl_get_def(vcp);
+ if (h == -1) {
+ h = ldef;
+ } else if (h < lmin) {
h = lmin;
} else if (h > lmax) {
h = lmax;
@@ -494,6 +554,13 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
case VIDIOC_STREAMON:
{
+ if (!fh->dev_info->stream) {
+ /* No stream defined for this node. This means
+ that we're not currently allowed to stream from
+ this node. */
+ ret = -EPERM;
+ break;
+ }
ret = pvr2_hdw_set_stream_type(hdw,dev_info->config);
if (ret < 0) return ret;
ret = pvr2_hdw_set_streaming(hdw,!0);
@@ -502,6 +569,13 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
case VIDIOC_STREAMOFF:
{
+ if (!fh->dev_info->stream) {
+ /* No stream defined for this node. This means
+ that we're not currently allowed to stream from
+ this node. */
+ ret = -EPERM;
+ break;
+ }
ret = pvr2_hdw_set_streaming(hdw,0);
break;
}
@@ -599,6 +673,7 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
struct v4l2_ext_control *ctrl;
unsigned int idx;
int val;
+ ret = 0;
for (idx = 0; idx < ctls->count; idx++) {
ctrl = ctls->controls + idx;
ret = pvr2_ctrl_get_value(
@@ -621,6 +696,7 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
(struct v4l2_ext_controls *)arg;
struct v4l2_ext_control *ctrl;
unsigned int idx;
+ ret = 0;
for (idx = 0; idx < ctls->count; idx++) {
ctrl = ctls->controls + idx;
ret = pvr2_ctrl_set_value(
@@ -643,6 +719,7 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
unsigned int idx;
/* For the moment just validate that the requested control
actually exists. */
+ ret = 0;
for (idx = 0; idx < ctls->count; idx++) {
ctrl = ctls->controls + idx;
pctl = pvr2_hdw_get_ctrl_v4l(hdw,ctrl->id);
@@ -662,16 +739,16 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
break;
}
#ifdef CONFIG_VIDEO_ADV_DEBUG
- case VIDIOC_INT_G_REGISTER:
- case VIDIOC_INT_S_REGISTER:
+ case VIDIOC_DBG_S_REGISTER:
+ case VIDIOC_DBG_G_REGISTER:
{
- u32 val;
+ u64 val;
struct v4l2_register *req = (struct v4l2_register *)arg;
- if (cmd == VIDIOC_INT_S_REGISTER) val = req->val;
+ if (cmd == VIDIOC_DBG_S_REGISTER) val = req->val;
ret = pvr2_hdw_register_access(
- hdw,req->i2c_id,req->reg,
- cmd == VIDIOC_INT_S_REGISTER,&val);
- if (cmd == VIDIOC_INT_G_REGISTER) req->val = val;
+ hdw,req->match_type,req->match_chip,req->reg,
+ cmd == VIDIOC_DBG_S_REGISTER,&val);
+ if (cmd == VIDIOC_DBG_G_REGISTER) req->val = val;
break;
}
#endif
@@ -707,8 +784,12 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip)
{
- printk(KERN_INFO "pvrusb2: unregistering device video%d [%s]\n",
- dip->devbase.minor,pvr2_config_get_name(dip->config));
+ int minor_id = dip->devbase.minor;
+ struct pvr2_hdw *hdw = dip->v4lp->channel.mc_head->hdw;
+ enum pvr2_config cfg = dip->config;
+ int v4l_type = dip->v4l_type;
+
+ pvr2_hdw_v4l_store_minor_number(hdw,dip->minor_type,-1);
/* Paranoia */
dip->v4lp = NULL;
@@ -717,13 +798,24 @@ static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip)
/* Actual deallocation happens later when all internal references
are gone. */
video_unregister_device(&dip->devbase);
+
+ printk(KERN_INFO "pvrusb2: unregistered device %s%u [%s]\n",
+ get_v4l_name(v4l_type),minor_id & 0x1f,
+ pvr2_config_get_name(cfg));
+
}
static void pvr2_v4l2_destroy_no_lock(struct pvr2_v4l2 *vp)
{
- pvr2_hdw_v4l_store_minor_number(vp->channel.mc_head->hdw,-1);
- pvr2_v4l2_dev_destroy(vp->vdev);
+ if (vp->dev_video) {
+ pvr2_v4l2_dev_destroy(vp->dev_video);
+ vp->dev_video = NULL;
+ }
+ if (vp->dev_radio) {
+ pvr2_v4l2_dev_destroy(vp->dev_radio);
+ vp->dev_radio = NULL;
+ }
pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr2_v4l2 id=%p",vp);
pvr2_channel_done(&vp->channel);
@@ -766,23 +858,37 @@ static int pvr2_v4l2_release(struct inode *inode, struct file *file)
struct pvr2_v4l2_fh *fhp = file->private_data;
struct pvr2_v4l2 *vp = fhp->vhead;
struct pvr2_context *mp = fhp->vhead->channel.mc_head;
+ struct pvr2_hdw *hdw = fhp->channel.mc_head->hdw;
pvr2_trace(PVR2_TRACE_OPEN_CLOSE,"pvr2_v4l2_release");
if (fhp->rhp) {
struct pvr2_stream *sp;
- struct pvr2_hdw *hdw;
- hdw = fhp->channel.mc_head->hdw;
pvr2_hdw_set_streaming(hdw,0);
sp = pvr2_ioread_get_stream(fhp->rhp);
if (sp) pvr2_stream_set_callback(sp,NULL,NULL);
pvr2_ioread_destroy(fhp->rhp);
fhp->rhp = NULL;
}
+
v4l2_prio_close(&vp->prio, &fhp->prio);
file->private_data = NULL;
pvr2_context_enter(mp); do {
+ /* Restore the previous input selection, if it makes sense
+ to do so. */
+ if (fhp->dev_info->v4l_type == VFL_TYPE_RADIO) {
+ struct pvr2_ctrl *cp;
+ int pval;
+ cp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
+ pvr2_ctrl_get_value(cp,&pval);
+ /* Only restore if we're still selecting the radio */
+ if (pval == PVR2_CVAL_INPUT_RADIO) {
+ pvr2_ctrl_set_value(cp,fhp->prev_input_val);
+ pvr2_hdw_commit_ctl(hdw);
+ }
+ }
+
if (fhp->vnext) {
fhp->vnext->vprev = fhp->vprev;
} else {
@@ -828,11 +934,10 @@ static int pvr2_v4l2_open(struct inode *inode, struct file *file)
return -EIO;
}
- fhp = kmalloc(sizeof(*fhp),GFP_KERNEL);
+ fhp = kzalloc(sizeof(*fhp),GFP_KERNEL);
if (!fhp) {
return -ENOMEM;
}
- memset(fhp,0,sizeof(*fhp));
init_waitqueue_head(&fhp->wait_data);
fhp->dev_info = dip;
@@ -840,6 +945,7 @@ static int pvr2_v4l2_open(struct inode *inode, struct file *file)
pvr2_context_enter(vp->channel.mc_head); do {
pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr_v4l2_fh id=%p",fhp);
pvr2_channel_init(&fhp->channel,vp->channel.mc_head);
+
fhp->vnext = NULL;
fhp->vprev = vp->vlast;
if (vp->vlast) {
@@ -849,6 +955,18 @@ static int pvr2_v4l2_open(struct inode *inode, struct file *file)
}
vp->vlast = fhp;
fhp->vhead = vp;
+
+ /* Opening the /dev/radioX device implies a mode switch.
+ So execute that here. Note that you can get the
+ IDENTICAL effect merely by opening the normal video
+ device and setting the input appropriately. */
+ if (dip->v4l_type == VFL_TYPE_RADIO) {
+ struct pvr2_ctrl *cp;
+ cp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
+ pvr2_ctrl_get_value(cp,&fhp->prev_input_val);
+ pvr2_ctrl_set_value(cp,PVR2_CVAL_INPUT_RADIO);
+ pvr2_hdw_commit_ctl(hdw);
+ }
} while (0); pvr2_context_exit(vp->channel.mc_head);
fhp->file = file;
@@ -873,6 +991,12 @@ static int pvr2_v4l2_iosetup(struct pvr2_v4l2_fh *fh)
struct pvr2_hdw *hdw;
if (fh->rhp) return 0;
+ if (!fh->dev_info->stream) {
+ /* No stream defined for this node. This means that we're
+ not currently allowed to stream from this node. */
+ return -EPERM;
+ }
+
/* First read() attempt. Try to claim the stream and start
it... */
if ((ret = pvr2_channel_claim_stream(&fh->channel,
@@ -1012,25 +1136,37 @@ static struct video_device vdev_template = {
static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
struct pvr2_v4l2 *vp,
- enum pvr2_config cfg)
+ int v4l_type)
{
int mindevnum;
int unit_number;
- int v4l_type;
+ int *nr_ptr = NULL;
dip->v4lp = vp;
- dip->config = cfg;
- switch (cfg) {
- case pvr2_config_mpeg:
- v4l_type = VFL_TYPE_GRABBER;
+ dip->v4l_type = v4l_type;
+ switch (v4l_type) {
+ case VFL_TYPE_GRABBER:
dip->stream = &vp->channel.mc_head->video_stream;
+ dip->config = pvr2_config_mpeg;
+ dip->minor_type = pvr2_v4l_type_video;
+ nr_ptr = video_nr;
+ if (!dip->stream) {
+ err("Failed to set up pvrusb2 v4l video dev"
+ " due to missing stream instance");
+ return;
+ }
break;
- case pvr2_config_vbi:
- v4l_type = VFL_TYPE_VBI;
+ case VFL_TYPE_VBI:
+ dip->config = pvr2_config_vbi;
+ dip->minor_type = pvr2_v4l_type_vbi;
+ nr_ptr = vbi_nr;
break;
- case pvr2_config_radio:
- v4l_type = VFL_TYPE_RADIO;
+ case VFL_TYPE_RADIO:
+ dip->stream = &vp->channel.mc_head->video_stream;
+ dip->config = pvr2_config_mpeg;
+ dip->minor_type = pvr2_v4l_type_radio;
+ nr_ptr = radio_nr;
break;
default:
/* Bail out (this should be impossible) */
@@ -1039,30 +1175,27 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
return;
}
- if (!dip->stream) {
- err("Failed to set up pvrusb2 v4l dev"
- " due to missing stream instance");
- return;
- }
-
memcpy(&dip->devbase,&vdev_template,sizeof(vdev_template));
dip->devbase.release = pvr2_video_device_release;
mindevnum = -1;
unit_number = pvr2_hdw_get_unit_number(vp->channel.mc_head->hdw);
- if ((unit_number >= 0) && (unit_number < PVR_NUM)) {
- mindevnum = video_nr[unit_number];
+ if (nr_ptr && (unit_number >= 0) && (unit_number < PVR_NUM)) {
+ mindevnum = nr_ptr[unit_number];
}
- if ((video_register_device(&dip->devbase, v4l_type, mindevnum) < 0) &&
- (video_register_device(&dip->devbase, v4l_type, -1) < 0)) {
- err("Failed to register pvrusb2 v4l video device");
- } else {
- printk(KERN_INFO "pvrusb2: registered device video%d [%s]\n",
- dip->devbase.minor,pvr2_config_get_name(dip->config));
+ if ((video_register_device(&dip->devbase,
+ dip->v4l_type, mindevnum) < 0) &&
+ (video_register_device(&dip->devbase,
+ dip->v4l_type, -1) < 0)) {
+ err("Failed to register pvrusb2 v4l device");
}
+ printk(KERN_INFO "pvrusb2: registered device %s%u [%s]\n",
+ get_v4l_name(dip->v4l_type),dip->devbase.minor & 0x1f,
+ pvr2_config_get_name(dip->config));
+
pvr2_hdw_v4l_store_minor_number(vp->channel.mc_head->hdw,
- dip->devbase.minor);
+ dip->minor_type,dip->devbase.minor);
}
@@ -1070,22 +1203,24 @@ struct pvr2_v4l2 *pvr2_v4l2_create(struct pvr2_context *mnp)
{
struct pvr2_v4l2 *vp;
- vp = kmalloc(sizeof(*vp),GFP_KERNEL);
+ vp = kzalloc(sizeof(*vp),GFP_KERNEL);
if (!vp) return vp;
- memset(vp,0,sizeof(*vp));
- vp->vdev = kmalloc(sizeof(*vp->vdev),GFP_KERNEL);
- if (!vp->vdev) {
+ vp->dev_video = kzalloc(sizeof(*vp->dev_video),GFP_KERNEL);
+ vp->dev_radio = kzalloc(sizeof(*vp->dev_radio),GFP_KERNEL);
+ if (!(vp->dev_video && vp->dev_radio)) {
+ kfree(vp->dev_video);
+ kfree(vp->dev_radio);
kfree(vp);
return NULL;
}
- memset(vp->vdev,0,sizeof(*vp->vdev));
pvr2_channel_init(&vp->channel,mnp);
pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr2_v4l2 id=%p",vp);
vp->channel.check_func = pvr2_v4l2_internal_check;
/* register streams */
- pvr2_v4l2_dev_init(vp->vdev,vp,pvr2_config_mpeg);
+ pvr2_v4l2_dev_init(vp->dev_video,vp,VFL_TYPE_GRABBER);
+ pvr2_v4l2_dev_init(vp->dev_radio,vp,VFL_TYPE_RADIO);
return vp;
}
diff --git a/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c b/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c
index 05f2cddeb47b..61efa6f02200 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c
@@ -66,7 +66,9 @@ static void set_input(struct pvr2_v4l_decoder *ctxt)
route.input = SAA7115_SVIDEO2;
break;
case PVR2_CVAL_INPUT_RADIO:
- // ????? No idea yet what to do here
+ // In radio mode, we mute the video, but point at one
+ // spot just to stay consistent
+ route.input = SAA7115_COMPOSITE5;
default:
return;
}
@@ -137,8 +139,7 @@ static int decoder_check(struct pvr2_v4l_decoder *ctxt)
unsigned long msk;
unsigned int idx;
- for (idx = 0; idx < sizeof(decoder_ops)/sizeof(decoder_ops[0]);
- idx++) {
+ for (idx = 0; idx < ARRAY_SIZE(decoder_ops); idx++) {
msk = 1 << idx;
if (ctxt->stale_mask & msk) continue;
if (decoder_ops[idx].check(ctxt)) {
@@ -154,8 +155,7 @@ static void decoder_update(struct pvr2_v4l_decoder *ctxt)
unsigned long msk;
unsigned int idx;
- for (idx = 0; idx < sizeof(decoder_ops)/sizeof(decoder_ops[0]);
- idx++) {
+ for (idx = 0; idx < ARRAY_SIZE(decoder_ops); idx++) {
msk = 1 << idx;
if (!(ctxt->stale_mask & msk)) continue;
ctxt->stale_mask &= ~msk;
@@ -183,25 +183,13 @@ static void decoder_enable(struct pvr2_v4l_decoder *ctxt,int fl)
}
-static int decoder_is_tuned(struct pvr2_v4l_decoder *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_decoder *ctxt,char *buf,unsigned int cnt)
{
return scnprintf(buf,cnt,"handler: pvrusb2-video-v4l");
}
-const static struct pvr2_i2c_handler_functions hfuncs = {
+static const struct pvr2_i2c_handler_functions hfuncs = {
.detach = (void (*)(void *))decoder_detach,
.check = (int (*)(void *))decoder_check,
.update = (void (*)(void *))decoder_update,
@@ -218,20 +206,17 @@ int pvr2_i2c_decoder_v4l_setup(struct pvr2_hdw *hdw,
if (cp->handler) return 0;
if (!decoder_detect(cp)) return 0;
- ctxt = kmalloc(sizeof(*ctxt),GFP_KERNEL);
+ ctxt = kzalloc(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->client = cp;
ctxt->hdw = hdw;
- ctxt->stale_mask = (1 << (sizeof(decoder_ops)/
- sizeof(decoder_ops[0]))) - 1;
+ ctxt->stale_mask = (1 << ARRAY_SIZE(decoder_ops)) - 1;
hdw->decoder_ctrl = &ctxt->ctrl;
cp->handler = &ctxt->handler;
pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x saa711x V4L2 handler set up",
diff --git a/drivers/media/video/pvrusb2/pvrusb2-wm8775.c b/drivers/media/video/pvrusb2/pvrusb2-wm8775.c
index 2413e5198e16..66b4d36ef765 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-wm8775.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-wm8775.c
@@ -50,15 +50,21 @@ 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);
+ switch(hdw->input_val) {
+ case PVR2_CVAL_INPUT_RADIO:
+ route.input = 1;
+ break;
+ default:
+ /* All other cases just use the second input */
+ route.input = 2;
+ break;
+ }
+ pvr2_trace(PVR2_TRACE_CHIPS,"i2c wm8775 set_input(val=%d route=0x%x)",
+ hdw->input_val,route.input);
- // Always point to input #1 no matter what
- route.input = 2;
pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_S_AUDIO_ROUTING,&route);
}
@@ -99,8 +105,7 @@ 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++) {
+ for (idx = 0; idx < ARRAY_SIZE(wm8775_ops); idx++) {
msk = 1 << idx;
if (ctxt->stale_mask & msk) continue;
if (wm8775_ops[idx].check(ctxt)) {
@@ -116,8 +121,7 @@ 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++) {
+ for (idx = 0; idx < ARRAY_SIZE(wm8775_ops); idx++) {
msk = 1 << idx;
if (!(ctxt->stale_mask & msk)) continue;
ctxt->stale_mask &= ~msk;
@@ -126,7 +130,7 @@ static void wm8775_update(struct pvr2_v4l_wm8775 *ctxt)
}
-const static struct pvr2_i2c_handler_functions hfuncs = {
+static const struct pvr2_i2c_handler_functions hfuncs = {
.detach = (void (*)(void *))wm8775_detach,
.check = (int (*)(void *))wm8775_check,
.update = (void (*)(void *))wm8775_update,
@@ -140,16 +144,14 @@ int pvr2_i2c_wm8775_setup(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp)
if (cp->handler) return 0;
- ctxt = kmalloc(sizeof(*ctxt),GFP_KERNEL);
+ ctxt = kzalloc(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;
+ ctxt->stale_mask = (1 << ARRAY_SIZE(wm8775_ops)) - 1;
cp->handler = &ctxt->handler;
pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x wm8775 V4L2 handler set up",
cp->client->addr);