summaryrefslogtreecommitdiff
path: root/linux/drivers/media/video/tuner-core.c
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <devnull@localhost>2005-06-28 03:17:39 +0000
committerMauro Carvalho Chehab <devnull@localhost>2005-06-28 03:17:39 +0000
commite4a3e5710f9d49095149a7ec54b295bfe177d456 (patch)
tree50af32dabd988f3bea79267013c0af6cd5552862 /linux/drivers/media/video/tuner-core.c
parent8864fa7428dae723f13f8cd22599f5b96986a843 (diff)
downloadmediapointer-dvb-s2-e4a3e5710f9d49095149a7ec54b295bfe177d456.tar.gz
mediapointer-dvb-s2-e4a3e5710f9d49095149a7ec54b295bfe177d456.tar.bz2
* cx88-i2c.c, cx88-video.c, saa7134-i2c.c, tuner-core.c, tuner.h:
- Improved support for multi tuners on multi boards. *tuner-core.c: - Pal M and PAL N added to tuner_fixup_std * tuner-simple.c: - Eliminated old tea code from tuner-simple. Signed-off-by: Mauro Carvalho Chehab <mchehab@brturbo.com.br>
Diffstat (limited to 'linux/drivers/media/video/tuner-core.c')
-rw-r--r--linux/drivers/media/video/tuner-core.c238
1 files changed, 135 insertions, 103 deletions
diff --git a/linux/drivers/media/video/tuner-core.c b/linux/drivers/media/video/tuner-core.c
index a5c3b6ab5..e6f0e2f4d 100644
--- a/linux/drivers/media/video/tuner-core.c
+++ b/linux/drivers/media/video/tuner-core.c
@@ -1,5 +1,5 @@
/*
- * $Id: tuner-core.c,v 1.29 2005/06/21 15:40:33 mchehab Exp $
+ * $Id: tuner-core.c,v 1.30 2005/06/28 03:17:39 mchehab Exp $
*
* i2c tv tuner chip device driver
* core core, i.e. kernel interfaces, registering and so on
@@ -66,9 +66,6 @@ MODULE_DESCRIPTION("device driver for various TV and TV+FM radio tuners");
MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer");
MODULE_LICENSE("GPL");
-static int this_adap;
-static unsigned short first_tuner, tv_tuner, radio_tuner;
-
static struct i2c_driver driver;
static struct i2c_client client_template;
@@ -140,7 +137,7 @@ static void set_freq(struct i2c_client *c, unsigned long freq)
t->freq = freq;
}
-static void set_type(struct i2c_client *c, unsigned int type)
+static void set_type(struct i2c_client *c, unsigned int type, enum tuner_admin_state new_admin_status)
{
struct tuner *t = i2c_get_clientdata(c);
unsigned char buffer[4];
@@ -156,12 +153,9 @@ static void set_type(struct i2c_client *c, unsigned int type)
t->type = type;
return;
}
- if ((t->initialized) && (t->type == type))
- /* run only once except type change Hac 04/05*/
+/* if ((t->admin_status==T_UNINITIALIZED) && (t->type == type))
return;
-
- t->initialized = 1;
-
+*/
t->type = type;
switch (t->type) {
case TUNER_MT2032:
@@ -171,11 +165,16 @@ static void set_type(struct i2c_client *c, unsigned int type)
tda8290_init(c);
break;
case TUNER_TEA5767:
- if (tea5767_tuner_init(c)==EINVAL) t->type=TUNER_ABSENT;
+ if (tea5767_tuner_init(c)==EINVAL) {
+ t->type = TUNER_ABSENT;
+ t->admin_status = T_UNINITIALIZED;
+ return;
+ }
+ t->admin_status = T_RADIO;
break;
case TUNER_PHILIPS_FMD1216ME_MK3:
- buffer[0] = 0x0b;
- buffer[1] = 0xdc;
+ buffer[0] = 0x0b;
+ buffer[1] = 0xdc;
buffer[2] = 0x9c;
buffer[3] = 0x60;
i2c_master_send(c,buffer,4);
@@ -186,55 +185,54 @@ static void set_type(struct i2c_client *c, unsigned int type)
default_tuner_init(c);
break;
default:
- /* TEA5767 autodetection code */
- if (tea5767_tuner_init(c)!=EINVAL) {
- t->type = TUNER_TEA5767;
- if (first_tuner == 0x60)
- first_tuner++;
- break;
- }
-
default_tuner_init(c);
break;
}
- tuner_dbg ("I2C addr 0x%02x with type %d\n",c->addr<<1,type);
-}
+ if (t->admin_status == T_UNINITIALIZED)
+ t->admin_status = new_admin_status;
-#define CHECK_ADDR(tp,cmd,tun) if (client->addr!=tp) { \
- return 0; } else if (tuner_debug) \
- tuner_info ("Cmd %s accepted to "tun"\n",cmd);
-#define CHECK_MODE(cmd) if (t->mode == V4L2_TUNER_RADIO) { \
- CHECK_ADDR(radio_tuner,cmd,"radio") } else \
- { CHECK_ADDR(tv_tuner,cmd,"TV"); }
+ tuner_dbg ("%s %s I2C addr 0x%02x with type %d used for 0x%02x\n",
+ c->adapter->name,c->driver->name,c->addr<<1,type,t->admin_status);
+}
static void set_addr(struct i2c_client *c, struct tuner_addr *tun_addr)
{
+ struct tuner *t = i2c_get_clientdata(c);
+ enum tuner_admin_state new_admin_status;
+
/* ADDR_UNSET defaults to first available tuner */
if ( tun_addr->addr == ADDR_UNSET ) {
- if (first_tuner != c->addr)
+ /* If no Address specifyed, accepts only if tuner is */
+ if ( !(t->admin_status & tun_addr->v4l2_tuner) )
return;
- switch (tun_addr->v4l2_tuner) {
- case V4L2_TUNER_RADIO:
- radio_tuner=c->addr;
- break;
- default:
- tv_tuner=c->addr;
- break;
- }
+ set_type(c,tun_addr->type,tun_addr->v4l2_tuner);
} else {
+ new_admin_status = tun_addr->v4l2_tuner;
+
/* Sets tuner to its configured value */
- switch (tun_addr->v4l2_tuner) {
- case V4L2_TUNER_RADIO:
- radio_tuner=tun_addr->addr;
- if ( tun_addr->addr == c->addr ) set_type(c,tun_addr->type);
- return;
- default:
- tv_tuner=tun_addr->addr;
- if ( tun_addr->addr == c->addr ) set_type(c,tun_addr->type);
- return;
+ if ( tun_addr->addr == c->addr ) set_type(c,tun_addr->type,new_admin_status);
+ }
+}
+
+static inline int check_mode (struct tuner *t,char *cmd)
+{
+ if (1<<t->mode & t->admin_status) {
+ if (tuner_debug) {
+ switch (t->type) {
+ case V4L2_TUNER_RADIO:
+ tuner_info ("Cmd %s accepted for radio\n",cmd);
+ break;
+ case V4L2_TUNER_ANALOG_TV:
+ tuner_info ("Cmd %s accepted for analog TV\n",cmd);
+ break;
+ case V4L2_TUNER_DIGITAL_TV:
+ tuner_info ("Cmd %s accepted for digital TV\n",cmd);
+ break;
+ }
}
+ return 0;
}
- set_type(c,tun_addr->type);
+ return EINVAL;
}
static char pal[] = "-";
@@ -264,6 +262,16 @@ static int tuner_fixup_std(struct tuner *t)
tuner_dbg("insmod fixup: PAL => PAL-DK\n");
t->std = V4L2_STD_PAL_DK;
break;
+ case 'M':
+ case 'm':
+ tuner_dbg("insmod fixup: PAL => PAL-M\n");
+ t->std = V4L2_STD_PAL_M;
+ break;
+ case 'N':
+ case 'n':
+ tuner_dbg("insmod fixup: PAL => PAL-N\n");
+ t->std = V4L2_STD_PAL_N;
+ break;
}
}
return 0;
@@ -271,18 +279,13 @@ static int tuner_fixup_std(struct tuner *t)
/* ---------------------------------------------------------------------- */
+/* static var Used only in tuner_attach and tuner_probe */
+static unsigned default_admin_status;
+
static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
{
struct tuner *t;
- /* by default, first I2C card is both tv and radio tuner */
- if (this_adap == 0) {
- first_tuner = addr;
- tv_tuner = addr;
- radio_tuner = addr;
- }
- this_adap++;
-
client_template.adapter = adap;
client_template.addr = addr;
@@ -292,15 +295,33 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
memset(t,0,sizeof(struct tuner));
memcpy(&t->i2c,&client_template,sizeof(struct i2c_client));
i2c_set_clientdata(&t->i2c, t);
- t->type = UNSET;
- t->radio_if2 = 10700*1000; /* 10.7MHz - FM radio */
- t->audmode = V4L2_TUNER_MODE_STEREO;
+ t->type = UNSET;
+ t->radio_if2 = 10700*1000; /* 10.7MHz - FM radio */
+ t->audmode = V4L2_TUNER_MODE_STEREO;
+ t->admin_status = T_UNINITIALIZED;
i2c_attach_client(&t->i2c);
tuner_info("chip found @ 0x%x (%s)\n",
addr << 1, adap->name);
-
- set_type(&t->i2c, t->type);
+
+ /* TEA5767 autodetection code - only for addr = 0xc0 */
+ if ( addr == 0x60) {
+ set_type(&t->i2c, TUNER_TEA5767 ,T_RADIO);
+ if (t->type==TUNER_TEA5767) {
+ t->type = TUNER_TEA5767;
+ t->admin_status = T_RADIO;
+ default_admin_status &= ~T_RADIO;
+ return 0;
+ }
+ }
+
+ /* Initializes only the first adapter found */
+ if (default_admin_status != T_UNINITIALIZED) {
+ tuner_dbg("admin to card = 0x%02x\n",default_admin_status);
+ t->admin_status = default_admin_status;
+ default_admin_status = T_UNINITIALIZED;
+ }
+
return 0;
}
@@ -310,11 +331,8 @@ static int tuner_probe(struct i2c_adapter *adap)
normal_i2c[0] = addr;
normal_i2c[1] = I2C_CLIENT_END;
}
- this_adap = 0;
- first_tuner = 0;
- tv_tuner = 0;
- radio_tuner = 0;
+ default_admin_status = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV;
if (adap->class & I2C_CLASS_TV_ANALOG)
return i2c_probe(adap, &addr_data, tuner_attach);
@@ -331,18 +349,25 @@ static int tuner_detach(struct i2c_client *client)
tuner_warn ("Client deregistration failed, client not detached.\n");
return err;
}
-
+
kfree(t);
return 0;
}
-#define SWITCH_V4L2 if (!t->using_v4l2 && tuner_debug) \
+#define switch_v4l2() if (!t->using_v4l2 && tuner_debug) \
tuner_info("switching to v4l2\n"); \
t->using_v4l2 = 1;
-#define CHECK_V4L2 if (t->using_v4l2) { if (tuner_debug) \
- tuner_info("ignore v4l1 call\n"); \
- return 0; }
-
+
+static inline int check_v4l2 (struct tuner *t)
+{
+ if (t->using_v4l2) {
+ if (tuner_debug)
+ tuner_info("ignore v4l1 call\n");
+ return EINVAL;
+ }
+ return 0;
+}
+
static int
tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
@@ -352,21 +377,21 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
switch (cmd) {
/* --- configuration --- */
case TUNER_SET_TYPE:
- set_type(client,*iarg);
+ set_type(client, *iarg,T_RADIO|T_ANALOG_TV|T_DIGITAL_TV);
break;
case TUNER_SET_TYPE_ADDR:
set_addr(client,(struct tuner_addr *)arg);
break;
case AUDC_SET_RADIO:
t->mode = V4L2_TUNER_RADIO;
- CHECK_ADDR(tv_tuner,"AUDC_SET_RADIO","TV");
-
+ if (check_mode(t,"AUDC_SET_RADIO")==EINVAL) return 0;
+
if (V4L2_TUNER_RADIO != t->mode) {
set_tv_freq(client,400 * 16);
}
break;
case AUDC_CONFIG_PINNACLE:
- CHECK_ADDR(tv_tuner,"AUDC_CONFIG_PINNACLE","TV");
+ if (check_mode(t,"AUDC_CONFIG_PINNACLE")==EINVAL) return 0;
switch (*iarg) {
case 2:
tuner_dbg("pinnacle pal\n");
@@ -393,9 +418,10 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
};
struct video_channel *vc = arg;
- CHECK_V4L2;
+ if (check_v4l2(t)==EINVAL) return 0;
+
t->mode = V4L2_TUNER_ANALOG_TV;
- CHECK_ADDR(tv_tuner,"VIDIOCSCHAN","TV");
+ if (check_mode(t,"VIDIOCSCHAN")==EINVAL) return 0;
if (vc->norm < ARRAY_SIZE(map))
t->std = map[vc->norm];
@@ -408,8 +434,9 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
unsigned long *v = arg;
- CHECK_MODE("VIDIOCSFREQ");
- CHECK_V4L2;
+ if (check_mode(t,"VIDIOCSFREQ")==EINVAL) return 0;
+ if (check_v4l2(t)==EINVAL) return 0;
+
set_freq(client,*v);
return 0;
}
@@ -417,8 +444,9 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
struct video_tuner *vt = arg;
- CHECK_ADDR(radio_tuner,"VIDIOCGTUNER","radio");
- CHECK_V4L2;
+ if (check_mode(t,"VIDIOCGTUNER")==EINVAL) return 0;
+ if (check_v4l2(t)==EINVAL) return 0;
+
if (V4L2_TUNER_RADIO == t->mode) {
if (t->has_signal)
vt->signal = t->has_signal(client);
@@ -437,15 +465,16 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
vt->rangelow = tv_range[0] * 16;
vt->rangehigh = tv_range[1] * 16;
}
-
+
return 0;
}
case VIDIOCGAUDIO:
{
struct video_audio *va = arg;
- CHECK_ADDR(radio_tuner,"VIDIOCGAUDIO","radio");
- CHECK_V4L2;
+ if (check_mode(t,"VIDIOCGAUDIO")==EINVAL) return 0;
+ if (check_v4l2(t)==EINVAL) return 0;
+
if (V4L2_TUNER_RADIO == t->mode && t->is_stereo)
va->mode = t->is_stereo(client)
? VIDEO_SOUND_STEREO
@@ -457,9 +486,10 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
v4l2_std_id *id = arg;
- SWITCH_V4L2;
t->mode = V4L2_TUNER_ANALOG_TV;
- CHECK_ADDR(tv_tuner,"VIDIOC_S_STD","TV");
+ if (check_mode(t,"VIDIOC_S_STD")==EINVAL) return 0;
+
+ switch_v4l2();
t->std = *id;
tuner_fixup_std(t);
@@ -471,8 +501,9 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
struct v4l2_frequency *f = arg;
- CHECK_MODE("VIDIOC_S_FREQUENCY");
- SWITCH_V4L2;
+ if (check_mode(t,"VIDIOC_S_FREQUENCY")==EINVAL) return 0;
+
+ switch_v4l2();
if (V4L2_TUNER_RADIO == f->type &&
V4L2_TUNER_RADIO != t->mode)
set_tv_freq(client,400*16);
@@ -484,8 +515,8 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
struct v4l2_frequency *f = arg;
- CHECK_MODE("VIDIOC_G_FREQUENCY");
- SWITCH_V4L2;
+ if (check_mode(t,"VIDIOC_G_FREQUENCY")==EINVAL) return 0;
+ switch_v4l2();
f->type = t->mode;
f->frequency = t->freq;
break;
@@ -494,8 +525,8 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
struct v4l2_tuner *tuner = arg;
- CHECK_MODE("VIDIOC_G_TUNER");
- SWITCH_V4L2;
+ if (check_mode(t,"VIDIOC_G_TUNER")==EINVAL) return 0;
+ switch_v4l2();
if (V4L2_TUNER_RADIO == t->mode) {
if (t->has_signal)
tuner -> signal = t->has_signal(client);
@@ -521,22 +552,23 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
struct v4l2_tuner *tuner = arg;
- CHECK_ADDR(radio_tuner,"VIDIOC_S_TUNER","radio");
- SWITCH_V4L2;
+ if (check_mode(t,"VIDIOC_S_TUNER")==EINVAL) return 0;
+ switch_v4l2();
- /* To switch the audio mode, applications initialize the
- index and audmode fields and the reserved array and
+ /* To switch the audio mode, applications initialize the
+ index and audmode fields and the reserved array and
call the VIDIOC_S_TUNER ioctl. */
/* rxsubchannels: V4L2_TUNER_MODE_MONO, V4L2_TUNER_MODE_STEREO,
- V4L2_TUNER_MODE_LANG1, V4L2_TUNER_MODE_LANG2,
+ V4L2_TUNER_MODE_LANG1, V4L2_TUNER_MODE_LANG2,
V4L2_TUNER_MODE_SAP */
+ if (V4L2_TUNER_RADIO == t->mode) {
+ if (tuner->audmode == V4L2_TUNER_MODE_MONO)
+ t->audmode = V4L2_TUNER_MODE_MONO;
+ else
+ t->audmode = V4L2_TUNER_MODE_STEREO;
- if (tuner->audmode == V4L2_TUNER_MODE_MONO)
- t->audmode = V4L2_TUNER_MODE_MONO;
- else
- t->audmode = V4L2_TUNER_MODE_STEREO;
-
- set_radio_freq(client, t->freq);
+ set_radio_freq(client, t->freq);
+ }
break;
}
case TDA9887_SET_CONFIG: /* Nothing to do on tuner-core */