summaryrefslogtreecommitdiff
path: root/drivers/media/video/mxb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/mxb.c')
-rw-r--r--drivers/media/video/mxb.c168
1 files changed, 91 insertions, 77 deletions
diff --git a/drivers/media/video/mxb.c b/drivers/media/video/mxb.c
index 8416ceff524b..b0aea4002d11 100644
--- a/drivers/media/video/mxb.c
+++ b/drivers/media/video/mxb.c
@@ -1,11 +1,11 @@
/*
mxb - v4l2 driver for the Multimedia eXtension Board
-
- Copyright (C) 1998-2003 Michael Hunold <michael@mihu.de>
+
+ Copyright (C) 1998-2006 Michael Hunold <michael@mihu.de>
Visit http://www.mihu.de/linux/saa7146/mxb/
for further details about this card.
-
+
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, or
@@ -35,12 +35,12 @@
#define I2C_SAA7111 0x24
-#define MXB_BOARD_CAN_DO_VBI(dev) (dev->revision != 0)
+#define MXB_BOARD_CAN_DO_VBI(dev) (dev->revision != 0)
/* global variable */
static int mxb_num = 0;
-/* initial frequence the tuner will be tuned to.
+/* initial frequence the tuner will be tuned to.
in verden (lower saxony, germany) 4148 is a
channel called "phoenix" */
static int freq = 4148;
@@ -55,7 +55,7 @@ MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off).");
enum { TUNER, AUX1, AUX3, AUX3_YC };
static struct v4l2_input mxb_inputs[MXB_INPUTS] = {
- { TUNER, "Tuner", V4L2_INPUT_TYPE_TUNER, 1, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
+ { TUNER, "Tuner", V4L2_INPUT_TYPE_TUNER, 1, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
{ AUX1, "AUX1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
{ AUX3, "AUX3 Composite", V4L2_INPUT_TYPE_CAMERA, 4, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
{ AUX3_YC, "AUX3 S-Video", V4L2_INPUT_TYPE_CAMERA, 4, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
@@ -66,7 +66,7 @@ static struct v4l2_input mxb_inputs[MXB_INPUTS] = {
static struct {
int hps_source;
int hps_sync;
-} input_port_selection[MXB_INPUTS] = {
+} input_port_selection[MXB_INPUTS] = {
{ SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A },
{ SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A },
{ SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A },
@@ -81,7 +81,7 @@ static int video_audio_connect[MXB_INPUTS] =
/* these are the necessary input-output-pins for bringing one audio source
(see above) to the CD-output */
static struct tea6420_multiplex TEA6420_cd[MXB_AUDIOS+1][2] =
- {
+ {
{{1,1,0},{1,1,0}}, /* Tuner */
{{5,1,0},{6,1,0}}, /* AUX 1 */
{{4,1,0},{6,1,0}}, /* AUX 2 */
@@ -122,8 +122,8 @@ static struct saa7146_extension_ioctls ioctls[] = {
{ VIDIOC_S_FREQUENCY, SAA7146_EXCLUSIVE },
{ VIDIOC_G_AUDIO, SAA7146_EXCLUSIVE },
{ VIDIOC_S_AUDIO, SAA7146_EXCLUSIVE },
- { MXB_S_AUDIO_CD, SAA7146_EXCLUSIVE }, /* custom control */
- { MXB_S_AUDIO_LINE, SAA7146_EXCLUSIVE }, /* custom control */
+ { MXB_S_AUDIO_CD, SAA7146_EXCLUSIVE }, /* custom control */
+ { MXB_S_AUDIO_LINE, SAA7146_EXCLUSIVE }, /* custom control */
{ 0, 0 }
};
@@ -132,7 +132,7 @@ struct mxb
struct video_device *video_dev;
struct video_device *vbi_dev;
- struct i2c_adapter i2c_adapter;
+ struct i2c_adapter i2c_adapter;
struct i2c_client* saa7111a;
struct i2c_client* tda9840;
@@ -198,17 +198,17 @@ static int mxb_probe(struct saa7146_dev* dev)
/* loop through all i2c-devices on the bus and look who is there */
list_for_each(item,&mxb->i2c_adapter.clients) {
client = list_entry(item, struct i2c_client, list);
- if( I2C_TEA6420_1 == client->addr )
+ if( I2C_ADDR_TEA6420_1 == client->addr )
mxb->tea6420_1 = client;
- if( I2C_TEA6420_2 == client->addr )
+ if( I2C_ADDR_TEA6420_2 == client->addr )
mxb->tea6420_2 = client;
- if( I2C_TEA6415C_2 == client->addr )
+ if( I2C_TEA6415C_2 == client->addr )
mxb->tea6415c = client;
- if( I2C_TDA9840 == client->addr )
+ if( I2C_ADDR_TDA9840 == client->addr )
mxb->tda9840 = client;
if( I2C_SAA7111 == client->addr )
mxb->saa7111a = client;
- if( 0x60 == client->addr )
+ if( 0x60 == client->addr )
mxb->tuner = client;
}
@@ -222,7 +222,7 @@ static int mxb_probe(struct saa7146_dev* dev)
return -ENODEV;
}
- /* all devices are present, probe was successful */
+ /* all devices are present, probe was successful */
/* we store the pointer in our private data field */
dev->ext_priv = mxb;
@@ -230,7 +230,7 @@ static int mxb_probe(struct saa7146_dev* dev)
return 0;
}
-/* some init data for the saa7740, the so-called 'sound arena module'.
+/* some init data for the saa7740, the so-called 'sound arena module'.
there are no specs available, so we simply use some init values */
static struct {
int length;
@@ -327,9 +327,10 @@ static int mxb_init_done(struct saa7146_dev* dev)
struct video_decoder_init init;
struct i2c_msg msg;
struct tuner_setup tun_setup;
+ v4l2_std_id std = V4L2_STD_PAL_BG;
int i = 0, err = 0;
- struct tea6415c_multiplex vm;
+ struct tea6415c_multiplex vm;
/* select video mode in saa7111a */
i = VIDEO_MODE_PAL;
@@ -361,6 +362,9 @@ static int mxb_init_done(struct saa7146_dev* dev)
mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_FREQUENCY,
&mxb->cur_freq);
+ /* set a default video standard */
+ mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
+
/* mute audio on tea6420s */
mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[6][0]);
mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[6][1]);
@@ -376,16 +380,16 @@ static int mxb_init_done(struct saa7146_dev* dev)
vm.in = 3;
vm.out = 13;
mxb->tea6415c->driver->command(mxb->tea6415c,TEA6415C_SWITCH, &vm);
-
+
/* the rest for mxb */
mxb->cur_input = 0;
mxb->cur_mute = 1;
mxb->cur_mode = V4L2_TUNER_MODE_STEREO;
mxb->tda9840->driver->command(mxb->tda9840, TDA9840_SWITCH, &mxb->cur_mode);
-
+
/* check if the saa7740 (aka 'sound arena module') is present
- on the mxb. if so, we must initialize it. due to lack of
+ on the mxb. if so, we must initialize it. due to lack of
informations about the saa7740, the values were reverse
engineered. */
msg.addr = 0x1b;
@@ -405,7 +409,7 @@ static int mxb_init_done(struct saa7146_dev* dev)
break;
}
- msg.len = mxb_saa7740_init[i].length;
+ msg.len = mxb_saa7740_init[i].length;
msg.buf = &mxb_saa7740_init[i].data[0];
if( 1 != (err = i2c_transfer(&mxb->i2c_adapter, &msg, 1))) {
DEB_D(("failed to initialize 'sound arena module'.\n"));
@@ -414,12 +418,12 @@ static int mxb_init_done(struct saa7146_dev* dev)
}
INFO(("'sound arena module' detected.\n"));
}
-err:
+err:
/* the rest for saa7146: you should definitely set some basic values
for the input-port handling of the saa7146. */
/* ext->saa has been filled by the core driver */
-
+
/* some stuff is done via variables */
saa7146_set_hps_source_and_sync(dev, input_port_selection[mxb->cur_input].hps_source, input_port_selection[mxb->cur_input].hps_sync);
@@ -427,7 +431,7 @@ err:
/* this is ugly, but because of the fact that this is completely
hardware dependend, it should be done directly... */
- saa7146_write(dev, DD1_STREAM_B, 0x00000000);
+ saa7146_write(dev, DD1_STREAM_B, 0x00000000);
saa7146_write(dev, DD1_INIT, 0x02000200);
saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
@@ -449,7 +453,7 @@ static struct saa7146_ext_vv vv_data;
static int mxb_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_data *info)
{
struct mxb* mxb = (struct mxb*)dev->ext_priv;
-
+
DEB_EE(("dev:%p\n",dev));
/* checking for i2c-devices can be omitted here, because we
@@ -460,7 +464,7 @@ static int mxb_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_data
ERR(("cannot register capture v4l2 device. skipping.\n"));
return -1;
}
-
+
/* initialization stuff (vbi) (only for revision > 0 and for extensions which want it)*/
if( 0 != MXB_BOARD_CAN_DO_VBI(dev)) {
if( 0 != saa7146_register_device(&mxb->vbi_dev, dev, "mxb", VFL_TYPE_VBI)) {
@@ -509,17 +513,17 @@ static int mxb_detach(struct saa7146_dev* dev)
return 0;
}
-static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
+static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
{
struct saa7146_dev *dev = fh->dev;
struct mxb* mxb = (struct mxb*)dev->ext_priv;
- struct saa7146_vv *vv = dev->vv_data;
-
+ struct saa7146_vv *vv = dev->vv_data;
+
switch(cmd) {
case VIDIOC_ENUMINPUT:
{
struct v4l2_input *i = arg;
-
+
DEB_EE(("VIDIOC_ENUMINPUT %d.\n",i->index));
if( i->index < 0 || i->index >= MXB_INPUTS) {
return -EINVAL;
@@ -555,11 +559,11 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
break;
}
}
-
+
if( i < 0 ) {
return -EAGAIN;
}
-
+
switch (vc->id ) {
case V4L2_CID_AUDIO_MUTE: {
vc->value = mxb->cur_mute;
@@ -567,7 +571,7 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
return 0;
}
}
-
+
DEB_EE(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n",vc->value));
return 0;
}
@@ -576,17 +580,17 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
{
struct v4l2_control *vc = arg;
int i = 0;
-
+
for (i = MAXCONTROLS - 1; i >= 0; i--) {
if (mxb_controls[i].id == vc->id) {
break;
}
}
-
+
if( i < 0 ) {
return -EAGAIN;
}
-
+
switch (vc->id ) {
case V4L2_CID_AUDIO_MUTE: {
mxb->cur_mute = vc->value;
@@ -610,12 +614,12 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
*input = mxb->cur_input;
DEB_EE(("VIDIOC_G_INPUT %d.\n",*input));
- return 0;
- }
+ return 0;
+ }
case VIDIOC_S_INPUT:
{
int input = *(int *)arg;
- struct tea6415c_multiplex vm;
+ struct tea6415c_multiplex vm;
int i = 0;
DEB_EE(("VIDIOC_S_INPUT %d.\n",input));
@@ -623,34 +627,34 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
if (input < 0 || input >= MXB_INPUTS) {
return -EINVAL;
}
-
+
/* fixme: locke das setzen des inputs mit hilfe des mutexes
- down(&dev->lock);
+ mutex_lock(&dev->lock);
video_mux(dev,*i);
- up(&dev->lock);
+ mutex_unlock(&dev->lock);
*/
-
+
/* fixme: check if streaming capture
if ( 0 != dev->streaming ) {
DEB_D(("VIDIOC_S_INPUT illegal while streaming.\n"));
return -EPERM;
}
*/
-
+
mxb->cur_input = input;
-
+
saa7146_set_hps_source_and_sync(dev, input_port_selection[input].hps_source, input_port_selection[input].hps_sync);
-
+
/* prepare switching of tea6415c and saa7111a;
have a look at the 'background'-file for further informations */
switch( input ) {
-
+
case TUNER:
{
i = 0;
vm.in = 3;
vm.out = 17;
-
+
if ( 0 != mxb->tea6415c->driver->command(mxb->tea6415c,TEA6415C_SWITCH, &vm)) {
printk("VIDIOC_S_INPUT: could not address tea6415c #1\n");
return -EFAULT;
@@ -658,7 +662,7 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
/* connect tuner-output always to multicable */
vm.in = 3;
vm.out = 13;
- break;
+ break;
}
case AUX3_YC:
{
@@ -699,11 +703,11 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
break;
}
}
-
+
/* switch video in saa7111a */
if ( 0 != mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_INPUT, &i)) {
printk("VIDIOC_S_INPUT: could not address saa7111a #1.\n");
- }
+ }
/* switch the audio-source only if necessary */
if( 0 == mxb->cur_mute ) {
@@ -734,11 +738,11 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
t->rangehigh = 13684; /* 855.25 MHz / 62.5 kHz = 13684 */
/* FIXME: add the real signal strength here */
t->signal = 0xffff;
- t->afc = 0;
+ t->afc = 0;
mxb->tda9840->driver->command(mxb->tda9840,TDA9840_DETECT, &byte);
t->audmode = mxb->cur_mode;
-
+
if( byte < 0 ) {
t->rxsubchans = V4L2_TUNER_SUB_MONO;
} else {
@@ -773,12 +777,12 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
struct v4l2_tuner *t = arg;
int result = 0;
int byte = 0;
-
+
if( 0 != t->index ) {
DEB_D(("VIDIOC_S_TUNER: channel %d does not have a tuner attached.\n",t->index));
return -EINVAL;
}
-
+
switch(t->audmode) {
case V4L2_TUNER_MODE_STEREO: {
mxb->cur_mode = V4L2_TUNER_MODE_STEREO;
@@ -786,6 +790,12 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
DEB_D(("VIDIOC_S_TUNER: V4L2_TUNER_MODE_STEREO\n"));
break;
}
+ case V4L2_TUNER_MODE_LANG1_LANG2: {
+ mxb->cur_mode = V4L2_TUNER_MODE_LANG1_LANG2;
+ byte = TDA9840_SET_BOTH;
+ DEB_D(("VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1_LANG2\n"));
+ break;
+ }
case V4L2_TUNER_MODE_LANG1: {
mxb->cur_mode = V4L2_TUNER_MODE_LANG1;
byte = TDA9840_SET_LANG1;
@@ -809,7 +819,7 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
if( 0 != (result = mxb->tda9840->driver->command(mxb->tda9840, TDA9840_SWITCH, &byte))) {
printk("VIDIOC_S_TUNER error. result:%d, byte:%d\n",result,byte);
}
-
+
return 0;
}
case VIDIOC_G_FREQUENCY:
@@ -835,7 +845,7 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
if (V4L2_TUNER_ANALOG_TV != f->type)
return -EINVAL;
-
+
if(0 != mxb->cur_input) {
DEB_D(("VIDIOC_S_FREQ: channel %d does not have a tuner!\n",mxb->cur_input));
return -EINVAL;
@@ -844,7 +854,7 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
mxb->cur_freq = *f;
DEB_EE(("VIDIOC_S_FREQUENCY: freq:0x%08x.\n", mxb->cur_freq.frequency));
- /* tune in desired frequency */
+ /* tune in desired frequency */
mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_FREQUENCY, &mxb->cur_freq);
/* hack: changing the frequency should invalidate the vbi-counter (=> alevt) */
@@ -857,12 +867,12 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
case MXB_S_AUDIO_CD:
{
int i = *(int*)arg;
-
+
if( i < 0 || i >= MXB_AUDIOS ) {
DEB_D(("illegal argument to MXB_S_AUDIO_CD: i:%d.\n",i));
return -EINVAL;
}
-
+
DEB_EE(("MXB_S_AUDIO_CD: i:%d.\n",i));
mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_cd[i][0]);
@@ -873,12 +883,12 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
case MXB_S_AUDIO_LINE:
{
int i = *(int*)arg;
-
+
if( i < 0 || i >= MXB_AUDIOS ) {
DEB_D(("illegal argument to MXB_S_AUDIO_LINE: i:%d.\n",i));
return -EINVAL;
}
-
+
DEB_EE(("MXB_S_AUDIO_LINE: i:%d.\n",i));
mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[i][0]);
mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[i][1]);
@@ -890,13 +900,13 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
struct v4l2_audio *a = arg;
if( a->index < 0 || a->index > MXB_INPUTS ) {
- DEB_D(("VIDIOC_G_AUDIO %d out of range.\n",a->index));
+ DEB_D(("VIDIOC_G_AUDIO %d out of range.\n",a->index));
return -EINVAL;
}
-
- DEB_EE(("VIDIOC_G_AUDIO %d.\n",a->index));
+
+ DEB_EE(("VIDIOC_G_AUDIO %d.\n",a->index));
memcpy(a, &mxb_audios[video_audio_connect[mxb->cur_input]], sizeof(struct v4l2_audio));
-
+
return 0;
}
case VIDIOC_S_AUDIO:
@@ -904,7 +914,7 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
struct v4l2_audio *a = arg;
DEB_D(("VIDIOC_S_AUDIO %d.\n",a->index));
return 0;
- }
+ }
default:
/*
DEB2(printk("does not handle this ioctl.\n"));
@@ -921,17 +931,21 @@ static int std_callback(struct saa7146_dev* dev, struct saa7146_standard *std)
int one = 1;
if(V4L2_STD_PAL_I == std->id ) {
+ v4l2_std_id std = V4L2_STD_PAL_I;
DEB_D(("VIDIOC_S_STD: setting mxb for PAL_I.\n"));
/* set the 7146 gpio register -- I don't know what this does exactly */
- saa7146_write(dev, GPIO_CTRL, 0x00404050);
+ saa7146_write(dev, GPIO_CTRL, 0x00404050);
/* unset the 7111 gpio register -- I don't know what this does exactly */
mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_GPIO, &zero);
+ mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
} else {
+ v4l2_std_id std = V4L2_STD_PAL_BG;
DEB_D(("VIDIOC_S_STD: setting mxb for PAL/NTSC/SECAM.\n"));
/* set the 7146 gpio register -- I don't know what this does exactly */
- saa7146_write(dev, GPIO_CTRL, 0x00404050);
+ saa7146_write(dev, GPIO_CTRL, 0x00404050);
/* set the 7111 gpio register -- I don't know what this does exactly */
mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_GPIO, &one);
+ mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
}
return 0;
}
@@ -961,8 +975,8 @@ static struct saa7146_standard standard[] = {
};
static struct saa7146_pci_extension_data mxb = {
- .ext_priv = "Multimedia eXtension Board",
- .ext = &extension,
+ .ext_priv = "Multimedia eXtension Board",
+ .ext = &extension,
};
static struct pci_device_id pci_tbl[] = {
@@ -984,7 +998,7 @@ static struct saa7146_ext_vv vv_data = {
.capabilities = V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE,
.stds = &standard[0],
.num_stds = sizeof(standard)/sizeof(struct saa7146_standard),
- .std_callback = &std_callback,
+ .std_callback = &std_callback,
.ioctls = &ioctls[0],
.ioctl = mxb_ioctl,
};
@@ -992,7 +1006,7 @@ static struct saa7146_ext_vv vv_data = {
static struct saa7146_extension extension = {
.name = MXB_IDENTIFIER,
.flags = SAA7146_USE_I2C_IRQ,
-
+
.pci_tbl = &pci_tbl[0],
.module = THIS_MODULE,
@@ -1002,7 +1016,7 @@ static struct saa7146_extension extension = {
.irq_mask = 0,
.irq_func = NULL,
-};
+};
static int __init mxb_init_module(void)
{
@@ -1010,7 +1024,7 @@ static int __init mxb_init_module(void)
DEB_S(("failed to register extension.\n"));
return -ENODEV;
}
-
+
return 0;
}