summaryrefslogtreecommitdiff
path: root/v4l_experimental/pvrusb2/pvrusb2-audio.c
diff options
context:
space:
mode:
Diffstat (limited to 'v4l_experimental/pvrusb2/pvrusb2-audio.c')
-rw-r--r--v4l_experimental/pvrusb2/pvrusb2-audio.c200
1 files changed, 108 insertions, 92 deletions
diff --git a/v4l_experimental/pvrusb2/pvrusb2-audio.c b/v4l_experimental/pvrusb2/pvrusb2-audio.c
index 8ba8827be..81408e1a6 100644
--- a/v4l_experimental/pvrusb2/pvrusb2-audio.c
+++ b/v4l_experimental/pvrusb2/pvrusb2-audio.c
@@ -1,6 +1,6 @@
/*
*
- * $Id: pvrusb2-audio.c,v 1.2 2005/11/29 14:10:44 mchehab Exp $
+ * $Id: pvrusb2-audio.c,v 1.3 2006/01/01 08:26:03 mcisely Exp $
*
* Copyright (C) 2005 Mike Isely <isely@pobox.com>
* Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
@@ -20,7 +20,6 @@
*
*/
-#include "pvrusb2-i2c.h"
#include "pvrusb2-audio.h"
#include "pvrusb2-hdw-internal.h"
#include "pvrusb2-debug.h"
@@ -28,6 +27,15 @@
#include <linux/videodev.h>
#include <media/audiochip.h>
+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;
+};
+
+
/*
MCI <isely@pobox.com> 10-Mar-2005 - Rather than operate the msp34xx
@@ -60,48 +68,22 @@ static int xlat_audiomode_to_v4l2(int id)
return V4L2_TUNER_MODE_STEREO;
}
-/* Relay the video standard into the msp3400 module so that it can use
- that information as additional clue(s) for correctly detecting
- audio. */
-int pvr2_audio_set_standard(struct pvr2_hdw *hdw)
-{
- struct video_channel vc;
- memset(&vc,0,sizeof(vc));
- switch (hdw->controls[PVR2_CID_VIDEOSTANDARD].value) {
- default:
- case PVR2_CVAL_VIDEOSTANDARD_NTSC_M:
- case PVR2_CVAL_VIDEOSTANDARD_PAL_M: /* Hack */
- vc.norm = VIDEO_MODE_NTSC;
- break;
- case PVR2_CVAL_VIDEOSTANDARD_SECAM_L:
- vc.norm = VIDEO_MODE_SECAM;
- break;
- case PVR2_CVAL_VIDEOSTANDARD_PAL_BG:
- case PVR2_CVAL_VIDEOSTANDARD_PAL_I:
- case PVR2_CVAL_VIDEOSTANDARD_PAL_DK:
- vc.norm = VIDEO_MODE_PAL;
- break;
- }
- hdw->subsys_enabled_mask |= PVR2_SUBSYS_AUDIO_CFG_STD;
- return pvr2_i2c_msp3400_cmd(hdw,VIDIOCSCHAN,&vc);
-}
/* This function selects the correct audio input source */
-int pvr2_audio_set_stereo(struct pvr2_hdw *hdw)
+static void set_stereo(struct pvr2_msp3400_handler *ctxt)
{
- int stat;
+ struct pvr2_hdw *hdw = ctxt->hdw;
unsigned short sarg = 0;
struct msp_matrix mspm;
- pvr2_trace(PVR2_TRACE_AUDIO,"pvr_audio_set_stereo");
+ pvr2_trace(PVR2_TRACE_CHIPS,"i2c msp3400 set_stereo");
if (hdw->controls[PVR2_CID_INPUT].value == PVR2_CVAL_INPUT_TV) {
struct v4l2_tuner vt;
memset(&vt,0,sizeof(vt));
vt.audmode = xlat_audiomode_to_v4l2(
hdw->controls[PVR2_CID_AUDIOMODE].value);
- stat = pvr2_i2c_msp3400_cmd(hdw,VIDIOC_S_TUNER,&vt);
- if (stat < 0) return stat;
+ pvr2_i2c_client_cmd(ctxt->client,VIDIOC_S_TUNER,&vt);
}
sarg = AUDIO_TUNER;
@@ -119,8 +101,7 @@ int pvr2_audio_set_stereo(struct pvr2_hdw *hdw)
sarg = AUDIO_EXTERN;
break;
}
- stat = pvr2_i2c_msp3400_cmd(hdw,AUDC_SET_INPUT,&sarg);
- if (stat < 0) return stat;
+ pvr2_i2c_client_cmd(ctxt->client,AUDC_SET_INPUT,&sarg);
/* The above should have been enough to do the job, however
msp3400.ko does an incomplete job of handling the scart
@@ -144,82 +125,117 @@ int pvr2_audio_set_stereo(struct pvr2_hdw *hdw)
break;
}
mspm.output = 1;
- stat = pvr2_i2c_msp3400_cmd(hdw,MSP_SET_MATRIX,&mspm);
- if (stat < 0) return stat;
+ pvr2_i2c_client_cmd(ctxt->client,MSP_SET_MATRIX,&mspm);
+}
- hdw->subsys_enabled_mask |= PVR2_SUBSYS_AUDIO_CFG_MODE;
- return 0;
+static int check_stereo(struct pvr2_msp3400_handler *ctxt)
+{
+ struct pvr2_hdw *hdw = ctxt->hdw;
+ return hdw->controls[PVR2_CID_INPUT].dirty != 0;
}
-/* This sets the audio volume parameters */
-int pvr2_audio_setvolume(struct pvr2_hdw *hdw)
+
+struct pvr2_msp3400_ops {
+ void (*update)(struct pvr2_msp3400_handler *);
+ int (*check)(struct pvr2_msp3400_handler *);
+};
+
+
+static const struct pvr2_msp3400_ops msp3400_ops[] = {
+ { .update = set_stereo, .check = check_stereo},
+};
+
+
+static int msp3400_check(struct pvr2_msp3400_handler *ctxt)
{
- struct video_audio vt;
- memset(&vt,0,sizeof(vt));
- vt.flags = (VIDEO_AUDIO_VOLUME |
- VIDEO_AUDIO_BALANCE |
- VIDEO_AUDIO_BASS |
- VIDEO_AUDIO_TREBLE |
- VIDEO_AUDIO_MUTABLE);
- if (hdw->controls[PVR2_CID_MUTE].value) vt.flags |= VIDEO_AUDIO_MUTE;
- vt.volume = hdw->controls[PVR2_CID_VOLUME].value;
- vt.balance = hdw->controls[PVR2_CID_BALANCE].value;
- vt.bass = hdw->controls[PVR2_CID_BASS].value;
- vt.treble = hdw->controls[PVR2_CID_TREBLE].value;
- pvr2_trace(PVR2_TRACE_AUDIO,
- "pvr_audio_setvolume(vol=%d bal=%d bas=%d treb=%d mute=%d)",
- vt.volume,vt.balance,vt.bass,vt.treble,
- (vt.flags & VIDEO_AUDIO_MUTE) != 0);
-
- hdw->subsys_enabled_mask |= PVR2_SUBSYS_AUDIO_CFG_VBBTM;
-
- return pvr2_i2c_msp3400_cmd(hdw,VIDIOCSAUDIO,&vt);
+ unsigned long msk;
+ unsigned int idx;
+
+ for (idx = 0; idx < sizeof(msp3400_ops)/sizeof(msp3400_ops[0]);
+ idx++) {
+ msk = 1 << idx;
+ if (ctxt->stale_mask & msk) continue;
+ if (msp3400_ops[idx].check(ctxt)) {
+ ctxt->stale_mask |= msk;
+ }
+ }
+ return ctxt->stale_mask != 0;
}
+
+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++) {
+ msk = 1 << idx;
+ if (!(ctxt->stale_mask & msk)) continue;
+ ctxt->stale_mask &= ~msk;
+ msp3400_ops[idx].update(ctxt);
+ }
+}
+
+
/* This reads back the current volume parameters and signal type */
-int pvr2_audio_update_status(struct pvr2_hdw *hdw)
+static int get_audio_status(struct pvr2_msp3400_handler *ctxt)
{
struct video_audio vt;
int stat;
- stat = pvr2_i2c_msp3400_cmd(hdw,VIDIOCGAUDIO,&vt);
+ memset(&vt,0,sizeof(vt));
+ stat = pvr2_i2c_client_cmd(ctxt->client,VIDIOCGAUDIO,&vt);
if (stat < 0) return stat;
-#ifdef notdef
- if (vt.flags & VIDEO_AUDIO_MUTABLE) {
- hdw->controls[PVR2_CID_MUTE].value =
- (vt.flags & VIDEO_AUDIO_MUTE) ? 1 : 0;
- }
- if (vt.flags & VIDEO_AUDIO_VOLUME) {
- pvr2_trace(PVR2_TRACE_AUDIO,
- "pvr_audio_update_status: got volume");
- hdw->controls[PVR2_CID_VOLUME].value = vt.volume;
- }
- if (vt.flags & VIDEO_AUDIO_BASS) {
- pvr2_trace(PVR2_TRACE_AUDIO,
- "pvr_audio_update_status: got bass");
- hdw->controls[PVR2_CID_BASS].value = vt.bass;
- }
- if (vt.flags & VIDEO_AUDIO_TREBLE) {
- pvr2_trace(PVR2_TRACE_AUDIO,
- "pvr_audio_update_status: got treble");
- hdw->controls[PVR2_CID_TREBLE].value = vt.treble;
- }
- if (vt.flags & (VIDEO_AUDIO_BALANCE|VIDEO_AUDIO_VOLUME)) {
- pvr2_trace(PVR2_TRACE_AUDIO,
- "pvr_audio_update_status: got balance");
- hdw->controls[PVR2_CID_BALANCE].value = vt.balance;
- }
-#endif
-
- hdw->flag_stereo = (vt.mode & VIDEO_SOUND_STEREO) != 0;
- hdw->flag_bilingual = (vt.mode &
- (VIDEO_SOUND_LANG1|VIDEO_SOUND_LANG2)) != 0;
+ ctxt->hdw->flag_stereo = (vt.mode & VIDEO_SOUND_STEREO) != 0;
+ ctxt->hdw->flag_bilingual =
+ (vt.mode & (VIDEO_SOUND_LANG1|VIDEO_SOUND_LANG2)) != 0;
return 0;
}
+static void pvr2_msp3400_detach(struct pvr2_msp3400_handler *ctxt)
+{
+ ctxt->client->handler = 0;
+ ctxt->hdw->audio_stat = 0;
+ kfree(ctxt);
+}
+
+
+const static struct pvr2_i2c_handler_functions msp3400_funcs = {
+ .detach = (void (*)(void *))pvr2_msp3400_detach,
+ .check = (int (*)(void *))msp3400_check,
+ .update = (void (*)(void *))msp3400_update,
+};
+
+
+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);
+ 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);
+ cp->handler = &ctxt->i2c_handler;
+ hdw->audio_stat = &ctxt->astat;
+ return !0;
+}
+
+
/*
Stuff for Emacs to see, in order to encourage consistent editing style:
*** Local Variables: ***