diff options
author | Mauro Carvalho Chehab <devnull@localhost> | 2005-06-28 03:17:39 +0000 |
---|---|---|
committer | Mauro Carvalho Chehab <devnull@localhost> | 2005-06-28 03:17:39 +0000 |
commit | e4a3e5710f9d49095149a7ec54b295bfe177d456 (patch) | |
tree | 50af32dabd988f3bea79267013c0af6cd5552862 /linux/drivers/media/video/tuner-core.c | |
parent | 8864fa7428dae723f13f8cd22599f5b96986a843 (diff) | |
download | mediapointer-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.c | 238 |
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 */ |